ChatGPT解决这个技术问题 Extra ChatGPT

找出一个类型是否实现了一个泛型接口

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

Find out if MyType implements the IList interface, for some T. 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


A
Anton Tykhyy
// 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.


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!)
For those like me who were curious about why the .IsInterface is needed: GetGenericTypeDefinition() throws if it is called on a non-generic type.
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.
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?
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.
c
casperOne

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.


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 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.
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.
u
user989279
    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);
    }

K
Knasterbax

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

G
GenericProgrammer

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!

C
Chris Ballance
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


S
Stan R.

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