I have 2 interfaces and 2 classes that I investigate via Reflection:
- IParent
- IChild - derives from IParent
- Parent
- Child - derives from Parent
Strange thing for me is the fact that when I look through reflection on IChild type I don't find IParent method.
Same code applied to Child type works as expected - reflection shows Parent method.
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);
}
Please explain such behaviour?
Is there any workaround to reflect base interface's methods from the derived interface's type?
Although, we use the interfaces as the same way we use inheritance (":"); interfaces are not inherited; they are to be implemented. In such a case; inheritance is confused with implementation since they are defined using the same operator (":").
As a summary;
IA : IB
and A:IA
means; any class implementing IA, shall implement IB. In this case; A shall implement IA and IB.
A:B
means A class inherits B class; it does not implement.
The confusion here derives from using the same operator (":").
Check this page interface inheritance
If you are dealing with an interface, use
t.GetInterfaces()
then you can check for methods on the types returned above.
Finding interface members by name is not relyable, be mindful that whilst in C# interface members cannot be renamed on implementation, in the CLR the names may be modified. (IDisposable.Dispose() is sometimes renamed to Close). In il there is an instruction called .implements
that allows one to change names. I believe VB.Net also has this feature.
The base interfaces of an interface (in this case IParent
is the base interface of IChild
) are explicit base interfaces. Inheritence is an unfortunate word for interfaces, because classes, structures, and other interfaces never inherit from interfaces, they simply implement the contract that the base interfaces define.
When you derive IChild
from IParent
(note I did not say inherit), it does not define the ParentMethod
method, it simply says anything that implements me, must also implement IParent
.
The reason it works when you reflect on an actual type, is because implementing an interface actually does define that method signatures in the type itself, and that's not the case with interfaces.
This is due to a process that occurs by the compiler called interface mapping, which is defined as the process of locating interface members in an implementing class or struct, but this does not occur for the interface itself.
When you reflect upon an interface, interface mapping does not occur, so only the interface itself is reflected.
Type t = typeof(IChild);
The type information will only contain type information explicitly about IChild
.
Type t = typeof(Child);
Here the process of interface mapping does occur. When you reflect upon the type of Child
for a method named ParentMethod
, each base interface is examined until a match is found.
This part of the language design. You can read more about it in section 13.1.4 of the C# Programming Language (Fourth Edition) or section 20.1.2 of the ECMA spec.
You can work around it somewhat by doing interface reimplementation, but it requires some extra code.
interface IParent
{
void ParentMethod();
}
interface IChild
{
new void ParentMethod(); // Reimplement IParent.ParentMethod()
void ChildMethod();
}
This would work.
Type t = typeof(IChild);
MethodInfo mi = t.GetMethod("ParentMethod");
Because of interface reimplementation, IChild
now contains a method signature of ParentMethod
.