Determine if object derives from collection type

2019-03-15 01:46发布

I want to determine if a generic object type ("T") method type parameter is a collection type. I would typically be sending T through as a Generic.List but it could be any collection type as this is used in a helper function.

Would I be best to test if it implements IEnumerable<T>?

If so, what would the code look like?

Update 14:17 GMT+10 Possibly extending on a solution here (however only works for List<T>'s not IEnumerable<T>'s when it should if List derives ?)

T currentObj;    
// works if currentObj is List<T>
currentObj.GetType().GetGenericTypeDefinition() == typeof(List<>)
// does not work if currentObj is List<T>
currentObj.GetType().GetGenericTypeDefinition() == typeof(IEnumerable<>)

10条回答
够拽才男人
2楼-- · 2019-03-15 02:26

In order to get the actual type of T at runtime, you can use the typeof(T) expression. From there the normal type comparison operators will do the trick

bool isEnumerable = typeof(IEnumerable<int>).IsAssignableFrom(typeof(T));

Full Code Sample:

static bool Foo<T>()
{
  return typeof(IEnumerable<int>).IsAssignableFrom(typeof(T));
}

Foo<List<T>>();  // true
Foo<int>(); // false
查看更多
一纸荒年 Trace。
3楼-- · 2019-03-15 02:26

Personally I tend to use a method that I wrote myself, called TryGetInterfaceGenericParameters, which I posted below. Here is how to use it in your case:

Example of use

object currentObj = ...;  // get the object
Type[] typeArguments;
if (currentObj.GetType().TryGetInterfaceGenericParameters(typeof(IEnumerable<>), out typeArguments))
{
    var innerType = typeArguments[0];
    // currentObj implements IEnumerable<innerType>
}
else
{
    // The type does not implement IEnumerable<T> for any T
}

It is important to note here that you pass in typeof(IEnumerable<>), not typeof(IEnumerable) (which is an entirely different type) and also not typeof(IEnumerable<T>) for any T (if you already know the T, you don’t need this method). Of course this works with any generic interface, e.g. you can use typeof(IDictionary<,>) as well (but not typeof(IDictionary)).

Method source

/// <summary>
///     Determines whether the current type is or implements the specified generic interface, and determines that
///     interface's generic type parameters.</summary>
/// <param name="type">
///     The current type.</param>
/// <param name="interface">
///     A generic type definition for an interface, e.g. typeof(ICollection&lt;&gt;) or typeof(IDictionary&lt;,&gt;).</param>
/// <param name="typeParameters">
///     Will receive an array containing the generic type parameters of the interface.</param>
/// <returns>
///     True if the current type is or implements the specified generic interface.</returns>
public static bool TryGetInterfaceGenericParameters(this Type type, Type @interface, out Type[] typeParameters)
{
    typeParameters = null;

    if (type.IsGenericType && type.GetGenericTypeDefinition() == @interface)
    {
        typeParameters = type.GetGenericArguments();
        return true;
    }

    var implements = type.FindInterfaces((ty, obj) => ty.IsGenericType && ty.GetGenericTypeDefinition() == @interface, null).FirstOrDefault();
    if (implements == null)
        return false;

    typeParameters = implements.GetGenericArguments();
    return true;
}
查看更多
Evening l夕情丶
4楼-- · 2019-03-15 02:26

I love generics. In this method T must have a public and parameterless constructor which means you can not use IList<object> for T. You must use List<object>

public static T IsEnumerable<T>() where T : new() {
    if (new T() is IEnumerable) {
}
查看更多
爷的心禁止访问
5楼-- · 2019-03-15 02:27

This will be the simplest check..

if(Obj is ICollection)
{
    //Derived from ICollection
}
else
{
    //Not Derived from ICollection
}
查看更多
手持菜刀,她持情操
6楼-- · 2019-03-15 02:28

You can use Type.GetInterface() with the mangled name.

private bool IsTAnEnumerable<T>(T x)
{
    return null != typeof(T).GetInterface("IEnumerable`1");
}
查看更多
Melony?
7楼-- · 2019-03-15 02:33

For simplicity and code sharing, I usually use this extension method:

public static bool IsGenericList(this object obj)
{
    return IsGenericList(obj.GetType());
}

public static bool IsGenericList(this Type type)
{
    if (type == null)
    {
        throw new ArgumentNullException("type");
    }

    foreach (Type @interface in type.GetInterfaces())
    {
        if (@interface.IsGenericType)
        {
            if (@interface.GetGenericTypeDefinition() == typeof(ICollection<>))
            {
                // if needed, you can also return the type used as generic argument
                return true;
            }
        }
    }

    return (type.GetInterface("IEnumerable") != null);
}
查看更多
登录 后发表回答