如何使用 C# 反射确定类型是否实现接口

发布于 2024-10-16 18:38:47 字数 288 浏览 2 评论 0原文

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

public interface IMyInterface {}

public class MyType : IMyInterface {}

// should yield 'true'
typeof(MyType)./* ????? */MODELS_INTERFACE(IMyInterface);

Does reflection in C# offer a way to determine if some given System.Type type models some interface?

public interface IMyInterface {}

public class MyType : IMyInterface {}

// should yield 'true'
typeof(MyType)./* ????? */MODELS_INTERFACE(IMyInterface);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

暗藏城府 2024-10-23 18:38:48
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 经过多次检查后最终确实调用
    获取接口。
  2. 它迭代本地数组,所以会有
    没有边界检查。
  3. 它使用 == 运算符,该运算符定义为
    类型,因此可能比 Equals 方法更安全(即 Contains
    调用,最终会使用)。
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;
}

I think this is the correct release, for three reasons:

  1. It uses GetInterfaces and not IsAssignableFrom, it's faster since
    IsAssignableFrom eventually after several checks does call
    GetInterfaces.
  2. It iterates over the local array, so there will be
    no bounds checks.
  3. It uses the == operator which is defined for
    Type, so probably is safer than the Equals method (that the Contains
    call, will eventually use).
天邊彩虹 2024-10-23 18:38:48

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

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

if(myObject is IMyInterface) {
  // object myObject implements IMyInterface
}

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

if(typeof(IMyInterface).IsAssignableFrom(typeof(MyType))) {
  // type MyType implements IMyInterface
}

如果您有一个泛型对象并且想要进行强制转换并检查您强制转换到的接口是否已实现,则代码为:

 var myCastedObject = myObject as IMyInterface;

    if(myCastedObject != null) {
      // object myObject implements IMyInterface
    }

If you have a type or an instance you can easily check if they support a specific interface.

To test if an object implements a certain interface:

if(myObject is IMyInterface) {
  // object myObject implements IMyInterface
}

To test if a type implements a certain interface:

if(typeof(IMyInterface).IsAssignableFrom(typeof(MyType))) {
  // type MyType implements IMyInterface
}

If you got a generic object and want to do a cast as well as a check if the interface you cast to is implemented the code is:

 var myCastedObject = myObject as IMyInterface;

    if(myCastedObject != null) {
      // object myObject implements IMyInterface
    }
妄断弥空 2024-10-23 18:38:48

我刚刚做了:

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

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

用法:

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

我只是说Implements,因为这样更直观。我总是会遇到 IsAssignableFrom 翻转的情况。

I just did:

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

I wish I could have said where I : interface, but interface is not a generic parameter constraint option. class is as close as it gets.

Usage:

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

I just said Implements because that's more intuitive. I always get IsAssignableFrom flip-flopped.

东京女 2024-10-23 18:38:48

正如其他人已经提到的:
本杰明 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);
    }
}

为什么不更通用一点(好吧不确定它是否真的那么有趣,我想我只是再传递一点“语法”糖):

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));
    }
}

我认为它这样可能会更自然,但这又只是个人意见的问题:

var isTrue = michelleType.IsAssignableTo<IMaBelle>();

As someone else already mentioned:
Benjamin Apr 10 '13 at 22:21"

It sure was easy to not pay attention and get the arguments for
IsAssignableFrom backwards. I will go with GetInterfaces now :p –

Well, another way around is just to create a short extension method that fulfills, to some extent, the "most usual" way of thinking (and agreed this is a very little personal choice to make it slightly "more natural" based on one's preferences):

public static class TypeExtensions
{
    public static bool IsAssignableTo(this Type type, Type assignableType)
    {
        return assignableType.IsAssignableFrom(type);
    }
}

And why not going a bit more generic (well not sure if it is really that interesting, well I assume I'm just passing another pinch of 'syntaxing' sugar):

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));
    }
}

I think it might be much more natural that way, but once again just a matter of very personal opinions:

var isTrue = michelleType.IsAssignableTo<IMaBelle>();
我做我的改变 2024-10-23 18:38:48

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

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

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

var implementations = typeof(TypeInTargetAssembly).Assembly.GetTypes()
                          .Where(t => typeof(IMyInterface).IsAssignableFrom(t) && t.IsClass);

Modifying Jeff's answer for optimal performance (thanks to performance test by Pierre Arnaud):

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

To find all types that implement an interface in a given Assembly:

var implementations = typeof(TypeInTargetAssembly).Assembly.GetTypes()
                          .Where(t => typeof(IMyInterface).IsAssignableFrom(t) && t.IsClass);
時窥 2024-10-23 18:38:48

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

  typeof(IMyInterface<>).IsAssignableFrom(typeof(MyType)) /* ALWAYS FALSE */

这也不起作用:

  typeof(MyType).GetInterfaces().Contains(typeof(IMyInterface<>))  /* ALWAYS FALSE */

但是,如果MyType 实现了 IMyInterface 这有效并返回 true

  typeof(IMyInterface<MyType>).IsAssignableFrom(typeof(MyType))

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

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

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

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

这里有一个适用于任何情况的 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);
    }
}

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

然后你可以这样做:

   typeof(MyType).IsImplementing(IMyInterface<>)

Note that if you have a generic interface IMyInterface<T> then this will always return false:

  typeof(IMyInterface<>).IsAssignableFrom(typeof(MyType)) /* ALWAYS FALSE */

This doesn't work either:

  typeof(MyType).GetInterfaces().Contains(typeof(IMyInterface<>))  /* ALWAYS FALSE */

However, if MyType implements IMyInterface<MyType> this works and returns true:

  typeof(IMyInterface<MyType>).IsAssignableFrom(typeof(MyType))

However, you likely will not know the type parameter T at runtime. A somewhat hacky solution is:

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

Jeff's solution is a bit less hacky:

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

Here's a extension method on Type that works for any case:

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);
    }
}

(Note that the above uses linq, which is probably slower than a loop.)

You can then do:

   typeof(MyType).IsImplementing(IMyInterface<>)
心舞飞扬 2024-10-23 18:38:48

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

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;
    }
}

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);
    }
}

Anyone searching for this might find the following extension method useful:

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;
    }
}

xunit tests:

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);
    }
}
半﹌身腐败 2024-10-23 18:38:48

IsAssignableFrom 现在移至 TypeInfo

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

IsAssignableFrom is now moved to TypeInfo:

typeof(ISMSRequest).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo());
浮生面具三千个 2024-10-23 18:38:48

正确的答案是

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

但是,

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

可能会返回错误的结果,如以下代码所示,使用字符串和 IConvertible:

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

结果:

 isConvertibleDirect: True
 isConvertibleTypeAssignable: False
 isConvertibleHasInterface: True

A correct answer is

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

However,

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

might return a wrong result, as the following code shows with string and IConvertible:

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

Results:

 isConvertibleDirect: True
 isConvertibleTypeAssignable: False
 isConvertibleHasInterface: True
我的影子我的梦 2024-10-23 18:38:48

怎么样

if(MyType as IMyInterface != null)

what about

if(MyType as IMyInterface != null)

?

久光 2024-10-23 18:38:48

怎么样

typeof(IWhatever).GetTypeInfo().IsInterface

What about

typeof(IWhatever).GetTypeInfo().IsInterface
装纯掩盖桑 2024-10-23 18:38:48

如果你不需要使用反射并且你有一个对象,你可以使用这个:

if(myObject is IMyInterface )
{
 // it's implementing IMyInterface
}

If you don't need to use reflection and you have an object, you can use this:

if(myObject is IMyInterface )
{
 // it's implementing IMyInterface
}
居里长安 2024-10-23 18:38:47

您有几种选择:

  1. typeof(IMyInterface).IsAssignableFrom(typeof(MyType)) 或(从 .NET 5 开始)等效的逆,typeof(MyType).IsAssignableTo(typeof(IMyInterface) ))
  2. typeof(MyType).GetInterfaces().Contains(typeof(IMyInterface))
  3. 在 C# 6+ 中,您可以使用 nameof 运算符 typeof(MyType).GetInterface(nameof(IMyInterface)) ! = null - 但请注意 nameof 不会返回完全限定的类型名称,因此如果您在不同的命名空间中有多个命名相同的接口,您最终可能会得到所有这些

接口一个通用接口,它有点复杂:

Array.Exists(
    typeof(MyType).GetInterfaces(),
    i => i.IsGenericType
      && i.GetGenericTypeDefinition() == typeof(IMyInterface<>))

或者使用 LINQ

typeof(MyType).GetInterfaces().Any(
    i => i.IsGenericType
      && i.GetGenericTypeDefinition() == typeof(IMyInterface<>))

You have a few choices:

  1. typeof(IMyInterface).IsAssignableFrom(typeof(MyType)) or (as of .NET 5) the equivalent inverse, typeof(MyType).IsAssignableTo(typeof(IMyInterface))
  2. typeof(MyType).GetInterfaces().Contains(typeof(IMyInterface))
  3. With C# 6+ you can use the nameof operator typeof(MyType).GetInterface(nameof(IMyInterface)) != null - but beware that nameof does not return the fully-qualified type name, so if you have multiple interfaces named the same in different namespaces, you may end up getting all of them

For a generic interface, it’s a bit more involved:

Array.Exists(
    typeof(MyType).GetInterfaces(),
    i => i.IsGenericType
      && i.GetGenericTypeDefinition() == typeof(IMyInterface<>))

or with LINQ:

typeof(MyType).GetInterfaces().Any(
    i => i.IsGenericType
      && i.GetGenericTypeDefinition() == typeof(IMyInterface<>))
客…行舟 2024-10-23 18:38:47

使用 Type.IsAssignableFrom

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

Use Type.IsAssignableFrom:

typeof(IMyInterface).IsAssignableFrom(typeof(MyType));
夜未央樱花落 2024-10-23 18:38:47
typeof(IMyInterface).IsAssignableFrom(someclass.GetType());

或者

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

or

typeof(IMyInterface).IsAssignableFrom(typeof(MyType));
月亮是我掰弯的 2024-10-23 18:38:47

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

typeof(MyType).IsAssignableTo(typeof(IMyInterface));

正如几条评论中所述,IsAssignableFrom 可能会因“向后”而被认为令人困惑。

Use Type.IsAssignableTo (as of .NET 5.0):

typeof(MyType).IsAssignableTo(typeof(IMyInterface));

As stated in a couple of comments IsAssignableFrom may be considered confusing by being "backwards".

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文