C# – Verkrijg het itemtype voor een generieke lijst

Wat is de beste manier om het type items te krijgen dat een generieke lijst bevat? Het is gemakkelijk genoeg om het eerste item in de verzameling te pakken en .GetType() aan te roepen, maar ik weet niet altijd zeker of er een item in de verzameling zal zijn.

Ik hoop dat dat logisch is.

Bedankt,
Sonny


Antwoord 1, autoriteit 100%

Je zou het Type.GetGenericArgumentsmethode voor dit doel.

List<Foo> myList = ...
Type myListElementType = myList.GetType().GetGenericArguments().Single();

Antwoord 2, autoriteit 13%

Voor een robuustere aanpak:

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

Maar als uw variabele List<T>wordt getypt, kunt u gewoon typeof(T)gebruiken. Bijvoorbeeld:

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

Houd er rekening mee dat je de parameter someListniet eens nodig hebt. Deze methode is slechts een voorbeeld van hoe u typeofzou kunnen gebruiken als u al een generieke methode gebruikt. U hoeft alleen de reflectiebenadering te gebruiken als u geen toegang heeft tot het T-token (de lijst is opgeslagen in een niet-generiek getypeerde variabele, zoals een getypte IList, object, enz.).


Antwoord 3, autoriteit 8%

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

Antwoord 4, autoriteit 5%

Hier is een andere manier die ook werkt voor niet-generieke collecties:

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

Dat wil zeggen, haal het retourtype foo[x]op, waarbij foovan het opgegeven type is.

Voorbeelden:

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

De GetItemTypemethode hierboven heeft echter een paar problemen:

  • Het genereert een NullReferenceExceptionals het type geen indexeringsoperator heeft.

  • Het genereert een AmbiguousMatchExceptionals het type meerdere overbelastingen heeft voor de indexeringsoperator (bijv. this[string]en this[int]).

Hier is een meer verfijnde versie:

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

Antwoord 5, autoriteit 2%

Hoe zit het hiermee, het is allemaal statisch (bijv. geen instanties vereist) en snel (geen lussen, geen gebruik van linq), en het is eenvoudig 🙂 deze werken voor collecties:

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

En een paar eenvoudige 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());
        }

Merk op dat er twee manieren zijn om hiernaar te kijken, het ene type kan worden geretourneerd door de indexeerder en een ander type kan worden geretourneerd door de enumerator. De eenheidstest laat beide zien.

Veel plezier,
Frans.

P.s. Voor opsommingen:

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

En voor 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;
    }

Antwoord 6, autoriteit 2%

   public Type GetType(IEnumerable<object> resultList)
    {
        return resultList.GetType().GetElementType();
    }

Antwoord 7

Oude vraag nieuwe methode met dynamic

void Foo(){
   Type type GetTypeT(data as dynamic);
}
private static Type GetTypeT<T>(IEnumerable<T> data)
{
    return typeof(T);
}

Antwoord 8

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

Antwoord 9

Hier is een oplossing die ook werkt met afgeleide klassen.

Omdat met deze les:

 public class SubList : List<int>
  {   }

Als u aanroept: subList.GetType().GetGenericArguments().Single()

Het geeft een System.InvalidOperationException

Met deze methode werkt het voor afgeleide klassen:

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

Other episodes