2011-09-27 76 views
9

我想通过反射在类的接口上执行查询,但是Type.GetInterfaces()方法也返回所有继承的接口。只找到非继承的接口?

public class Test : ITest { } 

public interface ITest : ITesting { } 

代码

typeof(Test).GetInterfaces(); 

将返回Type[]含有ITestITesting,在那里,我只希望ITest,有另一种,它允许您指定的继承方法?

谢谢, Alex。

编辑: 从下面我收集这个问题的答案,

Type t; 
t.GetInterfaces().Where(i => !t.GetInterfaces().Any(i2 => i2.GetInterfaces().Contains(i))); 

上面似乎工作,纠正我的意见,如果它不

+3

如果是公共课测试:ITest,ITesting',该怎么办?你为什么要这样? – SLaks

+3

因为我想知道这个类是从哪个接口直接继承的?而不是它从间接继承的接口,动态生成新类型。这有什么关系吗? –

+5

严格地说,你不会*继承*接口,你*实现*它们,所以在这种情况下'Test'类提供了'ITest'和'ITesting'的实现。 “ITest”从“ITesting”继承的事实仅仅意味着实现“ITest”的任何类型都必须提供“ITesting”的实现。 – LukeH

回答

6

你可以试试像这样:

Type[] interfaces = typeof(Test).GetInterfaces(); 
var exceptInheritedInterfaces = interfaces.Except(interfaces.SelectMany(t => t.GetInterfaces())); 

我觉得还有一个更优雅的方式,但现在我想不出它...

所以,如果你有这样的事情:

public interface A : B 
    { 
    } 

    public interface B : C 
    { 
    } 

    public interface C 
    { 
    } 

    public interface D 
    { 
    } 

    public class MyType : A, D 
    { 
    } 

代码将返回AD

0

试试这个:

​​
+2

这假设他知道他想找到的具体界面。如果他已经知道了,他可能不需要反思。 –

+0

不是很有帮助,我需要一个通用的解决方案,无需我知道接口的名称就可以工作。 –

+0

你是对的,我误解了它。再试一次 – ojlovecd

4

如果我错了,.NET中一个更大的专家可以纠正我,但我不相信这是可能的。在内部,我相信.NET框架实际上不会维护这个层次结构,并且在编译为IL代码时它会变得平坦。

例如,C#代码:

class Program : I2 
{ 
    static void Main(string[] args) 
    { 
    } 
} 

interface I1 
{ 
} 

interface I2 : I1 
{ 
} 

它被内置到IL代码后,它是:

.class private auto ansi beforefieldinit ReflectionTest.Program 
     extends [mscorlib]System.Object 
     implements ReflectionTest.I2, 
        ReflectionTest.I1 
{ 
    ... 

哪个是完全相同class Program : I1, I2


然而,在IL中也是:

.class interface private abstract auto ansi ReflectionTest.I2 
     implements ReflectionTest.I1 
{ 
    ... 

这意味着,你可以写一些逻辑从Program类获取(从我的例子)I1I2,然后查询每个这些接口的,看看他们是否落实别人的一个... 换句话说由于typeof(I2).GetInterfaces()包含I1,那么你就可以推断,由于typeof(Program).GetInterfaces()回报I1I2,然后Program可能不直接继承代码I1

我强调可能不会因为这也是有效的C#代码,并会作出同样的IL代码(以及相同的反射效果):直接

class Program : I1, I2 
{ 
    static void Main(string[] args) 
    { 
    } 
} 

interface I1 
{ 
} 

interface I2 : I1 
{ 
} 

现在Program都间接继承I1 ..

1

在我以前的尝试中,我无法成功。

Type[] types = typeof(Test).GetInterfaces(); 

var directTypes = types.Except 
        (types.SelectMany(t => t.GetInterfaces())); 

    foreach (var t in directTypes) 
    { 

    } 

希望这会帮助某人。

+0

寻求downvoter的积极评论。 – adatapost

+1

这*看起来像它应该完美地工作。替代非LINQ语法: 'typeof(Test).GetInterfaces()。Where(i => i.GetInterfaces()。Length> = 1).SingleOrDefault();' –

+1

如果类直接实现两个接口。 'Test:ITestInterface1,ITestInterface2'? (通过摔倒我的意思是忽略显示类直接实现多个接口) – Phill

1

这似乎没有琐碎的方法调用这样做,因为基本上下面的编译时是完全一样的:

MyClass : IEnumerable<bool> 

MyClass : IEnumerable<bool>,IEnumerable 

您可以询问每个接口,并要求其接口。看看他们是否在前者名单中。不寻常的是,GetInterfaces类是递归的。也就是说它可以获得各种级别的继承。对于接口它不是递归的。例如: IList返回IListICollection,但没有提到IEnumerable,它由ICollection执行。

但是,您最有可能对每个接口和它们的绑定唯一实现的方法感兴趣,在这种情况下,您可以使用方法GetInterfaceMap(Type)

0
Type t = typeof(Test); 
    int max = 0; 
    List<Type> results = new List<Type>(); 
    foreach (Type type in t.GetInterfaces()) 
    { 
     int len = type.GetInterfaces().Length; 
     if (len > max) 
     { 
      max = len; 
      results.Add(type); 
     } 
    } 
    if (results.Count > 0) 
     foreach (Type type in results) 
      Console.WriteLine(type.FullName); 
2

它不可能简单地检索眼前的接口,但我们有必要的类型的元数据来弄明白。如果我们从整个继承链中得到了一个扁平化的接口列表,并且每个接口都可以告诉我们它实现/需要哪些同级元素(它们是做什么的),我们可以递归地删除每个实现或需要的接口在父母身上。

这种做法有点过分进取,因为如果你在眼前类中声明IFooIBar,由IBar需要IFoo,它会被删除(但实际上,这是什么比在好奇心的运动吗?这样做的实用性是我不清楚......)

此代码是丑得要命,但我只是一个新鲜/裸MonoDevelop的安装扔在一起......

public static void Main (string[] args) 
{ 
    var nonInheritedInterfaces = typeof(Test).GetImmediateInterfaces(); 
    foreach(var iface in nonInheritedInterfaces) 
    { 
     Console.WriteLine(iface); 
    } 
    Console.Read(); 
} 

class Test : ITest { } 

interface ITest : ITestParent { } 

interface ITestParent { } 

public static class TypeExtensions 
{ 
    public static Type[] GetImmediateInterfaces(this Type type) 
    { 
     var allInterfaces = type.GetInterfaces(); 
     var nonInheritedInterfaces = new HashSet<Type>(allInterfaces); 
     foreach(var iface in allInterfaces) 
     { 
      RemoveInheritedInterfaces(iface, nonInheritedInterfaces); 
     } 
     return nonInheritedInterfaces.ToArray(); 
    } 

    private static void RemoveInheritedInterfaces(Type iface, HashSet<Type> ifaces) 
    { 
     foreach(var inheritedIface in iface.GetInterfaces()) 
     { 
      ifaces.Remove(inheritedIface); 
      RemoveInheritedInterfaces(inheritedIface, ifaces); 
     } 
    } 
} 

private static void RemoveInheritedInterfaces(Type iface, Dictionary<Type, Type> interfaces) 
{ 
    foreach(var inheritedInterface in iface.GetInterfaces()) 
    { 
     interfaces.Remove(inheritedInterface); 
     RemoveInheritedInterfaces(inheritedInterface, interfaces); 
    } 
}