web-dev-qa-db-fra.com

Liste générique C # <T> comment obtenir le type de T?

Je travaille sur un projet de réflexion, et maintenant je suis bloqué. Si j'ai un objet de "myclass" pouvant contenir une liste, est-ce que quelqu'un sait comment obtenir le type comme dans le code ci-dessous si la propriété myclass.SomList est vide?

List<myclass>  myList  =  dataGenerator.getMyClasses();
lbxObjects.ItemsSource = myList; 
lbxObjects.SelectionChanged += lbxObjects_SelectionChanged;

private void lbxObjects_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            Reflect();
        }
Private void Reflect()
{
foreach (PropertyInfo pi in lbxObjects.SelectedItem.GetType().GetProperties())
{
      switch (pi.PropertyType.Name.ToLower())
      {
       case "list`1":
           {           
            // This works if the List<T> contains one or more elements.
            Type tTemp = GetGenericType(pi.GetValue(lbxObjects.SelectedItem, null));

            // but how is it possible to get the Type if the value is null? 
            // I need to be able to create a new object of the type the generic list expect. 
            // Type type = pi.getType?? // how to get the Type of the class inside List<T>?
             break;
           }
      }
}
}
private Type GetGenericType(object obj)
        {
            if (obj != null)
            {
                Type t = obj.GetType();
                if (t.IsGenericType)
                {
                    Type[] at = t.GetGenericArguments();
                    t = at.First<Type>();
                } return t;
            }
            else
            {
                return null;
            }
        }
106
Skvettn
Type type = pi.PropertyType;
if(type.IsGenericType && type.GetGenericTypeDefinition()
        == typeof(List<>))
{
    Type itemType = type.GetGenericArguments()[0]; // use this...
}

Plus généralement, pour soutenir tout IList<T>, vous devez vérifier les interfaces:

foreach (Type interfaceType in type.GetInterfaces())
{
    if (interfaceType.IsGenericType &&
        interfaceType.GetGenericTypeDefinition()
        == typeof(IList<>))
    {
        Type itemType = type.GetGenericArguments()[0];
        // do something...
        break;
    }
}
210
Marc Gravell

Étant donné un objet que je soupçonne être une sorte de IList<>, comment puis-je déterminer de quoi c'est un IList<>?

Voici la solution de courage. Cela suppose que vous avez l'objet à tester (plutôt que Type).

public static Type ListOfWhat(Object list)
{
    return ListOfWhat2((dynamic)list);
}

private static Type ListOfWhat2<T>(IList<T> list)
{
    return typeof(T);
}

Exemple d'utilisation:

object value = new ObservableCollection<DateTime>();
ListOfWhat(value).Dump();

Impressions

typeof(DateTime)
20
Colonel Panic

La réponse de Marc est l'approche que j'utilise pour cela, mais pour des raisons de simplicité (et une API plus conviviale?), Vous pouvez définir une propriété dans la classe de base de la collection si vous en avez une telle que:

public abstract class CollectionBase<T> : IList<T>
{
   ...

   public Type ElementType
   {
      get
      {
         return typeof(T);
      }
   }
}

J'ai trouvé cette approche utile et facile à comprendre pour tout nouveau venu dans le domaine des génériques.

9
GaryJL

Étant donné un objet que je soupçonne être une sorte de IList<>, comment puis-je déterminer de quoi c'est un IList<>?

Voici une solution fiable. Mes excuses pour la longueur - l’API d’introspection de C # rend cela étonnamment difficile.

/// <summary>
/// Test if a type implements IList of T, and if so, determine T.
/// </summary>
public static bool TryListOfWhat(Type type, out Type innerType)
{
    Contract.Requires(type != null);

    var interfaceTest = new Func<Type, Type>(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IList<>) ? i.GetGenericArguments().Single() : null);

    innerType = interfaceTest(type);
    if (innerType != null)
    {
        return true;
    }

    foreach (var i in type.GetInterfaces())
    {
        innerType = interfaceTest(i);
        if (innerType != null)
        {
            return true;
        }
    }

    return false;
}

Exemple d'utilisation:

    object value = new ObservableCollection<int>();
Type innerType;
TryListOfWhat(value.GetType(), out innerType).Dump();
innerType.Dump();

Résultats

True
typeof(Int32)
7
Colonel Panic