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

Yip*_*Yay 527 c# reflection interface

是否反映C#报价的方式来确定是否给予一些System.Type款型的一些接口?

public interface IMyInterface {}

public class MyType : IMyInterface {}

// should yield 'true'
typeof(MyType)./* ????? */MODELS_INTERFACE(IMyInterface);
Run Code Online (Sandbox Code Playgroud)

Jef*_*eff 894

我有一些选择

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

  2. typeof(MyType).GetInterfaces().Contains(typeof(IMyInterface))

对于通用接口,它有点不同.

typeof(MyType).GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IMyInterface<>))
Run Code Online (Sandbox Code Playgroud)

  • 请记住,typeof(IMyInterface).IsAssignableFrom(typeof(IMyInterface))也是如此,这可能会对您的代码产生意外结果. (65认同)
  • 肯定很容易不注意并且反过来获得"IsAssignableFrom"的论据.我现在将使用`GetInterfaces`:p (25认同)
  • @PierreArnaud:IsAssignableFrom最终会调用GetInterfaces,所以可能你的测试首先检查了GetInterfaces,然后检查了IsAssignable.这是因为GetInterfaces缓存了它的结果,因此第一次调用的成本更高 (24认同)
  • 对@ Kosta答案的一个小改动.使用C#6,我们可以执行`typeof(MyType).GetInterface(nameof(IMyInterface))!= null`以获得更好的类型安全性和重构. (14认同)
  • `IsAssignableFrom(t1)`变体比`GetInterfaces()快3倍.在我的代码中包含(t2)`对应物. (12认同)
  • 你也可以使用`typeof(MyType).GetInterface("IMyInterface")!= null` (12认同)
  • 截至撰写此评论时,您的404,这里是+1,这样您就可以再次找到 (4认同)
  • 做了一些测试,似乎`IsAssignableFrom`比`GetInterfaces()快6倍.包含`.另外,"GetInterfaces"是缓存的,但`IsAssignableFrom`不是.即使使用缓存`GetInterfaces().Contains`也比`IsAssignableFrom`慢3.5倍. (3认同)
  • 还有一点需要注意,IsAssignableFrom仅在通过类型“直接”实现接口的情况下才返回true:即,接口A {}接口B:A {}类C:B {}`typeof(C).IsAssignableFrom(typeof(A ))`返回false,而typeof(C).GetInterfaces()。包含(typeof(A))或typeof(C).GetInterface(nameof(A))!= null均为true (2认同)
  • @adospace如果你想测试MyType是否实现IMyInterface,它应该是`typeof(IMyInterface).IsAssignableFrom(typeof(MyType))`。为了帮助记住正确的顺序: `// 如果您可以这样做... if (typeof(IMyInterface).IsAssignableFrom(typeof(MyType)) { // 那么您可以这样做... IMyInterface obj = new MyType() ;}` (2认同)

Sne*_*nea 64

用途Type.IsAssignableFrom:

typeof(IMyInterface).IsAssignableFrom(typeof(MyType));
Run Code Online (Sandbox Code Playgroud)


ajm*_*jma 29

typeof(IMyInterface).IsAssignableFrom(someclass.GetType());
Run Code Online (Sandbox Code Playgroud)

要么

typeof(IMyInterface).IsAssignableFrom(typeof(MyType));
Run Code Online (Sandbox Code Playgroud)

  • 如果你已经有了一个类的实例,那么更好的方法就是`someclass is IMyInterface`,因为它根本不涉及反射的成本.所以,虽然没有错,但它并不是理想的做法. (33认同)
  • @詹姆斯-同意。甚至 Resharper 也给出了同样的建议。 (2认同)

Pan*_*eof 12

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;
}
Run Code Online (Sandbox Code Playgroud)

我认为这是正确的版本,原因有三:

1)它使用GetInterfaces而不是IsAssignableFrom,因为IsAssignableFrom最终在几次检查之后调用GetInterfaces,所以它更快.
2)它遍历本地数组,因此不会进行边界检查.
3)它使用为Type定义的==运算符,因此可能比Equals方法(Contains调用最终将使用)更安全.

  • +1内容,我讨厌parens和埃及括号周围的空间.整个方法也可以写成:return type.GetInterfaces().Any(t => t == ifaceType); (7认同)

tod*_*dmo 8

我已经做了:

public static bool Implements<I>(this Type source) where I : class
{
  return typeof(I).IsAssignableFrom(source);
}
Run Code Online (Sandbox Code Playgroud)

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

用法:

if(MyType.Implements<IInitializable>())
  MyCollection.Initialize();
Run Code Online (Sandbox Code Playgroud)

我刚才说,Implements因为这更直观.我总是IsAssignableFrom翻转.


Eho*_*ret 7

正如其他人已经提到的那样:Benjamin 2013年4月10日22:21"

肯定很容易不注意并且反过来获得IsAssignableFrom的论据.我现在将使用GetInterfaces:p -

那么,另一种方法就是创建一种简短的扩展方法,在某种程度上实现"最常见"的思维方式(同意这是一个非常小的个人选择,根据一个人的偏好使其略微"更自然" ):

public static class TypeExtensions
{
    public static bool IsAssignableTo(this Type type, Type assignableType)
    {
        return assignableType.IsAssignableFrom(type);
    }
}
Run Code Online (Sandbox Code Playgroud)

为什么不去更通用(不确定它是否真的那么有趣,我想我只是传递了另一个'语法'糖):

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));
    }
}
Run Code Online (Sandbox Code Playgroud)

我认为这可能更自然,但再一次只是个人意见的问题:

var isTrue = michelleType.IsAssignableTo<IMaBelle>();
Run Code Online (Sandbox Code Playgroud)

  • 您是否有理由不直接将实现放在扩展方法中?我的意思是确保这可以让你双向调用它,但为什么你需要这样做呢? (4认同)

Ben*_*lde 7

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

var type = typeof(MyType);
var implementsInterface = typeof(IMyInterface).IsAssignableFrom(type) && type.IsClass;
Run Code Online (Sandbox Code Playgroud)

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

var implementations = typeof(TypeInTargetAssembly).Assembly.GetTypes()
                          .Where(t => typeof(IMyInterface).IsAssignableFrom(t) && t.IsClass);
Run Code Online (Sandbox Code Playgroud)


Die*_*ego 6

请注意,如果您有通用接口IMyInterface<T>,那么这将始终返回false

  typeof(IMyInterface<>).IsAssignableFrom(typeof(MyType)) /* ALWAYS FALSE */
Run Code Online (Sandbox Code Playgroud)

这也不起作用:

  typeof(MyType).GetInterfaces().Contains(typeof(IMyInterface<>))  /* ALWAYS FALSE */
Run Code Online (Sandbox Code Playgroud)

但是,如果MyType实现IMyInterface<MyType>此功能并返回true

  typeof(IMyInterface<MyType>).IsAssignableFrom(typeof(MyType))
Run Code Online (Sandbox Code Playgroud)

T但是,您可能在运行时不知道参数的类型。一个有点hacky的解决方案是:

  typeof(MyType).GetInterfaces()
                .Any(x=>x.Name == typeof(IMyInterface<>).Name)
Run Code Online (Sandbox Code Playgroud)

杰夫的解决方案不那么老套:

  typeof(MyType).GetInterfaces()
         .Any(i => i.IsGenericType 
             && i.GetGenericTypeDefinition() == typeof(IMyInterface<>));
Run Code Online (Sandbox Code Playgroud)

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

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

(请注意,上面使用了 linq,它可能比循环慢。)

然后你可以这样做:

   typeof(MyType).IsImplementing(IMyInterface<>)
Run Code Online (Sandbox Code Playgroud)


小智 6

如果您有类型或实例,您可以轻松检查它们是否支持特定接口。

测试一个对象是否实现了某个接口:

if(myObject is IMyInterface) {
  // object myObject implements IMyInterface
}
Run Code Online (Sandbox Code Playgroud)

测试一个类型是否实现了某个接口:

if(typeof(IMyInterface).IsAssignableFrom(typeof(MyType))) {
  // type MyType implements IMyInterface
}
Run Code Online (Sandbox Code Playgroud)

如果您有一个通用对象并想要进行转换以及检查您转换到的接口是否已实现,则代码为:

 var myCastedObject = myObject as IMyInterface;

    if(myCastedObject != null) {
      // object myObject implements IMyInterface
    }
Run Code Online (Sandbox Code Playgroud)


Bil*_*rry 6

搜索此内容的任何人可能会发现以下扩展方法很有用:

public static class TypeExtensions
{
    public static bool ImplementsInterface(this Type type, Type @interface)
    {
        if (type == null)
        {
            throw new ArgumentNullException(nameof(type));
        }

        if (@interface == null)
        {
            throw new ArgumentNullException(nameof(@interface));
        }

        var interfaces = type.GetInterfaces();
        if (@interface.IsGenericTypeDefinition)
        {
            foreach (var item in interfaces)
            {
                if (item.IsConstructedGenericType && item.GetGenericTypeDefinition() == @interface)
                {
                    return true;
                }
            }
        }
        else
        {
            foreach (var item in interfaces)
            {
                if (item == @interface)
                {
                    return true;
                }
            }
        }

        return false;
    }
}
Run Code Online (Sandbox Code Playgroud)

xunit 测试:

public class TypeExtensionTests
{
    [Theory]
    [InlineData(typeof(string), typeof(IList<int>), false)]
    [InlineData(typeof(List<>), typeof(IList<int>), false)]
    [InlineData(typeof(List<>), typeof(IList<>), true)]
    [InlineData(typeof(List<int>), typeof(IList<>), true)]
    [InlineData(typeof(List<int>), typeof(IList<int>), true)]
    [InlineData(typeof(List<int>), typeof(IList<string>), false)]
    public void ValidateTypeImplementsInterface(Type type, Type @interface, bool expect)
    {
        var output = type.ImplementsInterface(@interface);
        Assert.Equal(expect, output);
    }
}
Run Code Online (Sandbox Code Playgroud)


ola*_*ker 5

使用Type.IsAssignableTo(从 .NET 5.0 开始):

typeof(MyType).IsAssignableTo(typeof(IMyInterface));
Run Code Online (Sandbox Code Playgroud)

正如几条评论中所述,IsAssignableFrom 可能被认为是“落后”的混淆。