【问题标题】:How to detect if T is IEnumerable<T2>, and if so get type of T2?如何检测 T 是否为 IEnumerable<T2>,如果是则获取 T2 的类型?
【发布时间】:2011-01-07 22:28:27
【问题描述】:

我知道this 的问题,这是后续问题,还有this 的问题,但我无法将它们放在一起以帮助我做我想做的事情:

我有一个泛型类型,我想检查 T 是否为 struct 或者如果它实现了 IEnumerable&lt;T2&gt;,那么我想检查 T2 是否为 struct

到目前为止,我已经到了这里('因为杂乱无章的代码,这是实验性的):

private class TestClass<T>
{
    public TestClass()
    {
        Type type = typeof(T);
        //(detecting T == IEnumerable<something> ommitted for clarity)
        Type enumerableType = type.GetInterfaces()
                .Where(t => t.IsGenericType)
                .Select(t => t.GetGenericTypeDefinition())
                .Where(t => t == typeof(IEnumerable<>))
                .FirstOrDefault();
        if(enumerableType != null) 
        {
            Type enumeratedType = type.GetGenericArguments().First();
            if(!enumeratedType.IsValueType) //throw etc...
        }
    }
}

我遇到的问题是enumerableTypeIEnumerable&lt;&gt;,所以enumeratedType 输出为T,而不是我传入的任何内容(例如new TestClass&lt;int[]&gt;())。

【问题讨论】:

    标签: c# generics reflection


    【解决方案1】:

    您的问题是您选择了具有所有数据的类型以支持它的擦除泛型类型模板。

    试试:

        Type enumerableType = type.GetInterfaces()
                .Where(t => t.IsGenericType)
                .Where(t => t.GetGenericTypeDefinition() == typeof(IEnumerable<>))
                .Select(t => t.GetGenericArguments()[0])
                .FirstOrDefault();
    

    【讨论】:

    • 谢谢,它可以工作,我会相信你的边缘情况(在 dtb 的答案中,我对 cme​​ts 的理解有点过分了)。
    • @Benjol:根据您使用的 .NET 版本,您可能还需要显式检查数组,因为 in .NET 2.0 GetInterfaces was broken on array types。 dtb 的特定测试正确...if (type.IsArray) return type.GetElementType();.
    【解决方案2】:

    来自Matt Warren's Blog

    internal static class TypeSystem {
        internal static Type GetElementType(Type seqType) {
            Type ienum = FindIEnumerable(seqType);
            if (ienum == null) return seqType;
            return ienum.GetGenericArguments()[0];
        }
        private static Type FindIEnumerable(Type seqType) {
            if (seqType == null || seqType == typeof(string))
                return null;
            if (seqType.IsArray)
                return typeof(IEnumerable<>).MakeGenericType(seqType.GetElementType());
            if (seqType.IsGenericType) {
                foreach (Type arg in seqType.GetGenericArguments()) {
                    Type ienum = typeof(IEnumerable<>).MakeGenericType(arg);
                    if (ienum.IsAssignableFrom(seqType)) {
                        return ienum;
                    }
                }
            }
            Type[] ifaces = seqType.GetInterfaces();
            if (ifaces != null && ifaces.Length > 0) {
                foreach (Type iface in ifaces) {
                    Type ienum = FindIEnumerable(iface);
                    if (ienum != null) return ienum;
                }
            }
            if (seqType.BaseType != null && seqType.BaseType != typeof(object)) {
                return FindIEnumerable(seqType.BaseType);
            }
            return null;
        }
    }
    

    【讨论】:

    • +1,所有其他答案都犯了您没有的相同错误,即t == typeof(IEnumerable&lt;&gt;)。这永远不会起作用,因为这种类型的实例永远不会存在。
    • @leppie,呃,谈到反射时,谈论类型的实例对我来说有点毛骨悚然。你是说你永远不能实例化IEnumerable&lt;&gt; 类型的对象,或者你永远不能拥有typeof(T) == typeof(IEnumerable&lt;&gt;)——就像typeof(IEnumerable&lt;I don't care right now just tell me if you're IEnumerable&gt;)?
    • @leppie: 仔细看,GetGenericTypeDefinition() 是在比较之前调用的,它会匹配。
    • @dtb:这给Dictionary&lt;object, string&gt;带来了什么?
    • @BenVoigt,给我System.Collections.Generic.KeyValuePair2[System.Object,System.String]`
    【解决方案3】:

    我相信这段代码可以满足您的需求。
    不过,您可能需要稍微清理一下。

    public class TestClass<T>
    {
        public TestClass()
        {
            bool hasStruct = false;
            Type t1 = this.GetType().GetGenericArguments()[0];
            if(t1.IsValueType){
                hasStruct = true;
            }
            if (t1.IsGenericType)
            {
                Type t = t1.GetGenericArguments()[0];
                if (t.IsValueType)
                {
                    hasStruct = true;
                }
            }
    
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-09-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-01
      • 2015-06-25
      相关资源
      最近更新 更多