57

Let's say I have a type, MyType. I want to do the following:

  1. Find out if MyType implements the IList interface, for some T.
  2. If the answer to (1) is yes, find out what T is.

It seems like the way to do this is GetInterface(), but that only lets you search by a specific name. Is there a way to search for "all interfaces that are of the form IList" (If possible it woudl also be useful if it worked if the interface was a subinterface of IList.)

Related: How to determine if a type implements a specific generic interface type

Community
  • 1
  • 1
Alex319
  • 3,818
  • 9
  • 34
  • 40

7 Answers7

88
// this conditional is necessary if myType can be an interface,
// because an interface doesn't implement itself: for example,
// typeof (IList<int>).GetInterfaces () does not contain IList<int>!
if (myType.IsInterface && myType.IsGenericType && 
    myType.GetGenericTypeDefinition () == typeof (IList<>))
    return myType.GetGenericArguments ()[0] ;

foreach (var i in myType.GetInterfaces ())
    if (i.IsGenericType && i.GetGenericTypeDefinition () == typeof (IList<>))
        return i.GetGenericArguments ()[0] ;

Edit: Even if myType implements IDerivedFromList<> but not directly IList<>, IList<> will show up in the array returned by GetInterfaces().

Update: added a check for the edge case where myType is the generic interface in question.

Anton Tykhyy
  • 19,370
  • 5
  • 54
  • 56
  • This handles the case of arrays as well, which is nice. If you want to test for arrays explicitly then use "if (myType.IsArray) return myType.GetElementType();" (And while this might be faster, I hope none of this is performance-critical!) – yoyo May 28 '13 at 21:27
  • For those like me who were curious about why the .IsInterface is needed: GetGenericTypeDefinition() throws if it is called on a non-generic type. – GameFreak Oct 29 '16 at 01:46
  • The Type.IsGenericType property is not available on netstandard 1.6 and lower (and thus not available on .NET Core 1.0), but you can use TypeInfo.IsGenericType instead: type.GetTypeInfo().IsGenericType. – dotarj Oct 13 '17 at 11:42
  • What if MyType is an open genetic type? Do you still need to call GetGenericTypeDefinitiin? In other words, why does typeof(Dictionary<,>).GetInterfaces().Contains(typeof(IDictionary<,>)) return false? – Daniel Arant Jan 12 '18 at 17:14
  • Because you can't implement an open generic interface. `Dictionary<,>` implements ``IDictionary<`0, `1>`` where `'0` and `'1` refer to the type parameters of `Dictionary<,>` - look it up in ILDasm or similar. – Anton Tykhyy Jan 13 '18 at 06:21
11

Using reflection (and some LINQ) you can easily do this:

public static IEnumerable<Type> GetIListTypeParameters(Type type)
{
    // Query.
    return
        from interfaceType in type.GetInterfaces()
        where interfaceType.IsGenericType
        let baseInterface = interfaceType.GetGenericTypeDefinition()
        where baseInterface == typeof(IList<>)
        select interfaceType.GetGenericArguments().First();
}

First, you are getting the interfaces on the type and filtering out only for those that are a generic type.

Then, you get the generic type definition for those interface types, and see if it is the same as IList<>.

From there, it's a simple matter of getting the generic arguments for the original interface.

Remember, a type can have multiple IList<T> implementations, which is why the IEnumerable<Type> is returned.

casperOne
  • 73,706
  • 19
  • 184
  • 253
  • If you wrap the return expression in parentheses and add another ".First()" to the end then it returns a Type instead of a length-1 IEnumerable, which is a little easier to deal with. (Personally I think this is an example of being too clever with LINQ, but maybe that's just me.) – yoyo May 28 '13 at 21:35
  • @yoyo Or, you can just call `First` on the results of this method. If you return `First` from this method, you're *assuming* one type parameter which is outright *wrong*. – casperOne May 29 '13 at 00:35
  • Good point @casperOne, the OP's MyType could implement IList and IList. So the question should have been "find the T's" not "find the T". The accepted answer doesn't deal with this either. – yoyo May 31 '13 at 15:52
4
    public static bool Implements<I>(this Type type) where I : class
    {
         if (!typeof(I).IsInterface)
         {
             throw new ArgumentException("Only interfaces can be 'implemented'.");
         }

         return typeof(I).IsAssignableFrom(type);
    }
user989279
  • 41
  • 1
2

Using Anton Tykhyy's proposal, here is a small Extension Method to check if some type implements a generic interface with one given generic type parameters:

public static class ExtensionMethods
{
    /// <summary>
    /// Checks if a type has a generic interface. 
    /// For example 
    ///     mytype.HasGenericInterface(typeof(IList<>), typeof(int)) 
    /// will return TRUE if mytype implements IList<int>
    /// </summary>
    public static bool HasGenericInterface(this Type type, Type interf, Type typeparameter)
    {
        foreach (Type i in type.GetInterfaces())
            if (i.IsGenericType && i.GetGenericTypeDefinition() == interf)
                if (i.GetGenericArguments()[0] == typeparameter)
                    return true;

        return false;
    }
}
Knasterbax
  • 7,895
  • 1
  • 29
  • 23
1

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!
0

If i understand your question correctly, this is what you are trying to do. If not, please explain further.

public class MyType : ISomeInterface
{
}

MyType o = new MyType();

if(o is ISomeInterface)
 {
 }

edit: if you change your question, please add the fact that you edited..because now my answer looks like it doesn't belong.

In that case, here is a very large LINQ

            var item = typeof(MyType).GetInterfaces()
                            .Where(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IList<>))
                            .Select(t => t.GetGenericArguments().First())
                            .FirstOrDefault();

if( item != null )
 //it has a type
Stan R.
  • 15,757
  • 4
  • 50
  • 58
0
Type[] typeArray2 = c.GetInterfaces();
for (int num2 = 0; num2 < typeArray2.Length; num2++)
{
     if (this == typeArray2[num2])
     {
          return true;
     }
}

--http://www.hanselman.com/blog/DoesATypeImplementAnInterface.aspx

Chris Ballance
  • 33,810
  • 26
  • 104
  • 151