C#中的反射是否提供了一种方法来确定某些给定System.Type类型的模型是否具有某些接口?
| 12
 3
 4
 5
 6
 
 | public interface IMyInterface {}
public class  MyType :  IMyInterface {}
// should yield 'true'
typeof( MyType)./* ????? */ MODELS_INTERFACE( IMyInterface); | 
你在我头脑中有几个选择
typeof(IMyInterface).IsAssignableFrom(typeof(MyType))
typeof(MyType).GetInterfaces().Contains(typeof(IMyInterface))
对于通用接口,它有点不同。
| 1
 | typeof(MyType).GetInterfaces().Any( i =>  i.IsGenericType &&  i.GetGenericTypeDefinition() == typeof( IMyInterface<>)) | 
		
		
- 记住typeof(imyinterface).isassignablefrom(typeof(imyinterface))也是正确的,这可能会在代码中产生意外的结果。
- 很容易不引起注意,把IsAssignableFrom的论点倒过来。我现在就和GetInterfaces一起去:p
- 在我的代码中,IsAssignableFrom(t1)变体比GetInterfaces().Contains(t2)变体快3倍。
- 也可以使用typeof(MyType).GetInterface("IMyInterface") != null。
- @Pierrearnaud:IsassignableFrom最终会调用GetInterfaces,因此您的测试可能首先检查了GetInterfaces,然后检查了Isassignable。这是因为getInterfaces缓存它的结果,所以第一次调用的成本更高
- 我对IsAssignableFrom的性能测试是通过用相同的参数反复调用它来完成的。所以,是的,通过这种方法进行的任何缓存都会产生显著的加速。
- 在写这篇评论时,你的电话是404,这里是A+1,这样你就可以再次被发现了。
- 对@kosta答案的小小改变。有了C 6,我们就可以进行typeof(MyType).GetInterface(nameof(IMyInterface)) != null,以提高类型安全性和重构性。
- 仍然存在使用相同名称的多个接口的风险。
- 做了一些测试,发现IsAssignableFrom比GetInterfaces().Contains快6倍。另一方面,GetInterfaces是缓存的,但IsAssignableFrom不是缓存的。即使使用高速缓存,GetInterfaces().Contains也比IsAssignableFrom慢3.5倍。
- 另一个注意事项是,只有当接口由类型"直接"实现时,isassignablefrom才返回true:即interface A{} interface B:A{} class C:B{}typeof(C).IsAssignableFrom(typeof(A))返回false,而typeof(C).GetInterfaces().Contains(typeof(A))或typeof(C).GetInterface(nameof(A)) != null都是true。
 
	 
使用Type.IsAssignableFrom:
 
| 1
 | typeof(IMyInterface).IsAssignableFrom( someclass.GetType()); | 
或
		
		
- 如果您已经有了类的实例,那么更好的方法只是someclass is IMyInterface,因为这根本不涉及反射的成本。所以,虽然不是错的,但这不是一个理想的方法。
- @詹姆斯-同意。即使是雷瑟也给出了同样的建议。
- @贾梅斯J.Reganiv你应该把这作为回答,我几乎错过了你的评论。
- @谢谢,但评论没有回答最初的问题。这个问题要求反射解决方案,我只是说在这个答案的第一个案例中,你确实有一个对象反射的实例,这不是理想的解决方案。
- @Jamesj.Reganiv实际上,is在继承层次的两个方向上都进行检查,而IsAssignableFrom只向上检查。另外,如果您有一个对象实例,您应该调用IsInstanceOfType(它也只向上看)。
- @Universe is只检查一个方向,否则new object() is string是正确的。
- @乔汉娜那不是我的意思,但我觉得我很困惑。
 
	 
| 12
 3
 4
 5
 6
 7
 8
 9
 
 |     public static bool ImplementsInterface( this Type type, Type ifaceType ) {Type[] intf = type.GetInterfaces();
 for ( int i = 0; i < intf.Length; i++ ) {
 if ( intf[ i ] == ifaceType ) {
 return true;
 }
 }
 return false;
 }
 | 
我认为这是正确的版本,有三个原因:
1)它使用getInterfaces而不是isassignableFrom,因为isassignableFrom最终在多次检查后调用getInterfaces,所以速度更快。2)它在本地数组上迭代,因此没有边界检查。3)它使用为类型定义的==运算符,因此可能比equals方法(包含调用,最终将使用)更安全。
		
		
- +1至于内容,我讨厌帕伦斯和埃及大括号周围的空格。整个方法也可以写成:return-type.getInterfaces().any(t=>t==ifacetype);
- type.isassignablefrom()internaly的行为与代码完全相同
- 另外,为什么不键入.getInterfaces()。包含不使用Linq的(ifacetype)。
 
	 
我只是这样做的:
| 12
 3
 4
 
 | public static bool Implements(this  Type source) where  I : class
{
  return typeof( I).IsAssignableFrom( source);
} | 
我希望我可以说where I : interface,但interface不是通用参数约束选项。class是最接近的。
用途:
| 12
 
 | if(MyType.Implements<IInitializable>())MyCollection.Initialize();
 | 
我刚才说的Implements,因为这更直观。我总是让IsAssignableFrom触发器。
		
		
- 您可以执行return typeof(I).IsInterface && typeof(I).IsAssignableFrom(source);以对方法的任何"不正确"用法返回false,也就是说,将它与类类型而不是接口类型一起使用,或者如果类型参数不是接口,则引发异常。尽管您可能认为派生类"实现"它是父类…
 
	 
修改Jeff的答案以获得最佳性能(得益于Pierre Arnaud的性能测试):
| 12
 
 | var type = typeof( MyType);
var  implementsInterface = typeof( IMyInterface).IsAssignableFrom( type) &&  type.IsClass; | 
要查找在给定的Assembly中实现接口的所有类型:
| 12
 
 | var implementations = typeof( TypeInTargetAssembly).Assembly.GetTypes()
                          .Where( t => typeof( IMyInterface).IsAssignableFrom( t) &&  t.IsClass); | 
正如其他人已经提到的:本杰明4月10日13时22:21"
It sure was easy to not pay attention and get the arguments for
  IsAssignableFrom backwards. I will go with GetInterfaces now :p –
好吧,另一种方法只是创建一个简短的扩展方法,在某种程度上实现了"最常见"的思维方式(并且同意这是一个很小的个人选择,根据个人喜好使它稍微"更自然"):
| 12
 3
 4
 5
 6
 7
 
 | public static class TypeExtensions{
 public static bool IsAssignableTo(this Type type, Type assignableType)
 {
 return assignableType.IsAssignableFrom(type);
 }
 }
 | 
为什么不更通用一点(不确定它是否真的那么有趣,我假设我只是传递了另一点"合成"糖):
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | public static class TypeExtensions
{
    public static bool  IsAssignableTo(this  Type type, Type assignableType)
    {
        return  assignableType.IsAssignableFrom( type);
    }
    public static bool  IsAssignableTo< TAssignable>(this  Type type)
    {
        return  IsAssignableTo( type, typeof( TAssignable));
    }
} | 
我认为这样做可能更自然,但又一次只是个人意见的问题:
| 1
 | var isTrue = michelleType.IsAssignableTo<IMaBelle>(); | 
		
		
- 您是否有理由不将实现直接放在扩展方法中?我的意思是,这让你可以双向调用它,但是为什么你需要这样做呢?
- @Marqueiv很抱歉晚了2年才给你回电话,我想当时是个老习惯,为了避免重复代码,用扩展方法包装helper方法,会编辑我的答案:)
- @Marqueiv Done Plus改变了我不使用别名的另一个坏习惯,即Boolean=>bool(我不知道为什么我年轻时有一些严格的"花哨"编码规则)。
 
	 
IsAssignableFrom现在移到TypeInfo了:
| 1
 | typeof(ISMSRequest).GetTypeInfo().IsAssignableFrom(typeof( T).GetTypeInfo()); | 
正确答案是
然而,
可能返回错误的结果,如下代码显示字符串和IConvertible:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 
 |     static void TestIConvertible()
    {
        string  test ="test"; 
        Type stringType = typeof(string); // or test.GetType();
        bool  isConvertibleDirect =  test is  IConvertible;
        bool  isConvertibleTypeAssignable =  stringType.IsAssignableFrom(typeof( IConvertible));
        bool  isConvertibleHasInterface =  stringType.GetInterface(nameof( IConvertible)) != null; 
        Console.WriteLine( $"isConvertibleDirect: {isConvertibleDirect}"); 
        Console.WriteLine( $"isConvertibleTypeAssignable: {isConvertibleTypeAssignable}"); 
        Console.WriteLine( $"isConvertibleHasInterface: {isConvertibleHasInterface}");
    } | 
结果:
| 12
 3
 
 |  isConvertibleDirect: TrueisConvertibleTypeAssignable: False
 isConvertibleHasInterface: True
 | 
		
		
- 正如您在接受的答案中看到的,您在使用IsAssignableFrom时交换了类型。就像本杰明和埃霍恩警告的那样。
 
	 
注意,如果您有一个通用接口IMyInterface,那么它将始终返回false:
| 1
 |   typeof(IMyInterface<>).IsAssignableFrom(typeof( MyType)) /* ALWAYS FALSE */ | 
这也不起作用:
| 1
 |   typeof(MyType).GetInterfaces().Contains(typeof( IMyInterface<>))  /* ALWAYS FALSE */ | 
但是,如果MyType执行IMyInterface这项工作并返回true:
| 1
 |   typeof(IMyInterface< MyType>).IsAssignableFrom(typeof( MyType)) | 
但是,您可能在运行时不知道类型参数T。一个有点黑客的解决方案是:
| 12
 
 |   typeof(MyType).GetInterfaces()
                .Any( x=> x.Name == typeof( IMyInterface<>).Name) | 
Jeff的解决方案不那么简单:
| 12
 3
 
 |   typeof(MyType).GetInterfaces()
         .Any( i =>  i.IsGenericType 
             &&  i.GetGenericTypeDefinition() == typeof( IMyInterface<>)); | 
以下是适用于任何情况的Type的扩展方法:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | public static class TypeExtensions{
 public static bool IsImplementing(this Type type, Type someInterface)
 {
 return type.GetInterfaces()
 .Any(i => i == someInterface
 || i.IsGenericType
 && i.GetGenericTypeDefinition() == someInterface);
 }
 }
 | 
(请注意,上面使用的LINQ可能比循环慢。)
然后你可以做:
| 1
 |    typeof(MyType).IsImplementing( IMyInterface<>) | 
怎么样
| 1
 | typeof(IWhatever).GetTypeInfo().IsInterface | 
怎么样
| 1
 | if(MyType as IMyInterface != null) | 
?
		
		
- 当我有一个实例时,这是显而易见的。当我有一个类型从反射时不有用