Como obter o tipo de T de um membro de uma class ou método genérico?

Vamos dizer que eu tenho um membro genérico em uma class ou método, então:

public class Foo { public List Bar { get; set; } public void Baz() { // get type of T } } 

Quando eu instancio a class, o T se torna MyTypeObject1 , então a class tem uma propriedade de lista genérica: List . O mesmo se aplica a um método genérico em uma class não genérica:

 public class Foo { public void Bar() { var baz = new List(); // get type of T } } 

Gostaria de saber que tipo de objects contém a lista da minha turma. Então a propriedade list chamada Bar ou a variável local baz , contém que tipo de T ?

Eu não consigo fazer Bar[0].GetType() , porque a lista pode conter zero elementos. Como eu posso fazer isso?

Se bem entendi, sua lista tem o mesmo parâmetro de tipo que a própria class de contêiner. Se este for o caso, então:

 Type typeParameterType = typeof(T); 

Se você estiver na situação de sorte de ter o object como um parâmetro de tipo, veja a resposta de Marc .

(nota: estou assumindo que tudo que você sabe é object ou IList ou similar, e que a lista pode ser qualquer tipo em tempo de execução)

Se você sabe que é uma List , então:

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

Outra opção é olhar para o indexador:

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

Usando o novo TypeInfo:

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

Com o seguinte método de extensão, você pode sair sem refletir:

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

Ou mais geral:

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

Uso:

 List list = new List { "a", "b", "c" }; IEnumerable strings = list; IEnumerable objects = list; Type listType = list.GetListType(); // string Type stringsType = strings.GetEnumeratedType(); // string Type objectsType = objects.GetEnumeratedType(); // BEWARE: object 

Experimentar

 list.GetType().GetGenericArguments() 

Isso é trabalho para mim. Onde myList é algum tipo desconhecido de lista.

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

Considere isto: eu uso-o para exportar 20 listas digitadas da mesma maneira:

 private void Generate() { 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 { ((T)item as DemomigrItemList).CreateCSV(type); } } 

Se você não precisa da variável Type inteira e apenas deseja verificar o tipo, você pode facilmente criar uma variável temp e usar o operador is.

 T checkType = default(T); if (checkType is MyClass) {} 

O método GetGenericArgument() deve ser configurado no tipo base da sua instância (cuja class é uma class genérica myClass ). Caso contrário, retorna um tipo [0]

Exemplo:

 Myclass instance = new Myclass(); Type[] listTypes = typeof(instance).BaseType.GetGenericArguments(); 
 public string ListType(T value){ var valueType = value.GetType().GenericTypeArguments[0].FullName; return value; } 

Você pode usar este para executar novamente o tipo de lista genérica.

Você pode obter o tipo de “T” de qualquer tipo de coleção que implementa IEnumerable com o seguinte:

 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 once. return types.Length == 1 ? types[0].GetGenericArguments()[0] : null; } 

Observe que ele não suporta tipos de coleção que implementam IEnumerable duas vezes, por exemplo

 public class WierdCustomType : IEnumerable, IEnumerable { ... } 

Eu suponho que você poderia retornar um array de tipos se você precisasse suportar isso …

Além disso, você também pode querer armazenar em cache o resultado por tipo de coleção se estiver fazendo muito isso (por exemplo, em um loop).

Eu uso esse método de extensão para realizar algo semelhante:

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

Você usa assim:

 [TestMethod] public void GetFriendlyTypeName_ShouldHandleReallyComplexTypes() { typeof(Dictionary>).GetFriendlyTypeName() .ShouldEqual("Dictionary>"); } 

Isso não é exatamente o que você está procurando, mas é útil para demonstrar as técnicas envolvidas.

Usando a solução do 3dGrabber:

 public static T GetEnumeratedType(this IEnumerable _) { return default(T); } //and now var list = new Dictionary(); var stronglyTypedVar = list.GetEnumeratedType(); 
 public bool IsCollection(T value){ var valueType = value.GetType(); return valueType.IsArray() || typeof(IEnumerable).IsAssignableFrom(valueType) || typeof(IEnumerable).IsAssignableFrom(valuetype); } 

Se você quiser saber o tipo subjacente de uma propriedade, tente isto:

 propInfo.PropertyType.UnderlyingSystemType.GenericTypeArguments[0] 

É assim que eu fiz

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

Então ligue assim

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

OU

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

Tipo:

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