2009-11-23 2 views
4

При отражении по типу интерфейса я получаю только члены определенного типа, а не наследуемые члены.Почему элементы унаследованного интерфейса недоступны с помощью отражения?

В более упрощенном примере, программа только печатает «Имя», а не «ItemNumber», «Имя», как я бы ожидать:

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); 
    } 
} 

Каково Обоснование этого? Когда я наследую базовый интерфейс, я говорю, что любая из реализаций моего интерфейса также должна реализовывать унаследованные члены. Другими словами, IItem is-a IBasicItem. Итак, почему унаследованный член не появляется с помощью отражения?

ответ

10

Я думаю, что это именно то, о чем Фил Хаак просто писал в блоге.

Из общего языка спецификации инфраструктуры ECMA-335:

8.9.11 Интерфейс Типы интерфейсов типа деривации может потребовать осуществления одного или нескольких других интерфейсов. Любой тип, который реализует поддержку типа интерфейса , должен также реализовать поддержку любых необходимых интерфейсов, указанных этим интерфейсом . Это отличается от типа наследования объекта двумя способами:

  • типы объектов образуют одно дерево наследования; интерфейсные типы do нет.
  • Наследование типа объекта указывает, как реализации наследуются; необходимых интерфейсов нет, поскольку интерфейсы не определяют реализации. Необходимые интерфейсы определяют дополнительные контракты, которые должны соответствовать типам объектов, которые должны поддерживать .

Чтобы выделить последнюю разницы, рассмотрит интерфейс, IFoo, который имеет один метод. Интерфейс , IBar, который исходит от , требует, чтобы любой тип объекта , который поддерживает IBar, также поддерживает IFoo. В нем ничего не говорится о том, какие методы у самого IBar будут у него: .

Реферировано от: http://haacked.com/archive/2009/11/10/interface-inheritance-esoterica.aspx

+0

Doh ... Я могу сказать, что сегодня утром сон. +1 для правильного ответа. –

1

Это потому, что вы работаете с интерфейсами. Интерфейсы не получают ту же структуру наследования, что и классы.

Если у вас есть класс, который реализует эти интерфейсы, вы увидите правильную цепочку (если вы используете «BindingFlags.FlattenHierarchy»).

Попробуйте создать класс, который реализует интерфейс нижнего уровня, и вы должны увидеть, что вы ищете.

1

Это потому, что вы не запрашиваете информацию, которую хотите узнать. Другими словами, поскольку ваши унаследованные свойства имеют другое значение, чем свойства, которые вы получаете от интерфейсов, вам приходится обращаться к ним по-разному.

Таким образом, вы можете получить доступ через отражение, как это:

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

Поскольку наследование классов отличаются от соответствия интерфейса, представляется логичным получить доступ к ним по-разному.

6

Хороший способ подумать об этом заключается в том, что интерфейсы не имеют «наследования» так же, как и классы. Наследование подразумевает, что «является своего рода» отношением, но интерфейс «наследование» на самом деле подразумевает, что «требуется обеспечить эту услугу».

Когда мы говорим

interface IEnumerator<T> : IDisposable 

, что мы говорим не столько «счетчики последовательности являются своим родом одноразовой вещи», как «если вы предоставляете услуги перечислителя, то вы должны также обеспечить Dispose оказание услуг".

У этого теперь больше смысла?

Смежные вопросы