Как правильно выполнить Отражение базовых методов интерфейса

У меня есть 2 интерфейса и 2 класса, которые я исследую через Reflection:

  • IParent
  • IChild - происходит от IParent
  • Родитель
  • Ребенок - происходит от родителя

Странная вещь для меня - это тот факт, что когда я просматриваю отражение типа IChild, я не нахожу метод IParent.

Тот же код, примененный к типу Child работает как ожидалось - отражение показывает родительский метод.

interface IParent
{
     void ParentMethod();
}

interface IChild : IParent
{
     void ChildMethod();
}

class Parent 
{
     public void ParentMethod(){}
}

class Child : Parent
{
     public void ChildMethod(){}
}

void Main()
{
    //investigate derived interface
     Type t = typeof(IChild);
     var info = t.GetMethod("ChildMethod");//ok
     Console.WriteLine(info); 
     info = t.GetMethod("ParentMethod");//returns null!
     Console.WriteLine(info); 
     //investigate derived class
     t = typeof(Child);
     info = t.GetMethod("ChildMethod");//ok
     Console.WriteLine(info);
     info = t.GetMethod("ParentMethod");//ok
     Console.WriteLine(info);
}

Пожалуйста, объясните такое поведение?

Существует ли какое-либо обходное решение для отражения методов базового интерфейса из производного типа интерфейса?

Ответ 1

Хотя мы используем интерфейсы так же, как мы используем наследование ( ":" ); интерфейсы не наследуются; они должны быть реализованы. В таком случае; наследование путается с реализацией, поскольку они определяются с использованием одного и того же оператора ( ":" ).

Как резюме; IA : IB и A:IA означает; любой класс, реализующий IA, должен реализовать IB. В этом случае; A должен выполнять IA и IB.

A:B означает, что класс наследует класс B; он не реализуется.

Путаница здесь происходит от использования одного и того же оператора ( ":" ).

Проверьте эту страницу наследование интерфейса

Ответ 2

Если вы имеете дело с интерфейсом, используйте

t.GetInterfaces()

то вы можете проверить методы на возвращаемые выше типы.

Поиск членов интерфейса по имени не является допустимым, помните, что, хотя члены интерфейса С# не могут быть переименованы в реализацию, в CLR имена могут быть изменены. (IDisposable.Dispose() иногда переименовывается в Close). В il есть инструкция под названием .implements, которая позволяет изменять имена. Я считаю, что VB.Net также имеет эту функцию.

Ответ 3

Основными интерфейсами интерфейса (в данном случае IParent является базовый интерфейс IChild) являются явные базовые интерфейсы. Наследование является неудачным словом для интерфейсов, поскольку классы, структуры и другие интерфейсы никогда не наследуются от интерфейсов, они просто реализуют контракт, который определяют базовые интерфейсы.

Когда вы получаете IChild из IParent (обратите внимание, что я не наследовал), он не определяет метод ParentMethod, он просто говорит все, что меня реализует, также должен реализовывать IParent.

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

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

Когда вы размышляете о интерфейсе, отображение интерфейса не происходит, поэтому отражается только сам интерфейс.

Type t = typeof(IChild);

Информация о типе будет содержать только информацию о типе о IChild.

Type t = typeof(Child);

Здесь происходит процесс отображения интерфейса. Когда вы размышляете о типе Child для метода с именем ParentMethod, каждый базовый интерфейс проверяется до тех пор, пока не будет найдено совпадение.

Эта часть дизайна языка. Подробнее об этом читайте в разделе 13.1.4 языка программирования С# (четвертое издание) или в разделе 20.1.2 спецификации ECMA.

Вы можете немного обойти это, выполнив переопределение интерфейса, но для этого требуется дополнительный код.

interface IParent
{
    void ParentMethod();
}

interface IChild
{
    new void ParentMethod(); // Reimplement IParent.ParentMethod()
    void ChildMethod();
}

Это сработает.

Type t = typeof(IChild);
MethodInfo mi = t.GetMethod("ParentMethod");

Из-за переопределения интерфейса IChild теперь содержит подпись метода ParentMethod.