webentwicklung-frage-antwort-db.com.de

C # - Rufen Sie den Elementtyp für eine generische Liste ab

Was wäre der beste Weg, um die Art von Elementen zu erhalten, die eine generische Liste enthält? Es ist leicht genug, das erste Element in der Auflistung zu packen und .GetType () aufzurufen, aber ich kann nicht immer sicher sein, dass sich ein Element in der Auflistung befindet.

Hoffe das macht Sinn.

Vielen Dank,
Sonny

29
Sonny Boy

Sie können dazu die Methode Type.GetGenericArguments verwenden.

List<Foo> myList = ...

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

Für einen robusteren Ansatz:

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("someList", "Type must be List<>, but was " + type.FullName);

    return type.GetGenericArguments()[0];
}

Wenn Ihre Variable List<T> eingegeben wird, können Sie typeof(T) verwenden. Zum Beispiel:

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

Beachten Sie, dass Sie den Parameter someList nicht einmal benötigen. Diese Methode ist nur ein Beispiel dafür, wie Sie typeof verwenden könnten, wenn Sie bereits in einer generischen Methode sind. Sie müssen den Reflection-Ansatz nur verwenden, wenn Sie keinen Zugriff auf das Token T haben (die Liste wird in einer nicht generisch typisierten Variablen gespeichert, z. B. eine typisierte Variable IList, object usw.).

7
cdhowie
list.GetType().GetGenericArguments()[0]
5
Mehrdad

Hier ist ein anderer Weg, der auch für nicht generische Sammlungen funktioniert:

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

Rufen Sie also den Rückgabetyp von foo[x] ab, wobei foo vom angegebenen Typ ist.

Beispiele:

// 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)));

Die GetItemType-Methode oben hat jedoch einige Probleme:

  • Es gibt eine NullReferenceException, wenn der Typ keinen Indexierungsoperator hat.

  • Es gibt ein AmbiguousMatchException aus, wenn der Typ mehrere Überladungen für den Indexierungsoperator hat (z. B. this[string] und this[int]).

Hier ist eine verfeinerte 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];
}
4
Joey Adams

Was ist damit, es ist alles statisch (z. B. keine Instanzen erforderlich) und schnell (keine Schleifen, keine Verwendung von 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;
    }

Und ein paar einfache 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());
        }

Beachten Sie die Tatsache, dass es zwei Möglichkeiten gibt, dies zu betrachten. Möglicherweise wird ein Typ vom Indexer und ein anderer Typ vom Enumerator zurückgegeben. Der Unit-Test zeigt beides.

Viel Spaß ... Frans.

P.s. Für Aufzählungszeichen:

    [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;
    }

Und für den 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;
    }
1
FdW
    public Type GetType(IEnumerable<object> resultList)
    {
        return resultList.GetType().GetElementType();
    }
0
joyce

Alte Frage neue Methode mit dynamic

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

private static Type GetTypeT<T>(IEnumerable<T> data)
{
    return typeof(T);
}
0
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
0
toddmo