c# créer - Comment obtenir le type de T d'un membre d'une classe ou d'une méthode générique?




orienté parcourir (14)

Disons que j'ai un membre générique dans une classe ou une méthode, donc:

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

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

Lorsque j'instancie la classe, le T devient MyTypeObject1 , donc la classe a une propriété de liste générique: List<MyTypeObject1> . La même chose s'applique à une méthode générique dans une classe non générique:

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

        // get type of T
    }
}

Je voudrais savoir, quel type d'objets contient la liste de ma classe. Donc la propriété list appelée Bar ou la variable locale baz , contient quel type de T ?

Je ne peux pas faire Bar[0].GetType() , car la liste peut contenir zéro élément. Comment puis-je le faire?


Answers

public bool IsCollection<T>(T value){
  var valueType = value.GetType();
  return valueType.IsArray() || typeof(IEnumerable<object>).IsAssignableFrom(valueType) || typeof(IEnumerable<T>).IsAssignableFrom(valuetype);
}

La méthode GetGenericArgument() doit être définie sur le type de base de votre instance (dont la classe est une classe générique myClass<T> ). Sinon, il renvoie un type [0]

Exemple:

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

J'utilise cette méthode d'extension pour accomplir quelque chose de similaire:

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

Vous l'utilisez comme ceci:

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

Ce n'est pas tout à fait ce que vous cherchez, mais c'est utile pour démontrer les techniques impliquées.


Avec la méthode d'extension suivante, vous pouvez vous échapper sans réfléchir:

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

Ou plus général:

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

Usage:

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

Vous pouvez obtenir le type "T" de n'importe quel type de collection qui implémente IEnumerable <T> avec ce qui suit:

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

Notez qu'il ne prend pas en charge les types de collection qui implémentent IEnumerable <T> deux fois, par exemple

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

Je suppose que vous pourriez retourner un tableau de types si vous avez besoin de soutenir cela ...

En outre, vous pouvez également mettre en cache le résultat par type de collection si vous le faites souvent (par exemple, en boucle).


Si vous voulez connaître le type sous-jacent d'une propriété, essayez ceci:

propInfo.PropertyType.UnderlyingSystemType.GenericTypeArguments[0]

C'est comme ça que je l'ai fait

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

Alors appelez comme ça

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

OU

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

Si vous n'avez pas besoin de la variable Type entière et que vous voulez simplement vérifier le type, vous pouvez facilement créer une variable temp et utiliser l'opérateur.

T checkType = default(T);

if (checkType is MyClass)
{}

Type:

type = list.AsEnumerable().SingleOrDefault().GetType();

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

Vous pouvez utiliser celui-ci pour réexécuter le type de liste générique.


Essayer

list.GetType().GetGenericArguments()

C'est un travail pour moi. Où myList est une sorte de liste inconnue.

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

En utilisant la solution de 3dGrabber:

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

//and now 

var list = new Dictionary<string, int>();
var stronglyTypedVar = list.GetEnumeratedType();

Random r = new Random();
int n = r.Next();




c# .net generics