Как правильно выполнить Отражение базовых методов интерфейса
У меня есть 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
.