简体   繁体   English

C# - 获取通用列表的项目类型

[英]C# - Get the item type for a generic list

What would be the best way of getting the type of items a generic list contains?获取通用列表包含的项目类型的最佳方法是什么? It's easy enough to grab the first item in the collection and call .GetType(), but I can't always be sure there will be an item in the collection.获取集合中的第一个项目并调用 .GetType() 很容易,但我不能总是确定集合中会有一个项目。

Hope that makes sense.希望这是有道理的。

Thanks,谢谢,
Sonny桑尼

You could use the Type.GetGenericArguments method for this purpose.为此,您可以使用Type.GetGenericArguments方法。

List<Foo> myList = ...

Type myListElementType = myList.GetType().GetGenericArguments().Single();

For a more robust approach:对于更强大的方法:

public static Type GetListType(object someList)
{
    if (someList == null)
        throw new ArgumentNullException("someList");

    var type = someList.GetType();

    if (!type.IsGenericType || type.GetGenericTypeDefinition() != typeof(List<>))
        throw new ArgumentException("Type must be List<>, but was " + type.FullName, "someList");

    return type.GetGenericArguments()[0];
}

But if your variable is typed List<T> then you can just use typeof(T) .但是如果你的变量类型是List<T>那么你可以使用typeof(T) For example:例如:

public static Type GetListType<T>(List<T> someList)
{
    return typeof(T);
}

Note that you don't really even need the someList parameter.请注意,您甚至不需要someList参数。 This method is just an example for how you could use typeof if you are already in a generic method.如果您已经在通用方法中,此方法只是一个如何使用typeof的示例。 You only need to use the reflection approach if you don't have access to the T token (the list is stored in a non-generic-typed variable, such as one typed IList , object , etc.).如果您无权访问T令牌(列表存储在非泛型类型变量中,例如一个类型化的IListobject等),则只需要使用反射方法。

list.GetType().GetGenericArguments()[0]

Here's another way which works for non-generic collections, too:这是另一种适用于非通用集合的方法:

static Type GetItemType(Type collectionType)
{
    return collectionType.GetMethod("get_Item").ReturnType;
}

That is, get the return type of foo[x] , where foo is of the specified type.即获取foo[x]的返回类型,其中foo是指定类型。

Examples:例子:

// Generic type; prints System.Int32
Console.WriteLine(GetItemType(typeof(List<int>)));

// Non-generic type; prints System.String
Console.WriteLine(GetItemType(typeof(System.Collections.Specialized.StringCollection)));

The GetItemType method above has a couple issues, though: GetItemType上面的GetItemType方法有几个问题:

  • It throws a NullReferenceException if the type has no indexing operator.如果类型没有索引运算符,它会抛出NullReferenceException

  • It throws an AmbiguousMatchException if the type has multiple overloads for the indexing operator (eg this[string] and this[int] ).如果该类型具有索引运算符的多个重载(例如this[string]this[int] ),它将抛出AmbiguousMatchException

Here is a more refined version:这是一个更精致的版本:

public static Type GetItemType(this Type collectionType)
{
    var types =
        (from method in collectionType.GetMethods()
         where method.Name == "get_Item"
         select method.ReturnType
        ).Distinct().ToArray();
    if (types.Length == 0)
        return null;
    if (types.Length != 1)
        throw new Exception(string.Format("{0} has multiple item types", collectionType.FullName));
    return types[0];
}

What about this, its all static (eg no instances required), and fast (no loops, no usage of linq), and it is simple :) these work for collections:怎么样,它都是静态的(例如不需要实例)和快速(没有循环,没有使用 linq),而且很简单 :) 这些适用于集合:

    [System.Diagnostics.DebuggerHidden]
    public static Type GetIndexedType(this ICollection poICollection)
    {
        PropertyInfo oPropertyInfo = poICollection == null ? null : poICollection.GetType().GetProperty("Item");
        return oPropertyInfo == null ? null : oPropertyInfo.PropertyType;
    }

    [System.Diagnostics.DebuggerHidden]
    public static Type GetEnumeratedType(this ICollection poICollection)
    {
        PropertyInfo oPropertyInfo = poICollection == null ? null : poICollection.GetType().GetMethod("GetEnumerator").ReturnType.GetProperty("Current");
        return oPropertyInfo == null ? null : oPropertyInfo.PropertyType;
    }

And a few simple unit tests:以及一些简单的单元测试:

        [Test]
        public void GetIndexedType()
        {
            Assert.AreEqual(null, ((ICollection)null).GetIndexedType());
            Assert.AreEqual(typeof(int), (new List<int>()).GetIndexedType());
            Assert.AreEqual(typeof(bool), (new SortedList<string, bool>()).GetIndexedType());
        }

        [Test]
        public void GetEnumeratedType()
        {
            Assert.AreEqual(null, ((ICollection)null).GetEnumeratedType());
            Assert.AreEqual(typeof(int), (new List<int>()).GetEnumeratedType());
            Assert.AreEqual(typeof(KeyValuePair<string, bool>), (new SortedList<string, bool>()).GetEnumeratedType());
        }

Notice the fact that there are two ways to look at this, one type may be returned by the indexer and an other type may be returned by the enumerator.请注意,有两种方法可以查看这一点,一种类型可能由索引器返回,另一种类型可能由枚举器返回。 The unit test do show both.单元测试确实显示了两者。

Have fun, Frans.玩得开心,弗兰斯。

Ps For enumerables: Ps 对于枚举:

    [System.Diagnostics.DebuggerHidden]
    public static Type GetEnumeratedType(this System.Collections.IEnumerable poIEnumerable)
    {
        PropertyInfo oPropertyInfo = poIEnumerable == null ? null : poIEnumerable.GetType().GetMethod("GetEnumerator").ReturnType.GetProperty("Current");
        return oPropertyInfo == null ? null : oPropertyInfo.PropertyType;
    }

And for enumerator:对于枚举器:

    [System.Diagnostics.DebuggerHidden]
    public static Type GetEnumeratedType(this System.Collections.IEnumerator poIEnumerator)
    {
        PropertyInfo oPropertyInfo = poIEnumerator == null ? null : poIEnumerator.GetType().GetProperty("Current");
        return oPropertyInfo == null ? null : oPropertyInfo.PropertyType;
    }
    public Type GetType(IEnumerable<object> resultList)
    {
        return resultList.GetType().GetElementType();
    }

Old question new method with dynamic老问题新方法dynamic

void Foo(){
   Type type GetTypeT(data as dynamic);
}

private static Type GetTypeT<T>(IEnumerable<T> data)
{
    return typeof(T);
}

Here is a solution that also works with derived classes.这是一个也适用于派生类的解决方案。

Because with this class :因为有了这个类:

  public class SubList : List<int>
  {   }

If you call : subList.GetType().GetGenericArguments().Single()如果您调用: subList.GetType().GetGenericArguments().Single()

It will throws a System.InvalidOperationException它会抛出一个System.InvalidOperationException

With this method it works for derived classes :使用这种方法,它适用于派生类:

public Type GetListItemType<T>(List<T> list)
{
  Type type = list.GetType();
  while (type != typeof(List<T>))
    type = type.BaseType;
  return type.GetGenericArguments().Single();
}


var list = new List<int>();
var subList = new SubList();
Console.WriteLine(GetListItemType(list)); // System.Int32
Console.WriteLine(GetListItemType(subList)); // System.Int32
Public Shared Function ListItemType(ListType As System.Type) As System.Type

  If Not ListType.IsGenericType Then
    If ListType.BaseType IsNot Nothing AndAlso ListType.BaseType.IsGenericType Then
      Return ListItemType(ListType.BaseType)
    End If
  Else
    Return ListType.GetGenericArguments.Single
  End If
End Function

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM