仅用于声明的接口的Type.GetInterfaces()

时间:2012-03-20 19:02:55

标签: c# reflection

首先,有很多这样的问题,也许有些OP甚至都在问这个完全相同的问题。问题是,对这些问题的答案(不论是否接受)实际上都没有回答这个问题,至少我找不到。

如何确定类直接声明的接口,而不是父类或声明的接口继承的接口?

e.g。

interface I {}
interface W : I {}
class C : W {}
class D : C, I {}
class E : D {}

结果:

  1. C声明W
  2. D声明I
  3. E声明无
  4. 可接受的解决方案可能要求接口至少有一个方法。

    如果您认为这是不可能的,请注意不要犯this错误,这实际上是can

    InterfaceMap处理很多情况,但不是全部(我在下面举例说明InterfaceMap无法解决)。我有一个想法,但不知道如何实现它,是反编译类的字节码,看看声明什么,因为ILSpy等工具正确识别每个案例!如果你喜欢这个想法,请给我一个链接到这个领域的更多信息。

    我希望你们中的一些人会建议我清理我的设计。如果这不是您的论点,那么帖子的其余部分与您无关。

    我项目的一部分目的是跟踪给定类型的潜在代码路径(在运行时)。为了以编程方式确定将在目标类型上调用哪个方法,而不实际调用该方法或创建目标类型的实例,知道目标类型的声明接口是确定性地解决此问题的必要条件。 “不,”你说?考虑:

    interface I { int Foo(); }
    class C : I { public int Foo() { return 1; } }
    class D : C { public new int Foo() { return 2; } }
    class E : D, I { }
    
    C p = new E();
    Assert.AreEqual(1 or 2, (p as I).Foo())
    

    正确答案为2,但如果您将E的声明更改为不直接包含I,则答案为1。现在确定这是边缘情况,但它也是正确的答案。因此,我的引擎与潜在的用户代码不完全兼容。告诉用户清理他们的代码以便使用我的工具是不可接受的。 (注意,有很多有趣的规则可以转换为接口,但我不会在这里讨论它们。)

5 个答案:

答案 0 :(得分:2)

要获取给定类型的声明接口,您可以在给定类型上使用GetInterfaces,如果它具有BaseType,您可以使用{{3枚举器排除基类型的接口......

它未经测试,但可能类似于这种扩展方法......

public static IEnumerable<Type> GetDeclaredInterfaces(this Type t)
{
    var allInterfaces = t.GetInterfaces();
    var baseInterfaces = Enumerable.Empty<Type>();
    if (t.BaseType != null)
    {
        baseInterfaces = t.BaseType.GetInterfaces();
    }
    return allInterfaces.Except(baseInterfaces);
}

答案 1 :(得分:2)

基于评论中的有用信息,我能够明确地证明这不能用msft反射完成(虽然它可以用mono.cecil)。原因是GetInterfaces调用进行本机调用,返回为目标类型预先展平的接口。

答案 2 :(得分:1)

这个怎么样?

Type type = typeof(E);
var interfaces = type.GetInterfaces()
    .Where(i => type.GetInterfaceMap(i).TargetMethods.Any(m => m.DeclaringType == type))
    .ToList();

答案 3 :(得分:1)

  

为了以编程方式确定将在目标类型上调用哪个方法,而不实际调用该方法或创建目标类型的实例,知道目标类型的声明接口是确定性地解决此问题的必要条件。

Reflection API通过Type.GetInterfaceMap(Type)提供此功能。例如,在您的情况下,typeof(E).GetInterfaceMap(typeof(I))会为您提供以下信息,以便您直接确定映射:

InterfaceMethods            TargetMethods
[0]: I.Foo()                [0]: E.I.Foo()

显然,如果实例在运行时类型为TargetMethodsE会告诉您确切调用哪个方法。

您会注意到接口方法I.Foo()实际上映射到明确实现E的类型I.Foo()上的方法。 This method was inserted by the compiler and it just calls D.Foo().

(更新:哎呀,正如你在屏幕截图中看到的那样,我创建了第二个Foo()虚拟。虽然非虚拟的结果完全相同。)

答案 4 :(得分:0)

我认为问题不在于GetInterfaces会给你错误的信息。问题是你看错了类型。

当您拥有(p as I).Foo()之类的代码时,您应该查看typeof(I) p.GetType()typeof(C)的方法,也不是typeof(E)

反映I将告诉您正确解决呼叫所需的一切,但这绝不是微不足道的。