如何确定类型是否实现带有C#反射的接口

How to determine if a type implements an interface with C# reflection

C#中的反射是否提供了一种方法来确定某些给定System.Type类型的模型是否具有某些接口?

1
2
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<>))


    使用Type.IsAssignableFrom

    1
    typeof(IMyInterface).IsAssignableFrom(typeof(MyType));


    1
    typeof(IMyInterface).IsAssignableFrom(someclass.GetType());

    1
    typeof(IMyInterface).IsAssignableFrom(typeof(MyType));


    1
    2
    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
    2
    3
    4
    public static bool Implements(this Type source) where I : class
    {
      return typeof(I).IsAssignableFrom(source);
    }

    我希望我可以说where I : interface,但interface不是通用参数约束选项。class是最接近的。

    用途:

    1
    2
    if(MyType.Implements<IInitializable>())
      MyCollection.Initialize();

    我刚才说的Implements,因为这更直观。我总是让IsAssignableFrom触发器。


    修改Jeff的答案以获得最佳性能(得益于Pierre Arnaud的性能测试):

    1
    2
    var type = typeof(MyType);
    var implementsInterface = typeof(IMyInterface).IsAssignableFrom(type) && type.IsClass;

    要查找在给定的Assembly中实现接口的所有类型:

    1
    2
    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 –

    好吧,另一种方法只是创建一个简短的扩展方法,在某种程度上实现了"最常见"的思维方式(并且同意这是一个很小的个人选择,根据个人喜好使它稍微"更自然"):

    1
    2
    3
    4
    5
    6
    7
    public static class TypeExtensions
    {
        public static bool IsAssignableTo(this Type type, Type assignableType)
        {
            return assignableType.IsAssignableFrom(type);
        }
    }

    为什么不更通用一点(不确定它是否真的那么有趣,我假设我只是传递了另一点"合成"糖):

    1
    2
    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>();


    IsAssignableFrom现在移到TypeInfo了:

    1
    typeof(ISMSRequest).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo());

    正确答案是

    1
    typeof(MyType).GetInterface(nameof(IMyInterface)) != null;

    然而,

    1
    typeof(MyType).IsAssignableFrom(typeof(IMyInterface));

    可能返回错误的结果,如下代码显示字符串和IConvertible:

    1
    2
    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}");
        }

    结果:

    1
    2
    3
     isConvertibleDirect: True
     isConvertibleTypeAssignable: False
     isConvertibleHasInterface: True


    注意,如果您有一个通用接口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。一个有点黑客的解决方案是:

    1
    2
      typeof(MyType).GetInterfaces()
                    .Any(x=>x.Name == typeof(IMyInterface<>).Name)

    Jeff的解决方案不那么简单:

    1
    2
    3
      typeof(MyType).GetInterfaces()
             .Any(i => i.IsGenericType
                 && i.GetGenericTypeDefinition() == typeof(IMyInterface<>));

    以下是适用于任何情况的Type的扩展方法:

    1
    2
    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)