代码之家  ›  专栏  ›  技术社区  ›  GONeale

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

  •  19
  • GONeale  · 技术社区  · 16 年前

    我想确定泛型对象类型(“T”)方法类型参数是否是集合类型。我通常将T作为泛型.list发送,但它可以是任何集合类型,因为它在助手函数中使用。

    如果它实现IEnumerable<t>,我是否最好测试它?

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

    更新14:17 GMT+10,可能扩展到解决方案 here (但是,仅适用于列表<t>'s not ienumerable<t>'s when it should if list派生?)

    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 回复  |  直到 7 年前
        1
  •  30
  •   this. __curious_geek    16 年前

    这是最简单的检查。

    if(Obj is ICollection)
    {
        //Derived from ICollection
    }
    else
    {
        //Not Derived from ICollection
    }
    
        2
  •  15
  •   Jonathan Rupp    16 年前

    可以将type.getInterface()与损坏的名称一起使用。

    private bool IsTAnEnumerable<T>(T x)
    {
        return null != typeof(T).GetInterface("IEnumerable`1");
    }
    
        3
  •  8
  •   JaredPar    16 年前

    为了在运行时获得T的实际类型,可以使用type of(T)表达式。从那里,普通的类型比较运算符就可以做到这一点。

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

    完整代码示例:

    static bool Foo<T>()
    {
      return typeof(IEnumerable<int>).IsAssignableFrom(typeof(T));
    }
    
    Foo<List<T>>();  // true
    Foo<int>(); // false
    
        4
  •  7
  •   Timwi    11 年前

    就我个人而言,我倾向于使用我自己写的一种方法,叫做 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
    }
    

    重要的是要注意你是通过这里的 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;
    }
    
        5
  •  3
  •   James Curran    16 年前

    另外,记住,仅仅因为您使用的是泛型,不要忘记其他基本技术,在本例中,比如重载。我怀疑你在计划这样的事情:

    void SomeFunc<T>(T t)
    {
        if (IsCollectionCase(t))
           DoSomethingForCollections()
        else
           DoSOmethingElse();
    }
    

    这将更好地处理为:

    void SomeFunc(IEnumerable t)
    {
           DoSomethingForCollections()
    }
    void SomeFunc<T>(T t)
    {
           DoSomethingElse()
    }
    
        6
  •  3
  •   Jeroen Vannevel luciomrx    11 年前

    我会测试 IEnumerable 相反,因为集合类型只能实现 可枚举的 不需要执行 IEnumerable<T> .

    这也取决于:你的意思是 集合类型 ?您可以拥有一个集合,而不实现这些接口中的任何一个。

        7
  •  2
  •   Mitselplik    11 年前

    虽然我不能确定最初的海报的意图是什么,但对于投射到IEnumerable进行测试的效果,已经有了一些反应。这很好,但是每个人都应该知道字符串实例通过了这个测试,这可能不是原始作者想要的。当我去寻找答案并找到这篇文章时,我知道我确实没有:

    string testString = "Test";
    Console.WriteLine(testString as IEnumerable != null);  // returns true
    

    我正在尝试编写一个使用反射来完成某些任务的自定义序列化程序。作为任务的一部分,我需要确定属性值是项的集合/数组/列表还是单个属性值。特别令人恼火的是,几个Linq表达式实际上会产生一个可枚举的类型值,但getType()。IsArray为这些表达式返回false,并将它们强制转换为ICollection也返回空值,但将它们强制转换为IEnumerable则返回非空值。

    所以……目前,我仍在寻求一个适用于所有情况的解决方案。

        8
  •  1
  •   Eduard Malakhov    7 年前

    为了简单和代码共享,我通常使用以下扩展方法:

    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);
    }
    
        9
  •  0
  •   k rey    9 年前

    我在试图将任何对象序列化为JSON格式时遇到了同样的问题。以下是我最后使用的:

    Type typ = value.GetType();
    
    // Check for array type
    if(typeof(IEnumerable).IsAssignableFrom(typ) || typeof(IEnumerable<>).IsAssignableFrom(typ))
    { 
        List<object> list = ((IEnumerable)value).Cast<object>().ToList();
        //Serialize as an array with each item in the list...
    }
    else
    {
        //Serialize as object or value type...
    }
    
        10
  •  0
  •   guneysus    8 年前

    我喜欢仿制药。在该方法中 T 必须具有公共的无参数构造函数,这意味着您不能使用 IList<object> 对于 T . 你必须使用 List<object>

    public static T IsEnumerable<T>() where T : new() {
        if (new T() is IEnumerable) {
    }
    
    推荐文章