首先,有很多这样的问题,也许有些OP甚至都在问这个完全相同的问题。问题是,对这些问题的答案(不论是否接受)实际上都没有回答这个问题,至少我找不到。
如何确定类直接声明的接口,而不是父类或声明的接口继承的接口?
e.g。
interface I {}
interface W : I {}
class C : W {}
class D : C, I {}
class E : D {}
结果:
C
声明W
D
声明I
E
声明无可接受的解决方案可能要求接口至少有一个方法。
如果您认为这是不可能的,请注意不要犯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
。现在确定这是边缘情况,但它也是正确的答案。因此,我的引擎与潜在的用户代码不完全兼容。告诉用户清理他们的代码以便使用我的工具是不可接受的。 (注意,有很多有趣的规则可以转换为接口,但我不会在这里讨论它们。)
答案 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()
显然,如果实例在运行时类型为TargetMethods
,E
会告诉您确切调用哪个方法。
您会注意到接口方法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
将告诉您正确解决呼叫所需的一切,但这绝不是微不足道的。