it-swarm.com.de

Wie bekomme ich den Typ von T von einem Member einer generischen Klasse oder Methode?

Angenommen, ich habe ein generisches Mitglied in einer Klasse oder Methode, also:

public class Foo<T>
{
    public List<T> Bar { get; set; }

    public void Baz()
    {
        // get type of T
    }   
}

Wenn ich die Klasse instanziiere, wird T zu MyTypeObject1, sodass die Klasse über eine generische Listeneigenschaft verfügt: List<MyTypeObject1>. Gleiches gilt für eine generische Methode in einer nicht generischen Klasse:

public class Foo
{
    public void Bar<T>()
    {
        var baz = new List<T>();

        // get type of T
    }
}

Ich würde gerne wissen, welche Art von Objekten die Liste meiner Klasse enthält. Die Listeneigenschaft Bar oder die lokale Variable baz enthält also welchen Typ von T

Ich kann Bar[0].GetType() nicht ausführen, da die Liste möglicherweise null Elemente enthält. Wie kann ich es tun?

593

Wenn ich es richtig verstanden habe, hat Ihre Liste den gleichen Typparameter wie die Containerklasse selbst. Wenn dies der Fall ist, dann:

Type typeParameterType = typeof(T);

Wenn Sie sich in der glücklichen Situation befinden, object als Typparameter zu verwenden, lesen Sie die Antwort von Marc .

594
Tamas Czinege

(Anmerkung: Ich gehe davon aus, dass alles, was Sie wissen, object oder IList oder ähnlich ist und dass die Liste zur Laufzeit einen beliebigen Typ haben kann.

Wenn Sie wissen, dass es sich um einen List<T> handelt, dann:

Type type = abc.GetType().GetGenericArguments()[0];

Eine andere Möglichkeit ist, sich den Indexer anzusehen:

Type type = abc.GetType().GetProperty("Item").PropertyType;

Neue TypeInfo verwenden:

using System.Reflection;
// ...
var type = abc.GetType().GetTypeInfo().GenericTypeArguments[0];
484
Marc Gravell

Mit der folgenden Erweiterungsmethode können Sie ungestört davonkommen:

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

Oder allgemeiner:

public static Type GetEnumeratedType<T>(this IEnumerable<T> _)
{
    return typeof(T);
}

Verwendungszweck:

List<string>        list    = new List<string> { "a", "b", "c" };
IEnumerable<string> strings = list;
IEnumerable<object> objects = list;

Type listType    = list.GetListType();           // string
Type stringsType = strings.GetEnumeratedType();  // string
Type objectsType = objects.GetEnumeratedType();  // BEWARE: object
43
3dGrabber

Versuchen

list.GetType().GetGenericArguments()
29
Rauhotz

Das ist Arbeit für mich. Wo meine Liste eine unbekannte Art von Liste ist.

IEnumerable myEnum = myList as IEnumerable;
Type entryType = myEnum.AsQueryable().ElementType;
13

Betrachten Sie folgendes: Ich verwende es, um 20 eingegebene Listen auf dieselbe Weise zu exportieren:

private void Generate<T>()
{
    T item = (T)Activator.CreateInstance(typeof(T));

    ((T)item as DemomigrItemList).Initialize();

    Type type = ((T)item as DemomigrItemList).AsEnumerable().FirstOrDefault().GetType();
    if (type == null) return;
    if (type != typeof(account)) //account is listitem in List<account>
    {
        ((T)item as DemomigrItemList).CreateCSV(type);
    }
}
9
Ferenc Mucsi

Wenn Sie nicht die gesamte Typvariable benötigen und nur den Typ überprüfen möchten, können Sie einfach eine temporäre Variable erstellen und den Operator operator verwenden.

T checkType = default(T);

if (checkType is MyClass)
{}
9
Sebi

Sie können diese für den Rückgabetyp der generischen Liste verwenden:

public string ListType<T>(T value)
{
    var valueType = value.GetType().GenericTypeArguments[0].FullName;
    return valueType;
}
8

Die GetGenericArgument()-Methode muss auf den Basistyp Ihrer Instanz festgelegt werden (Deren Klasse eine generische Klasse myClass<T> ist). Andernfalls wird ein Typ [0] zurückgegeben.

Beispiel:

Myclass<T> instance = new Myclass<T>();
Type[] listTypes = typeof(instance).BaseType.GetGenericArguments();
5
Thomas

Ich verwende diese Erweiterungsmethode, um etwas Ähnliches zu erreichen:

public static string GetFriendlyTypeName(this Type t)
{
    var typeName = t.Name.StripStartingWith("`");
    var genericArgs = t.GetGenericArguments();
    if (genericArgs.Length > 0)
    {
        typeName += "<";
        foreach (var genericArg in genericArgs)
        {
            typeName += genericArg.GetFriendlyTypeName() + ", ";
        }
        typeName = typeName.TrimEnd(',', ' ') + ">";
    }
    return typeName;
}

public static string StripStartingWith(this string s, string stripAfter)
{
    if (s == null)
    {
        return null;
    }
    var indexOf = s.IndexOf(stripAfter, StringComparison.Ordinal);
    if (indexOf > -1)
    {
        return s.Substring(0, indexOf);
    }
    return s;
}

Du verwendest es so:

[TestMethod]
public void GetFriendlyTypeName_ShouldHandleReallyComplexTypes()
{
    typeof(Dictionary<string, Dictionary<string, object>>).GetFriendlyTypeName()
        .ShouldEqual("Dictionary<String, Dictionary<String, Object>>");
}

Das ist nicht genau das, wonach Sie suchen, aber es ist hilfreich, um die verwendeten Techniken zu demonstrieren. 

4
Ken Smith

Sie können den Typ "T" von jedem Auflistungstyp abrufen, der IEnumerable <T> mit folgendem Code implementiert:

public static Type GetCollectionItemType(Type collectionType)
{
    var types = collectionType.GetInterfaces()
        .Where(x => x.IsGenericType 
            && x.GetGenericTypeDefinition() == typeof(IEnumerable<>))
        .ToArray();
    // Only support collections that implement IEnumerable<T> once.
    return types.Length == 1 ? types[0].GetGenericArguments()[0] : null;
}

Beachten Sie, dass es keine Auflistungstypen unterstützt, die IEnumerable <T> zweimal implementieren, z. 

public class WierdCustomType : IEnumerable<int>, IEnumerable<string> { ... }

Ich nehme an, Sie könnten ein Array von Typen zurückgeben, wenn Sie dies unterstützen müssten ...

Wenn Sie dies häufig tun (z. B. in einer Schleife), möchten Sie möglicherweise auch das Ergebnis pro Erfassungstyp zwischenspeichern.

4
Dan Malcolm

Verwenden der 3dGrabber-Lösung:

public static T GetEnumeratedType<T>(this IEnumerable<T> _)
{
    return default(T);
}

//and now 

var list = new Dictionary<string, int>();
var stronglyTypedVar = list.GetEnumeratedType();
1
fantastory
public bool IsCollection<T>(T value){
  var valueType = value.GetType();
  return valueType.IsArray() || typeof(IEnumerable<object>).IsAssignableFrom(valueType) || typeof(IEnumerable<T>).IsAssignableFrom(valuetype);
}
1
Karanvir Kang

So habe ich es gemacht 

internal static Type GetElementType(this Type type)
{
        //use type.GenericTypeArguments if exist 
        if (type.GenericTypeArguments.Any())
         return type.GenericTypeArguments.First();

         return type.GetRuntimeProperty("Item").PropertyType);
}

Dann nenne es so 

var item = Activator.CreateInstance(iListType.GetElementType());

OR

var item = Activator.CreateInstance(Bar.GetType().GetElementType());
0
Alen.Toma

Wenn Sie den zugrunde liegenden Typ einer Eigenschaft erfahren möchten, versuchen Sie Folgendes:

propInfo.PropertyType.UnderlyingSystemType.GenericTypeArguments[0]
0
Fatih Çelik

Für Entwickler, die mit wörtlich mit Typnamen umgehen möchten, beispielsweise um eine switch-Anweisung zu verwenden, ist hier ein Beispiel:

    public static void TypeBasedLogic<T>(T item)
    {
        switch (typeof(T).ToString()) //e.g. System.Int32
        {
            case nameof(System) + "." + nameof(Int32):
                //Logic for int
                Console.Write("It's an integer");
            break;

            case nameof(System) + "." + nameof(Double):
                //Logic for double
                Console.Write("It's a double");
            break;

            case nameof(System) + "." + nameof(Decimal):
                //Logic for decimal
                Console.Write("It's a decimal");
            break;

            case nameof(System) + "." + nameof(String):
                //Logic for string
                Console.Write("It's a string");
            break;

            default:
                //logic for the rest other System or custom types
                Console.Write("It's a "+ typeof(T).ToString());
            break;

        }
    }

verwendungszweck:

TypeBasedLogic(5); // outputs: It's an integer
0
Shadi Namrouti