276

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?

sduplooy
  • 14,340
  • 9
  • 41
  • 60

14 Answers14

476

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<>));
sduplooy
  • 14,340
  • 9
  • 41
  • 60
  • 1
    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. – Daniel T. Nov 10 '09 at 03:25
  • 7
    I recommend you make this an extension method a la http://bit.ly/ccza8B -- will clean this up quite nicely! – Brad Heller Jul 27 '10 at 23:06
  • 2
    Depending on your needs, you may find you need to recur on the interfaces returned. – Sebastian Good Feb 08 '12 at 15:44
  • 6
    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 ... – Sofija Mar 05 '12 at 22:12
  • 4
    minor addition: if IBar has multiple generic types, you need to indicate this like: `typeof(IBar<,,,>)` with commas acting like placeholders – Rob Von Nesselrode Sep 12 '18 at 04:14
  • I should add that [TypeSupport](https://github.com/replaysMike/TypeSupport) adds this very cleanly using `type.Implements(typeof(IBar<>))` and covers all case conditions. – Michael Brown Aug 11 '21 at 00:41
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.

Community
  • 1
  • 1
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
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;
    }
}
TcKs
  • 25,849
  • 11
  • 66
  • 104
  • 2
    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() – Michael Meadows Feb 02 '09 at 15:39
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!
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • 2
    "IsAssignableFrom" was exactly what I was looking for - thanks – Jesper Oct 02 '10 at 14:48
  • 27
    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 Sep 11 '12 at 09:14
  • 1
    @ctusch then, any solution for that? – Tohid Oct 08 '18 at 07:55
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();
Ben Foster
  • 34,340
  • 40
  • 176
  • 285
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);
    }
Philip Pittle
  • 11,821
  • 8
  • 59
  • 123
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));

    }
Sebastian Good
  • 6,310
  • 2
  • 33
  • 57
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>.

Andrew Hare
  • 344,730
  • 71
  • 640
  • 635
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();
Pablo Retyk
  • 5,690
  • 6
  • 44
  • 59
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));
    }
Derek Greer
  • 15,454
  • 5
  • 45
  • 52
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>)));
 }
Waleed A.K.
  • 1,596
  • 13
  • 13
2
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.

Zoidbergseasharp
  • 3,697
  • 1
  • 11
  • 20
  • 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. – Christian Klemm Aug 20 '22 at 22:31
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());
   }
}   
Osama AbuSitta
  • 3,918
  • 4
  • 35
  • 51
-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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
mindlace
  • 313
  • 2
  • 8
  • 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. – andyroschy Jan 19 '16 at 19:37
  • 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". – nathanchere Aug 15 '16 at 12:45
  • Why not this? `bool implementsGeneric = (anObject.Implements(typeof(IBar<>).Name) != null);` – Maxime Gélinas Jun 17 '17 at 02:39