如何正确反射基本接口方法

Posted

技术标签:

【中文标题】如何正确反射基本接口方法【英文标题】:How to do proper Reflection of base Interface methods 【发布时间】:2012-05-20 00:39:15 【问题描述】:

我有 2 个接口和 2 个类,我通过反射进行调查:

父母亲 IChild - 派生自 IParent 家长 子 - 派生自父

对我来说奇怪的是,当我查看 IChild 类型的反射时,我没有找到 IParent 方法。

应用于 Child 类型的相同代码按预期工作 - 反射显示 Parent 方法。

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

请解释这种行为?

是否有任何解决方法可以从派生接口的类型中反映基接口的方法?

【问题讨论】:

Parent 没有实现IParent...错字? 好问题。我从阅读答案中学到了一些东西。还不需要知道它,但知识就是力量...... @Jamiec 不,这不是错字。只是展示了反映继承的类和接口的区别。 【参考方案1】:

如果您正在处理接口,请使用

t.GetInterfaces()

然后您可以检查上面返回的类型的方法。

通过名称查找接口成员是不可靠的,请注意,虽然在 C# 中接口成员无法在实现时重命名,但在 CLR 中名称可能会被修改。 (IDisposable.Dispose() 有时重命名为 Close)。在 il 中有一条名为.implements 的指令允许更改名称。我相信VB.Net也有这个功能。

【讨论】:

【参考方案2】:

虽然,我们使用接口的方式与使用继承的方式相同(“:”);接口不被继承;它们将得到执行。在这种情况下;继承与实现混淆了,因为它们是使用相同的运算符(“:”)定义的。

作为总结; IA : IBA:IA 表示;任何实现 IA 的类都应实现 IB。在这种情况下; A 应实现 IA 和 IB。

A:B表示A类继承B类;它没有实现。

这里的混淆源于使用相同的运算符(“:”)。

查看此页面interface inheritance

【讨论】:

【参考方案3】:

接口的基础接口(在这种情况下IParentIChild 的基础接口)是显式基础接口。继承对于接口来说是一个不幸的词,因为类、结构和其他接口从不继承接口,它们只是实现基本接口定义的契约。

当你从IParent派生IChild时(注意我没有说继承),它没有定义ParentMethod方法,它只是说任何实现我的东西,也必须实现IParent

当您考虑实际类型时,它起作用的原因是因为实现接口实际上确实在类型本身中定义了该方法签名,而接口并非如此。

这是由于编译器发生的称为接口映射的过程,该过程被定义为在实现类或结构中定位接口成员的过程,但接口不会发生这种情况自己。

当你反射一个接口时,接口映射发生,所以只有接口本身被反射。

Type t = typeof(IChild);

类型信息将仅包含关于IChild 的明确类型信息。

Type t = typeof(Child);

接口映射的过程确实发生了。当您为名为 ParentMethod 的方法考虑 Child 的类型时,会检查每个基本接口,直到找到匹配项。

这部分的语言设计。您可以在 C# Programming Language (Fourth Edition) 的第 13.1.4 节或 ECMA 规范的第 20.1.2 节中阅读有关它的更多信息。

您可以通过接口重新实现来解决它,但它需要一些额外的代码。

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 的方法签名。

【讨论】:

以上是关于如何正确反射基本接口方法的主要内容,如果未能解决你的问题,请参考以下文章

JAVA 反射枚举 Lambda 表达式详解

JAVA 反射枚举 Lambda 表达式详解

GO之反射

如何利用java反射构造一个类,使之实现一个接口和一些功能

如何把一个接口的所有实现类反射出来?

Java反射理解-- 方法反射的基本操作