C#泛型列表<T>如何获取T的类型? [复制]

Posted

技术标签:

【中文标题】C#泛型列表<T>如何获取T的类型? [复制]【英文标题】:C# generic list <T> how to get the type of T? [duplicate] 【发布时间】:2009-06-25 12:57:39 【问题描述】:

我正在做一个反射项目,现在我卡住了。

如果我有一个myclass 的对象可以保存List&lt;SomeClass&gt;,如果属性myclass.SomList 为空,有谁知道如何获取下面代码中的类型?

List<myclass> myList = dataGenerator.getMyClasses();
lbxObjects.ItemsSource = myList; 
lbxObjects.SelectionChanged += lbxObjects_SelectionChanged;

private void lbxObjects_SelectionChanged(object sender, SelectionChangedEventArgs e)

    Reflect();


Private void Reflect()

    foreach (PropertyInfo pi in lbxObjects.SelectedItem.GetType().GetProperties())
    
        switch (pi.PropertyType.Name.ToLower())
        
            case "list`1":
                       
                // This works if the List<T> contains one or more elements.
                Type tTemp = GetGenericType(pi.GetValue(lbxObjects.SelectedItem, null));

                // but how is it possible to get the Type if the value is null? 
                // I need to be able to create a new object of the type the generic list expect. 
                // Type type = pi.getType?? // how to get the Type of the class inside List<T>?
                break;
            
        
    


private Type GetGenericType(object obj)

    if (obj != null)
    
        Type t = obj.GetType();
        if (t.IsGenericType)
        
            Type[] at = t.GetGenericArguments();
            t = at.First<Type>();
         
        return t;
    
    else
    
        return null;
    

【问题讨论】:

【参考方案1】:
Type type = pi.PropertyType;
if(type.IsGenericType && type.GetGenericTypeDefinition()
        == typeof(List<>))

    Type itemType = type.GetGenericArguments()[0]; // use this...


更一般地说,要支持任何IList&lt;T&gt;,您需要检查接口:

foreach (Type interfaceType in type.GetInterfaces())

    if (interfaceType.IsGenericType &&
        interfaceType.GetGenericTypeDefinition()
        == typeof(IList<>))
    
        Type itemType = type.GetGenericArguments()[0];
        // do something...
        break;
    

【讨论】:

不应该是Type itemType = interfaceType.GetGenericArguments()[0]; 有趣的是,第二个例子失败了,比如IList&lt;int&gt;。修复以下***.com/a/13608408/284795 我知道答案很老了,但我尝试理解以下内容:'GetGenericArguments()[0];'为什么有0? Type[] 中是否总是只有一项? 因为调用 GetGenericArguments() 返回一个数组。 msdn.microsoft.com/en-us/library/… List 只有一种类型。例如,一个字典会有两个。【参考方案2】:

给定一个我怀疑是某种IList&lt;&gt; 的对象,我如何确定什么它是IList&lt;&gt;

这是大胆的解决方案。它假定您有要测试的实际对象(而不是 Type)。

public static Type ListOfWhat(Object list)

    return ListOfWhat2((dynamic)list);


private static Type ListOfWhat2<T>(IList<T> list)

    return typeof(T);

示例用法:

object value = new ObservableCollection<DateTime>();
ListOfWhat(value).Dump();

打印

typeof(DateTime)

【讨论】:

-1:为什么是IList&lt;T&gt; 而不是IEnumerable&lt;T&gt;?为什么dynamic 我误解了 OP 的问题吗?细节不清楚,所以我回答了标题中的问题。 你先生,是个巫师!我一直在努力解决具有通用数据结构(可以处理单一类型和列表)的动态解析器​​的问题,this 让我走上了正轨。 “动态”用法的好例子【参考方案3】:

Marc 的回答是我为此使用的方法,但为了简单起见(以及更友好的 API?),如果您有这样的属性,您可以在集合基类中定义一个属性:

public abstract class CollectionBase<T> : IList<T>

   ...

   public Type ElementType
   
      get
      
         return typeof(T);
      
   

我发现这种方法很有用,而且对于任何刚接触泛型的人来说都很容易理解。

【讨论】:

我想使用这种方法,但后来我意识到我必须拥有列表实例才能确定元素类型,但我并不总是拥有。 您可以将属性设为静态。像“public static Type ElementType”......然后你得到它作为“var t = CollectionBase.ElementType;” ...您将不需要实例变量 是的。静态允许您在没有现有对象的情况下使用类。我发现这种方法更容易使用。当然,你需要在你的对象中存储额外的信息,但至少你可以避免在批准的答案中进行这种级联调用。【参考方案4】:

给定一个我怀疑是某种IList&lt;&gt; 的对象,我如何确定什么它是IList&lt;&gt;

这是一个可靠的解决方案。抱歉,C# 的自省 API 让这变得异常困难。

/// <summary>
/// Test if a type implements IList of T, and if so, determine T.
/// </summary>
public static bool TryListOfWhat(Type type, out Type innerType)

    Contract.Requires(type != null);

    var interfaceTest = new Func<Type, Type>(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IList<>) ? i.GetGenericArguments().Single() : null);

    innerType = interfaceTest(type);
    if (innerType != null)
    
        return true;
    

    foreach (var i in type.GetInterfaces())
    
        innerType = interfaceTest(i);
        if (innerType != null)
        
            return true;
        
    

    return false;

示例用法:

    object value = new ObservableCollection<int>();
Type innerType;
TryListOfWhat(value.GetType(), out innerType).Dump();
innerType.Dump();

返回

True
typeof(Int32)

【讨论】:

我没有看到任何其他结果作为 Marcs 方法(也使用 marcs 我得到 Int32)

以上是关于C#泛型列表<T>如何获取T的类型? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

C#如何将类型Type作为泛型T的参数T传递

C# 如何获取泛型集合 的数据

c# 在不知道类型的情况下,如何判断并使用带泛型的扩展方法?

C#实体类中如何定义泛型集合类型的属性

C#关于反射创建泛型类

C#中的泛型和泛型集合