tags:

views:

131

answers:

4

When reflecting on an interface type, I only get the members of the specific type, not inherited members.

In this over-simplified example, the program only prints "Name", not "ItemNumber", "Name" as I would expect:

using System;

public interface IBasicItem
{
    string ItemNumber { get; set; }
}

public interface IItem : IBasicItem
{
    string Name { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        var type = typeof (IItem);
        foreach (var prop in type.GetProperties())
            Console.WriteLine(prop.Name);
    }
}

What is the rationale behind this ? When I am inheriting from the base interface, I am saying that any of the implementations of my interface, must also implement the inherited members. In other words, IItem is-a IBasicItem. So why does the inherited member not show up using reflection ?

+7  A: 

I think this is exactly what Phil Haack just blogged about.

From the ECMA-335 Common Language Infrastructure specification:

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.

Referenced from: http://haacked.com/archive/2009/11/10/interface-inheritance-esoterica.aspx

blu
Doh...I can tell I'm sleepy this morning. +1 for the correct answer.
Justin Niessner
+1  A: 

It's because you're working with interfaces. Interfaces don't get the same inheritance structure that classes do.

If you have a class that implements these interfaces, you'll see the proper chain (assuming you use "BindingFlags.FlattenHierarchy").

Try creating a class that implements the lower level interface, and you should see what you're looking for.

jvenema
+1  A: 

It's because your not asking for the information you want to know. In other words, as your inherited properties have a different meaning than the properties you get from interfaces, you have to access them differently.

Therefore, you could access through reflection like this:

foreach ( var iface in type.GetInterfaces() )
{
  foreach ( var prop in iface.GetProperties() )
  {
 Console.WriteLine( iface.Name +"-"+ prop.Name );
  }
}

Since class inheritance is different than interface compliance, it seems logical to access them differently.

muela
+4  A: 

A good way to think about this is that interfaces do not have "inheritance" the same way classes do. Inheritance implies the "is a kind of" relationship, but interface "inheritance" actually implies the "is required to provide this service" relationship.

When we say

interface IEnumerator<T> : IDisposable

what we're saying is not so much "sequence enumerators are a kind of disposable thing" as "if you provide the enumerator service then you must also provide the dispose service".

Does that now make more sense?

Eric Lippert