ChatGPT解决这个技术问题 Extra ChatGPT

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

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

F
FlyingFoX

You have a few choices:

typeof(IMyInterface).IsAssignableFrom(typeof(MyType)) typeof(MyType).GetInterfaces().Contains(typeof(IMyInterface)) With C# 6 you can use typeof(MyType).GetInterface(nameof(IMyInterface)) != null

For a generic interface, it’s a bit different.

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

Remember that typeof(IMyInterface).IsAssignableFrom(typeof(IMyInterface)) is also true, which may have an unexpected result on your code.
It sure was easy to not pay attention and get the arguments for IsAssignableFrom backwards. I will go with GetInterfaces now :p
The IsAssignableFrom(t1) variant is about 3x faster than the GetInterfaces().Contains(t2) counterpart in my code.
@PierreArnaud: IsAssignableFrom does eventually calls GetInterfaces, so probably your test checked the GetInterfaces first and IsAssignable after. That is because GetInterfaces caches it's results so the first invocation costs more
A small change to @Kosta's answer. With C# 6 we can do typeof(MyType).GetInterface(nameof(IMyInterface)) != null for better type safety and refactoring.
S
Snea

Use Type.IsAssignableFrom:

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

a
ajma
typeof(IMyInterface).IsAssignableFrom(someclass.GetType());

or

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

If you already have an instance of the class a much better approach is simply someclass is IMyInterface as that doesn't involve the cost of reflection at all. So, while not wrong, its not an ideal way to do it.
@James - Agree. Even Resharper gives the same suggestion.
@JamesJ.ReganIV you should post that as an answer, I almost missed your comment
@reggaeguitar, thanks, but the comment doesn't answer the original question. The question asks for the Reflection solution, I am just saying in this answer's first case where you do have an instance of the object reflection isn't the ideal solution.
@JamesJ.ReganIV Actually, is checks in both directions of the inheritance hierarchy whereas IsAssignableFrom only checks upwards. Also, if you have an instance of an object, you should call IsInstanceOfType (which also only looks upwards).
E
Emond
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:

It uses GetInterfaces and not IsAssignableFrom, it's faster since IsAssignableFrom eventually after several checks does call GetInterfaces. It iterates over the local array, so there will be no bounds checks. It uses the == operator which is defined for Type, so probably is safer than the Equals method (that the Contains call, will eventually use).


+1 for content, I hate the spaces around the parens and the Egyptian braces though. Also the whole method can be written as: return type.GetInterfaces().Any(t => t == ifaceType);
Type.IsAssignableFrom() internaly acts exactly like your code
Also why not type.GetInterfaces().Contains(ifaceType) which doesnt use LINQ.
o
olabacker

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".


t
toddmo

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.


You could do return typeof(I).IsInterface && typeof(I).IsAssignableFrom(source); to return false on any 'incorrect' usages of the method, that is; using it with a class type instead of an interface type, alternatively throw an exception if the type-parameter is not an interface. Though you could argue that a derived class 'implements' it's parent...
佚名

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
    }

N
Natalie Perret

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

Is there a reason you didn't just put the implementation directly in the extension method? I mean sure this lets you call it both ways, but why would you ever need to do that?
@MarqueIV sorry to get back to you almost 2 years late, well I guess it was an old bad habit back then to wrap helper method in extension method to avoid repeating code, will edit my answer :)
@MarqueIV done plus changed my other bad habit of not using alias , i.e. Boolean => bool (I don't why I used to have some strict "fancy" rules of coding when I was younger).
B
Ben Wilde

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

B
Bill Barry

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

D
Diego

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

N
NucS

IsAssignableFrom is now moved to TypeInfo:

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

E
EricBDev

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

As you can see in accepted answer, you interchanged the types in usage of IsAssignableFrom. Just like Benjamin and Ehouarn warn about.
P
Pingi

what about

if(MyType as IMyInterface != null)

?


This is obvious when I have an instance. Not useful when I have a Type from reflection
L
LaWi

What about

typeof(IWhatever).GetTypeInfo().IsInterface

s
sskiba

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
}

Your solution will only work for existing objects. It is not applicable for types. Moreover, if you have a created object, you can get its type and perform the necessary checks.