如何确定一个类型实现特定的泛型接口类型,

问题描述:

假设以下类型定义:如何确定一个类型实现特定的泛型接口类型,

public interface IFoo<T> : IBar<T> {} 
public class Foo<T> : IFoo<T> {} 

如何找出型Foo是否实现了通用接口IBar<T>当只有错位类型可用?

通过使用从TcKs回答它也可以用以下LINQ查询完成:

bool isBar = foo.GetType().GetInterfaces().Any(x => 
    x.IsGenericType && 
    x.GetGenericTypeDefinition() == typeof(IBar<>)); 
+1

这是一个非常优雅的解决方案!我在SO上看到的其他人使用foreach循环或更长的LINQ查询。请记住,要使用这个,你需要有.NET框架3.5。 – 2009-11-10 03:25:14

+7

我建议你让这个扩展方法成为一个la http://bit.ly/ccza8B - 会很好地清理它! – 2010-07-27 23:06:01

你必须检查构造类型的通用接口。

你将不得不做这样的事情:

foo is IBar<String> 

因为IBar<String>表示构造类型。您必须这样做的原因是因为如果您的支票中未定义T,编译器不知道您的意思是IBar<Int32>还是IBar<SomethingElse>

你必须通过继承树上去,找到树中的每个类的所有接口,并与调用Type.GetGenericTypeDefinition如果的接口是通用的结果比较typeof(IBar<>)。当然,这有点痛苦。

有关更多信息和代码,请参阅this answerthese ones

+0

为什么不只是投到IBar 并检查为空? (我的意思是当然是用'as'投射) – 2009-02-02 14:04:58

+3

T是未知的,不能转换成特定类型。 – sduplooy 2009-02-02 14:06:55

+0

@sduplooy:也许我错过了T怎么可能是未知的?它会编译公共类Foo:IFoo {} – 2009-02-02 14:07:59

public interface IFoo<T> : IBar<T> {} 
public class Foo : IFoo<Foo> {} 

var implementedInterfaces = typeof(Foo).GetInterfaces(); 
foreach(var interfaceType in implementedInterfaces) { 
    if (false == interfaceType.IsGeneric) { continue; } 
    var genericType = interfaceType.GetGenericTypeDefinition(); 
    if (genericType == typeof(IFoo<>)) { 
     // do something ! 
     break; 
    } 
} 
+1

由于typeof(Foo)返回System.Type对象(描述Foo),GetType()调用将始终返回System.Type的类型。您应该更改为typeof(Foo).GetInterfaces() – 2009-02-02 15:39:51

所有public class Foo : IFoo<T> {}首先不能编译,因为你需要指定一个类,而不是T,但假设你做这样的事情public class Foo : IFoo<SomeClass> {}

那么如果你

Foo f = new Foo(); 
IBar<SomeClass> b = f as IBar<SomeClass>; 

if(b != null) //derives from IBar<> 
    Blabla(); 

作为一种辅助方法,扩展

public static bool Implements<I>(this Type type, I @interface) where I : class 
{ 
    if(((@interface as Type)==null) || !(@interface as Type).IsInterface) 
     throw new ArgumentException("Only interfaces can be 'implemented'."); 

    return (@interface as Type).IsAssignableFrom(type); 
} 

用法示例:

var testObject = new Dictionary<int, object>(); 
result = testObject.GetType().Implements(typeof(IDictionary<int, object>)); // true! 

我使用@GenericProgrammers扩展方法的稍微简单一些的版本:

public static bool Implements<TInterface>(this Type type) where TInterface : class { 
    var interfaceType = typeof(TInterface); 

    if (!interfaceType.IsInterface) 
     throw new InvalidOperationException("Only interfaces can be implemented."); 

    return (interfaceType.IsAssignableFrom(type)); 
} 

用法:

if (!featureType.Implements<IFeature>()) 
     throw new InvalidCastException(); 

不应该有什么错了以下内容:

对于额外的信用,你可以赶上AmbiguousMatchException如果你想提供一个特定的通用型参数与伊巴尔查询。

为了完全处理类型系统,我认为你需要处理递归,例如, IList<T>ICollection<T>IEnumerable<T>,没有它你不会知道IList<int>最终实现了IEnumerable<>

/// <summary>Determines whether a type, like IList&lt;int&gt;, implements an open generic interface, like 
    /// IEnumerable&lt;&gt;. Note that this only checks against *interfaces*.</summary> 
    /// <param name="candidateType">The type to check.</param> 
    /// <param name="openGenericInterfaceType">The open generic type which it may impelement</param> 
    /// <returns>Whether the candidate type implements the open interface.</returns> 
    public static bool ImplementsOpenGenericInterface(this Type candidateType, Type openGenericInterfaceType) 
    { 
     Contract.Requires(candidateType != null); 
     Contract.Requires(openGenericInterfaceType != null); 

     return 
      candidateType.Equals(openGenericInterfaceType) || 
      (candidateType.IsGenericType && candidateType.GetGenericTypeDefinition().Equals(openGenericInterfaceType)) || 
      candidateType.GetInterfaces().Any(i => i.IsGenericType && i.ImplementsOpenGenericInterface(openGenericInterfaceType)); 

    } 

在你想要将支持通用的基本类型以及接口扩展方法的情况下,我已经扩大sduplooy的回答是:

public static bool InheritsFrom(this Type t1, Type t2) 
    { 
     if (null == t1 || null == t2) 
      return false; 

     if (null != t1.BaseType && 
      t1.BaseType.IsGenericType && 
      t1.BaseType.GetGenericTypeDefinition() == t2) 
     { 
      return true; 
     } 

     if (InheritsFrom(t1.BaseType, t2)) 
      return true; 

     return 
      (t2.IsAssignableFrom(t1) && t1 != t2) 
      || 
      t1.GetInterfaces().Any(x => 
       x.IsGenericType && 
       x.GetGenericTypeDefinition() == t2); 
    } 

方法来检查,如果该类型继承或实现一个通用类型:

public static bool IsTheGenericType(this Type candidateType, Type genericType) 
    { 
     return 
      candidateType != null && genericType != null && 
      (candidateType.IsGenericType && candidateType.GetGenericTypeDefinition() == genericType || 
      candidateType.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == genericType) || 
      candidateType.BaseType != null && candidateType.BaseType.IsTheGenericType(genericType)); 
    }