282

Assume the following type definitions:

public interface IFoo<T> : IBar<T> {}
public class Foo<T> : IFoo<T> {}

How do I find out whether the type Foo implements the generic interface IBar<T> when only the mangled type is available?

0

14 Answers 14

494

By using the answer from TcKs it can also be done with the following LINQ query:

bool isBar = foo.GetType().GetInterfaces().Any(x =>
  x.IsGenericType &&
  x.GetGenericTypeDefinition() == typeof(IBar<>));
Sign up to request clarification or add additional context in comments.

6 Comments

This is a very elegant solution! The others I've seen on SO use foreach loops or longer LINQ queries. Keep in mind though that to use this, you need to have .NET framework 3.5.
I recommend you make this an extension method a la bit.ly/ccza8B -- will clean this up quite nicely!
Depending on your needs, you may find you need to recur on the interfaces returned.
I'd say this should have been implemented within .net much better... as a core ... like member.Implements(IBar) or CustomType.Implements(IBar), or even better, using a keyword "is" .... I'm exploring c# and I'm a more then bit disappointed in .net right now ...
minor addition: if IBar has multiple generic types, you need to indicate this like: typeof(IBar<,,,>) with commas acting like placeholders
|
36

You have to go up through the inheritance tree and find all the interfaces for each class in the tree, and compare typeof(IBar<>) with the result of calling Type.GetGenericTypeDefinition if the interface is generic. It's all a bit painful, certainly.

See this answer and these ones for more info and code.

3 Comments

why not just cast to IBar<SomeClass> and check for null? (I mean casting with 'as' of course)
T is unknown and cannot be cast to a specific type.
@sduplooy: maybe I am missing something how can T be unknown? it would compile public class Foo : IFoo<T> {}
28
public interface IFoo<T> : IBar<T> {}
public class Foo : IFoo<Foo> {}

var implementedInterfaces = typeof( Foo ).GetInterfaces();
foreach( var interfaceType in implementedInterfaces ) {
    if ( false == interfaceType.IsGeneric ) { continue; }
    var genericType = interfaceType.GetGenericTypeDefinition();
    if ( genericType == typeof( IFoo<> ) ) {
        // do something !
        break;
    }
}

1 Comment

Since typeof( Foo ) returns the a System.Type object (describing Foo), the GetType() call will always return the type for System.Type. You should change to typeof(Foo).GetInterfaces()
6

I'm using a slightly simpler version of @GenericProgrammers extension method:

public static bool Implements<TInterface>(this Type type) where TInterface : class {
    var interfaceType = typeof(TInterface);

    if (!interfaceType.IsInterface)
        throw new InvalidOperationException("Only interfaces can be implemented.");

    return (interfaceType.IsAssignableFrom(type));
}

Usage:

    if (!featureType.Implements<IFeature>())
        throw new InvalidCastException();

1 Comment

It still doesn't work as per the original question's requirement which is for generic interfaces.
6

As a helper method extension

public static bool Implements<I>(this Type type, I @interface) where I : class
{
    if(((@interface as Type)==null) || !(@interface as Type).IsInterface)
        throw new ArgumentException("Only interfaces can be 'implemented'.");

    return (@interface as Type).IsAssignableFrom(type);
}

Example usage:

var testObject = new Dictionary<int, object>();
result = testObject.GetType().Implements(typeof(IDictionary<int, object>)); // true!

3 Comments

"IsAssignableFrom" was exactly what I was looking for - thanks
This doesn't work for the asker's requirement of not knowing the generic type parameter. From your example testObject.GetType().Implements(typeof(IDictionary<,>)); will return false.
@ctusch then, any solution for that?
5

To tackle the type system completely, I think you need to handle recursion, e.g. IList<T> : ICollection<T> : IEnumerable<T>, without which you wouldn't know that IList<int> ultimately implements IEnumerable<>.

    /// <summary>Determines whether a type, like IList&lt;int&gt;, implements an open generic interface, like
    /// IEnumerable&lt;&gt;. Note that this only checks against *interfaces*.</summary>
    /// <param name="candidateType">The type to check.</param>
    /// <param name="openGenericInterfaceType">The open generic type which it may impelement</param>
    /// <returns>Whether the candidate type implements the open interface.</returns>
    public static bool ImplementsOpenGenericInterface(this Type candidateType, Type openGenericInterfaceType)
    {
        Contract.Requires(candidateType != null);
        Contract.Requires(openGenericInterfaceType != null);

        return
            candidateType.Equals(openGenericInterfaceType) ||
            (candidateType.IsGenericType && candidateType.GetGenericTypeDefinition().Equals(openGenericInterfaceType)) ||
            candidateType.GetInterfaces().Any(i => i.IsGenericType && i.ImplementsOpenGenericInterface(openGenericInterfaceType));

    }

Comments

5

In case you wanted an extension method that would support generic base types as well as interfaces, I've expanded sduplooy's answer:

    public static bool InheritsFrom(this Type t1, Type t2)
    {
        if (null == t1 || null == t2)
            return false;

        if (null != t1.BaseType &&
            t1.BaseType.IsGenericType &&
            t1.BaseType.GetGenericTypeDefinition() == t2)
        {
            return true;
        }

        if (InheritsFrom(t1.BaseType, t2))
            return true;

        return
            (t2.IsAssignableFrom(t1) && t1 != t2)
            ||
            t1.GetInterfaces().Any(x =>
              x.IsGenericType &&
              x.GetGenericTypeDefinition() == t2);
    }

1 Comment

This extension is simply perfect!
4
var genericType = typeof(ITest<>);
Console.WriteLine(typeof(Test).GetInterfaces().Any(x => x.GetGenericTypeDefinition().Equals(genericType))); // prints: "True"

interface ITest<T> { };

class Test : ITest<string> { }

This worked for me.

1 Comment

This should be the accepted answer. Note that it is generally a good idea to check whether a type is generic before calling GetGenericTypeDefinition() because otherwise you might get an exception.
3

You have to check against a constructed type of the generic interface.

You will have to do something like this:

foo is IBar<String>

because IBar<String> represents that constructed type. The reason you have to do this is because if T is undefined in your check, the compiler doesn't know if you mean IBar<Int32> or IBar<SomethingElse>.

Comments

3

First of all public class Foo : IFoo<T> {} does not compile because you need to specify a class instead of T, but assuming you do something like public class Foo : IFoo<SomeClass> {}

then if you do

Foo f = new Foo();
IBar<SomeClass> b = f as IBar<SomeClass>;

if(b != null)  //derives from IBar<>
    Blabla();

Comments

2

Method to check if the type inherits or implements a generic type:

   public static bool IsTheGenericType(this Type candidateType, Type genericType)
    {
        return
            candidateType != null && genericType != null &&
            (candidateType.IsGenericType && candidateType.GetGenericTypeDefinition() == genericType ||
             candidateType.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == genericType) ||
             candidateType.BaseType != null && candidateType.BaseType.IsTheGenericType(genericType));
    }

Comments

2

Try the following extension.

public static bool Implements(this Type @this, Type @interface)
{
    if (@this == null || @interface == null) return false;
    return @interface.GenericTypeArguments.Length>0
        ? @interface.IsAssignableFrom(@this)
        : @this.GetInterfaces().Any(c => c.Name == @interface.Name);
}

To test it. create

public interface IFoo { }
public interface IFoo<T> : IFoo { }
public interface IFoo<T, M> : IFoo<T> { }
public class Foo : IFoo { }
public class Foo<T> : IFoo { }
public class Foo<T, M> : IFoo<T> { }
public class FooInt : IFoo<int> { }
public class FooStringInt : IFoo<string, int> { }
public class Foo2 : Foo { }

and the test method

public void Test()
{
    Console.WriteLine(typeof(Foo).Implements(typeof(IFoo)));
    Console.WriteLine(typeof(FooInt).Implements(typeof(IFoo)));
    Console.WriteLine(typeof(FooInt).Implements(typeof(IFoo<>)));
    Console.WriteLine(typeof(FooInt).Implements(typeof(IFoo<int>)));
    Console.WriteLine(typeof(FooInt).Implements(typeof(IFoo<string>)));
    Console.WriteLine(typeof(FooInt).Implements(typeof(IFoo<,>)));
    Console.WriteLine(typeof(FooStringInt).Implements(typeof(IFoo<,>)));
    Console.WriteLine(typeof(FooStringInt).Implements(typeof(IFoo<string,int>)));
    Console.WriteLine(typeof(Foo<int,string>).Implements(typeof(IFoo<string>)));
 }

1 Comment

Checking the FullName would be safer? What if IFoo<> is defined in two separate namespaces?
0

You can add the below extension method:

public static TypeExtension
{
    public static bool IsImplement<T>(this Type type)
    {
         return type.IsImplement(typeof(T));
    }

    public static bool IsImplement(this Type type, Type interfaceType)
    {
        if (!interfaceType.IsInterface)
              throw new InvalidOperationException("Only interfaces can be implemented.");

       return type.IsAssignableTo(interfaceType) ||
           interfaceType.IsGenericType && type.GetInterfaces()
            .Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == interfaceType.GetGenericTypeDefinition());
   }
}   

Comments

-3

There shouldn't be anything wrong the following:

bool implementsGeneric = (anObject.Implements("IBar`1") != null);

For extra credit you could catch AmbiguousMatchException if you wanted to provide a specific generic-type-parameter with your IBar query.

3 Comments

Well, it's usually better to avoid using string literals when possible. This approach would make it harder to refactor the application, since renaming the IBar interface would not change the string literal, and the error would only be detectable at runtime.
As much as I usually agree with the comment above on using 'magic strings' etc, this is still the best approach I've found. Well close enough - testing for the PropertyType.Name equalling "IWhatever`1".
Why not this? bool implementsGeneric = (anObject.Implements(typeof(IBar<>).Name) != null);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.