确定对象是否派生自集合类型

GON*_*ale 20 .net c# reflection

我想确定通用对象类型("T")方法类型参数是否是集合类型.我通常会将T通过作为Generic.List发送,但它可以是任何集合类型,因为它在辅助函数中使用.

我是否最好测试它是否实现IEnumerable <T>?

如果是这样,代码会是什么样的?

更新格林尼治标准时间14:17 + 10可能会扩展到这里的解决方案(但是如果列表派生的话,它只适用于List <T>而不是IEnumerable <T>)

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<>)
Run Code Online (Sandbox Code Playgroud)

thi*_*eek 34

这将是最简单的检查..

if(Obj is ICollection)
{
    //Derived from ICollection
}
else
{
    //Not Derived from ICollection
}
Run Code Online (Sandbox Code Playgroud)

  • **警告!**如果`obj是ICollection`是真的,它**不遵循**'obj`也为任何T实现`ICollection <T>`接口`ICollection`和`ICollection <T> `是两个独立的接口. (31认同)
  • 很简单。谢谢,即使“obj is IEnumerable”和“obj is IList”也能使用你的想法。我试过 'obj is IEnumerable&lt;T&gt;', 'obj is IList&lt;T&gt;'.. 有趣的是,虽然这不起作用。不过我有一个想法,T 将是一个集合。所以也许它正在以某种方式测试列表列表*耸肩*。 (2认同)

Jon*_*upp 15

您可以将Type.GetInterface()与受损名称一起使用.

private bool IsTAnEnumerable<T>(T x)
{
    return null != typeof(T).GetInterface("IEnumerable`1");
}
Run Code Online (Sandbox Code Playgroud)

  • 相对于右边?C程序员的旧习惯,其中"if(i = 0)"是条件内的赋值,而不是编译错误. (7认同)

Jar*_*Par 8

为了在运行时获取T的实际类型,可以使用typeof(T)表达式.从那里,普通类型比较运算符将起到作用

bool isEnumerable = typeof(IEnumerable<int>).IsAssignableFrom(typeof(T));
Run Code Online (Sandbox Code Playgroud)

完整代码示例:

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

Foo<List<T>>();  // true
Foo<int>(); // false
Run Code Online (Sandbox Code Playgroud)


Tim*_*mwi 7

就个人而言,我倾向于使用我自己编写的方法,TryGetInterfaceGenericParameters我在下面发布了这个方法.以下是如何在您的情况下使用它:

使用示例

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
}
Run Code Online (Sandbox Code Playgroud)

重要的是要注意你传入typeof(IEnumerable<>),而不是 typeof(IEnumerable)(这是一个完全不同的类型),也不 typeof(IEnumerable<T>)是任何T(如果你已经知道T,你不需要这种方法).当然这适用于任何通用接口,例如您也可以使用typeof(IDictionary<,>)(但不能 typeof(IDictionary)).

方法来源

/// <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;
}
Run Code Online (Sandbox Code Playgroud)