Como obter o tipo de T de um membro de uma classe ou método genérico?
public class Foo<T>
{
public List<T> Bar { get; set; }
public void Baz()
{
// get type of T
}
}
Quando eu instanciar a classe, A T
torna-se MyTypeObject1
, por isso a classe tem uma propriedade genérica da lista: List<MyTypeObject1>
. O mesmo se aplica a um método genérico numa classe não-genérica:
public class Foo
{
public void Bar<T>()
{
var baz = new List<T>();
// get type of T
}
}
Eu gostaria de saber que tipo de objetos a lista da minha classe contém. Então a propriedade da lista chamada Bar
ou a variável local baz
, contém Que tipo de T
?
não posso fazer Bar[0].GetType()
, porque a lista pode conter zero elementos. Como posso fazê-lo?
16 answers
Se bem entendi, a sua lista tem o mesmo tipo de parâmetro que a própria classe do contentor. Se for esse o caso, então:
Type typeParameterType = typeof(T);
Se você está na situação de sorte de ter object
como parâmetro de tipo, Veja a resposta de Marc .
(Nota: presumo que tudo o que sabe é object
ou IList
ou similar, e que a lista pode ser qualquer tipo no tempo de execução) {[[8]}
Se sabes que é um List<T>
, 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, pode escapar sem reflexão:
public static Type GetListType<T>(this List<T> _)
{
return typeof(T);
}
Ou mais gerais:
public static Type GetEnumeratedType<T>(this IEnumerable<T> _)
{
return typeof(T);
}
Utilização:
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
Tenta
list.GetType().GetGenericArguments()
IEnumerable myEnum = myList as IEnumerable;
Type entryType = myEnum.AsQueryable().ElementType;
Considere isto.: Uso-o para exportar 20 listas dactilografadas da mesma forma:
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);
}
}
public string ListType<T>(T value){
var valueType = value.GetType().GenericTypeArguments[0].FullName;
return value;
}
Você pode usar este para reler o tipo de lista genérica.
Se você não precisa de toda a variável tipo e só quer verificar o tipo que você pode facilmente criar uma variável temp e usar é o operador.
T checkType = default(T);
if (checkType is MyClass)
{}
O método GetGenericArgument()
tem de ser definido no tipo de base da sua instância.
(cuja classe é uma classe genérica myClass<T>
). Caso contrário, devolve um tipo[0]
Exemplo:
Myclass<T> instance = new Myclass<T>();
Type[] listTypes = typeof(instance).BaseType.GetGenericArguments();
Pode obter o tipo de " T " de qualquer tipo de colecção que implemente Ienumerável
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;
}
Note que não suporta tipos de colecção que implementam Ienumeráveis duas vezes, por exemplo
public class WierdCustomType : IEnumerable<int>, IEnumerable<string> { ... }
Suponho que você poderia retornar um conjunto de tipos se você precisasse suportar isto...
Além disso, você também pode querer cache o resultado por tipo de coleção Se você está fazendo isso muito (por exemplo, em um loop).
Uso este método de extensão para conseguir 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;
}
Usa-o assim:
[TestMethod]
public void GetFriendlyTypeName_ShouldHandleReallyComplexTypes()
{
typeof(Dictionary<string, Dictionary<string, object>>).GetFriendlyTypeName()
.ShouldEqual("Dictionary<String, Dictionary<String, Object>>");
}
Isto não é bem o que procuras, mas ajuda a demonstrar as técnicas envolvidas.
Usando a solução 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();
public bool IsCollection<T>(T value){
var valueType = value.GetType();
return valueType.IsArray() || typeof(IEnumerable<object>).IsAssignableFrom(valueType) || typeof(IEnumerable<T>).IsAssignableFrom(valuetype);
}
Se quer saber o tipo subjacente de uma propriedade, tente isto:
propInfo.PropertyType.UnderlyingSystemType.GenericTypeArguments[0]
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 chama-lhe assim.
var item = Activator.CreateInstance(iListType.GetElementType());
Ou
var item = Activator.CreateInstance(Bar.GetType().GetElementType());
Tipo:
type = list.AsEnumerable().SingleOrDefault().GetType();