【问题标题】:C# generic list <T> how to get the type of T? [duplicate]C#泛型列表<T>如何获取T的类型? [复制]
【发布时间】: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;
    }
}

【问题讨论】:

    标签: c# reflection generic-list


    【解决方案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;。修复以下stackoverflow.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)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-24
    • 2023-03-06
    • 2012-11-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多