Interface Inheritance Esoterica

0 comments suggest edit

I learned something new yesterday about interface inheritance in .NET as compared to implementation inheritance. To illustrate this difference, here’s a simple demonstration.

I’ll start with two concrete classes, one which inherits from the other. Each class defines a property. In this case, we’re dealing with implementation inheritance.

public class Person {
    public string Name { get; set; }
}

public class SuperHero : Person {
    public string Alias { get; set; }
}

We can now use two different techniques to print out the properties of the SuperHero type: type descriptors and reflection. Here’s a little console app that does this. Note the code I’m showing below doesn’t include a few Console.WriteLine calls that I have in the actual app.

static void Main(string[] args) {
  // type descriptor
  var properties = TypeDescriptor.GetProperties(typeof(SuperHero));
  foreach (PropertyDescriptor property in properties) {
    Console.WriteLine(property.Name);
  }

  // reflection
  var reflectedProperties = typeof(SuperHero).GetProperties();
  foreach (var property in reflectedProperties) {
    Console.WriteLine(property.Name);
  }
}

Let’s look at the output of this code.

impl-inheritance

No surprises there.

The SuperHero type has two properties, Alias defined on SuperHero and the Name property inherited from its base type.

But now, let’s change these classes into interfaces so that we’re now dealing with interface inheritance. Notice that ISupeHero now derives from IPerson.

public interface IPerson {
  string Name { get; set; }
}

public interface ISuperHero : IPerson {
  string Alias { get; set; }
}

I’ve also made the corresponding changes to the console app.

var properties = TypeDescriptor.GetProperties(typeof(ISuperHero));
foreach (PropertyDescriptor property in properties) {
  Console.WriteLine(property.Name);
}

// reflection
var reflectedProperties = typeof(ISuperHero).GetProperties();
foreach (var property in reflectedProperties) {
  Console.WriteLine(property.Name);
}

Before looking at the next screenshot, take a moment to answer the question, what is the output of the program now?

interface-inheritance Well it should be obvious that the output is different otherwise I wouldn’t be writing this blog post in the first place, right?

When I first tried this out, I found the behavior surprising. However, it’s probably not surprising to anyone who has an encyclopedic knowledge of the ECMA-335 Common Language Infrastructure specification (PDF) such as Levi, one of the ASP.NET MVC developers who pointed me to section 8.9.11 of the spec when I asked about this behavior:

8.9.11 Interface type derivation Interface types can require the implementation of one or more other interfaces. Any type that implements support for an interface type shall also implement support for any required interfaces specified by that interface. This is different from object type inheritance in two ways:

  • Object types form a single inheritance tree; interface types do not.
  • Object type inheritance specifies how implementations are inherited; required interfaces do not, since interfaces do not define implementation. Required interfaces specify additional contracts that an implementing object type shall support.

To highlight the last difference, consider an interface, IFoo, that has a single method. An interface, IBar, which derives from it, is requiring that any object type that supports IBar also support IFoo. It does not say anything about which methods IBar itself will have.

The last paragraph provides a great example of why the code I wrote behaves as it does. The fact that ISuperHero inherits from IPerson doesn’t mean the ISuperHero interface type inherits the properties of IPerson because interfaces do not define implementation.

Rather, what it means is that any class that implements ISuperHero must also implement the IPerson interface. Thus if I wrote an implementation of ISuperHero such as:

public class Groo : ISuperHero {
  public string Name {get; set;}
  public string Alias {get; set;}
}

The Groo type must implement both ISuperHero and IPerson and iterating over its properties would show both properties.

Implications for ASP.NET MVC Model Binding

You probably could have guessed this part was coming. Let’s say you’re trying to use model binding to bind the Name property of an ISuperHero. Since our model binder uses type descriptors under the hood, we won’t be able to bind that property for the reasons stated above.

I learned of this detail investigating a bug reported in StackOverflow. It turns out this behavior is by design. In the context of sending a view model to the view, that view model should be a simple carrier of data. Thus it makes sense to use concrete types on your view model, in contrast to your domain models which will more likely be interface based.

Found a typo or error? Suggest an edit! If accepted, your contribution is listed automatically here.

Comments

avatar

14 responses

  1. Avatar for Eyston
    Eyston November 10th, 2009

    Nicely explained, thanks.

  2. Avatar for Kelly Bourg
    Kelly Bourg November 10th, 2009

    that's not a bug, that's a feature!

  3. Avatar for Craig Vermeer
    Craig Vermeer November 10th, 2009

    I ran into the same issue a while back with a project I was working on. I actually switched my approach from away from using interface inheritance because of it. :-)

  4. Avatar for Brian Chiasson
    Brian Chiasson November 10th, 2009

    I understand the specification and the sample, however, I would still expect the output to include both Alias and Name. While implementing the interface, ISuperHero, does NOT indicate how your concrete class will gain its members (Alias or Name) it still requires both properties to be defined somewhere in the hierarchy in order to abide by the ISuperHero contract.

  5. Avatar for Brian Chiasson
    Brian Chiasson November 10th, 2009

    It says that, in order to abide by the ISuperHero contract, you have to implement the members of IPerson - that's not the same thing I said before. My beef is that the runtime should know that both of the interfaces' members are implemented.

  6. Avatar for Rahul Ballal
    Rahul Ballal November 10th, 2009

    A must read for people who think " All the OO stuff I learnt at school, where does all this fit in real world?" . Great post!

  7. Avatar for Brad Wilson
    Brad Wilson November 10th, 2009

    Brian,
    The difference is that classes define an is-a relationship, whereas interfaces don't (it's more like a can-do relationship). So An ISuperHero can do "Alias", and to obey the contract of ISuperHero, you must also implement IPerson (which can do "Name"), but that doesn't meant that ISuperHero is-a IPerson.
    If you want the is-a relationship, you should use abstract classes instead.

  8. Avatar for Josh
    Josh November 10th, 2009

    HA! I actually expected the output of "Alias" only. Only because in a former life, I used a lot of Reflection and wrote my own reflection library because the one in .Net 1.0 sucked. BUT... I had no idea that was the reason why. Guess it makes sense that interface inheritance doesn't require a single inheritance tree.
    Thanks for this post.

  9. Avatar for configurator
    configurator November 10th, 2009

    If a class implements an interface explicitly, the properties also won't appear when enumerating the class's methods for similar reasons.

  10. Avatar for Haacked
    Haacked November 10th, 2009

    @Brian note that I'm iterating over the properties of a type. So there is no concrete implementation at that point.
    If I actually had an instance that implemented ISuperHero and called instance.GetType().GetProperties();
    I would then get both properties.

  11. Avatar for Aaron Fischer
    Aaron Fischer November 10th, 2009

    And if you wanted ISuperHero to have a Name...
    public interface ISuperHero : IPerson {
    new string Name { get; set; }
    string Alias { get; set; }
    }

  12. Avatar for Frank Quednau
    Frank Quednau November 10th, 2009

    Also consider the "multiple inheritance" thing in interfaces. If your interface states to implement the 2 interfaces A, B and the 2 have the same method, which one should be reflected?

  13. Avatar for Jordan Terrell
    Jordan Terrell November 10th, 2009

    What's wrong with doing something like this?
    http://gist.github.com/231389

  14. Avatar for Rick Spence
    Rick Spence October 30th, 2010

    Hello,
    I found this on the web today searching for interface inheritance. This was new to be as well I think I see why it's that way. Doesn't it solve the diamond problem of C++? If you had INormalHero inherit from IPerson, and then have a class called BothHeroes implement both ISuperHero and iNormalHero, how many of the name properties do you expect?
    Obviously this is by design but it does mean you can't have different implementations of any parent interface method so that if I declare:
    ISuperHero superHero = new BothHeroes()
    INormalHero normalHero = new Bothheroes();
    both objects use the same name property?
    Best