¿Cómo obtener el tipo de T de un miembro de una clase o método genérico?
Frecuentes
Visto 686,731 equipos
722
Digamos que tengo un miembro genérico en una clase o método, entonces:
public class Foo<T>
{
public List<T> Bar { get; set; }
public void Baz()
{
// get type of T
}
}
Cuando instancia la clase, el T
se convierte en MyTypeObject1
, por lo que la clase tiene una propiedad de lista genérica: List<MyTypeObject1>
. Lo mismo se aplica a un método genérico en una clase no genérica:
public class Foo
{
public void Bar<T>()
{
var baz = new List<T>();
// get type of T
}
}
Me gustaría saber qué tipo de objetos contiene la lista de mi clase. Entonces la propiedad de la lista llamada Bar
o la variable local baz
, contiene que tipo de T
?
No puedo hacerlo Bar[0].GetType()
, porque la lista puede contener cero elementos. ¿Cómo puedo hacerlo?
16 Respuestas
748
Si lo entiendo correctamente, su lista tiene el mismo parámetro de tipo que la clase de contenedor en sí. Si este es el caso, entonces:
Type typeParameterType = typeof(T);
Si se encuentra en la afortunada situación de tener object
como parámetro de tipo, consulte La respuesta de Marc.
Respondido el 19 de junio de 17 a las 13:06
538
(nota: supongo que todo lo que sabes es object
or IList
o similar, y que la lista podría ser de cualquier tipo en tiempo de ejecución)
Si sabes que es un List<T>
, entonces:
Type type = abc.GetType().GetGenericArguments()[0];
Otra opción es mirar el indexador:
Type type = abc.GetType().GetProperty("Item").PropertyType;
Usando nuevo TypeInfo:
using System.Reflection;
// ...
var type = abc.GetType().GetTypeInfo().GenericTypeArguments[0];
Respondido el 29 de diciembre de 14 a las 22:12
Escriba type = abc.GetType (). GetGenericArguments () [0]; ==> Índice de matriz fuera de límites ... - patricio desjardins
@Daok: entonces no es una lista - Marc Gravell ♦
Necesita algo para BindingList o List o cualquier objeto que contenga un . Lo que estoy haciendo uso un BindingListView personalizado - patricio desjardins
Pruébelo con BindingList , nuestro BindingListView heredar de BindingList y he probado ambas opciones y no funciona. Podría hacer algo mal ... pero creo que esta solución funciona para el tipo List pero no otro tipo de lista. - patricio desjardins
Escriba type = abc.GetType (). GetProperty ("Elemento"). PropertyType; return BindingListView en lugar de MyObject ... - patricio desjardins
52
Con el siguiente método de extensión puedes salirte sin reflexionar:
public static Type GetListType<T>(this List<T> _)
{
return typeof(T);
}
O más general:
public static Type GetEnumeratedType<T>(this IEnumerable<T> _)
{
return typeof(T);
}
Uso:
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
respondido 06 nov., 14:13
32
Intente
list.GetType().GetGenericArguments()
Respondido 14 Jul 10, 02:07
lista nueva () .GetType (). GetGenericArguments () devuelve System.Type [1] aquí con System.Int32 como entrada - Rauhotz
@Rauhotz el GetGenericArguments
El método devuelve un objeto Array de Type
, de los cuales debe analizar la posición del tipo genérico que necesita. Como Type<TKey, TValue>
: necesitarías GetGenericArguments()[0]
para obtener TKey
tipo y GetGenericArguments()[1]
para obtener TValue
tipo - Obispo de oro
15
Eso es trabajo para mí. Donde myList es un tipo de lista desconocido.
IEnumerable myEnum = myList as IEnumerable;
Type entryType = myEnum.AsQueryable().ElementType;
Respondido el 16 de junio de 20 a las 08:06
Recibo un error de que requiere un argumento de tipo (es decir <T>
) - jose humfrey
Joseph y otros, para deshacerse del error está en System.Collections. - user2334883
Solo necesito la segunda línea. A List
ya es una implementación de IEnumerable
, por lo que el elenco no parece agregar nada. Pero gracias, es una buena solución. - bomba de agua
12
Si no necesita toda la variable Tipo y solo desea verificar el tipo, puede crear fácilmente una variable temporal y usar el operador is.
T checkType = default(T);
if (checkType is MyClass)
{}
Respondido 20 Oct 15, 15:10
Esta debería ser la respuesta aceptada, sin duda la más eficaz. - serj sagan
9
Puede usar este para el tipo de devolución de lista genérica:
public string ListType<T>(T value)
{
var valueType = value.GetType().GenericTypeArguments[0].FullName;
return valueType;
}
Respondido el 08 de enero de 19 a las 07:01
8
Considere esto: lo uso para exportar 20 listas escritas de la misma manera:
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);
}
}
Respondido el 07 de diciembre de 11 a las 10:12
Esto no funciona si T es una superclase abstracta de los objetos agregados reales. Sin mencionar, solo new T();
haría lo mismo que (T)Activator.CreateInstance(typeof(T));
. Requiere que agregue where T : new()
a la definición de clase / función, pero si quieres para hacer objetos, eso debería hacerse de todos modos. - Nyerguds
Además, estás llamando GetType
en un FirstOrDefault
entrada que resulta en una posible excepción de referencia nula. Si está seguro de que devolverá al menos un artículo, ¿por qué no utilizar First
¿en lugar de? - Mathias Lykkegaard Lorenzen
6
LA GetGenericArgument()
El método debe establecerse en el Tipo base de su instancia (cuya clase es una clase genérica myClass<T>
). De lo contrario, devuelve un tipo [0].
Ejemplo:
Myclass<T> instance = new Myclass<T>();
Type[] listTypes = typeof(instance).BaseType.GetGenericArguments();
Respondido 13 Jul 11, 16:07
6
Utilizo este método de extensión para lograr algo similar:
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;
}
Lo usas así:
[TestMethod]
public void GetFriendlyTypeName_ShouldHandleReallyComplexTypes()
{
typeof(Dictionary<string, Dictionary<string, object>>).GetFriendlyTypeName()
.ShouldEqual("Dictionary<String, Dictionary<String, Object>>");
}
Esto no es exactamente lo que está buscando, pero es útil para demostrar las técnicas involucradas.
Respondido el 10 de enero de 19 a las 03:01
5
Puede obtener el tipo de "T" de cualquier tipo de colección que implemente IEnumerable con lo siguiente:
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;
}
Tenga en cuenta que no admite tipos de colección que implementan IEnumerable dos veces, p. ej.
public class WierdCustomType : IEnumerable<int>, IEnumerable<string> { ... }
Supongo que podría devolver una matriz de tipos si necesitara admitir esto ...
Además, es posible que también desee almacenar en caché el resultado por tipo de colección si está haciendo esto mucho (por ejemplo, en un bucle).
Respondido 17 Abr '14, 00:04
1
Usando la solución 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();
Respondido el 03 de junio de 15 a las 15:06
0
public bool IsCollection<T>(T value){
var valueType = value.GetType();
return valueType.IsArray() || typeof(IEnumerable<object>).IsAssignableFrom(valueType) || typeof(IEnumerable<T>).IsAssignableFrom(valuetype);
}
contestado el 05 de mayo de 15 a las 19:05
Esto parece abordar la cuestión de si el tipo es un tipo de lista y, pero la cuestión es más sobre cómo determinar con qué parámetro de tipo genérico ya se inicializó un tipo que se sabe que es una Lista. - nathan tuggy
0
Si desea conocer el tipo subyacente de una propiedad, intente esto:
propInfo.PropertyType.UnderlyingSystemType.GenericTypeArguments[0]
Respondido 13 Oct 16, 12:10
0
Así es como lo hice
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);
}
Entonces llámalo así
var item = Activator.CreateInstance(iListType.GetElementType());
OR
var item = Activator.CreateInstance(Bar.GetType().GetElementType());
Respondido el 27 de junio de 17 a las 22:06
-9
Tipo:
type = list.AsEnumerable().SingleOrDefault().GetType();
Respondido 14 Jul 10, 02:07
Esto arrojaría una NullReferenceException si la lista no tiene elementos dentro de ella para probarlos. - rossis muerto
SingleOrDefault()
también lanza InvalidOperationException
cuando hay dos o más elementos. - desarrollador
Esta respuesta es incorrecta, como lo señalaron correctamente \ @rossisdead y \ @devgeezer. - Oliver
No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas c# .net generics or haz tu propia pregunta.
Me encanta lo legible
typeof
es. Si quieres saber el tipo de T, solo usatypeof(T)
:) - demonio codigoDe hecho, solo usé typeof (Type) y funciona muy bien. - Anton
Sin embargo, no puede usar typeof () con un parámetro genérico. - reynevan
@Reynevan Por supuesto que puedes usar
typeof()
con un parámetro genérico. ¿Tiene algún ejemplo en el que no funcionaría? ¿O confunde los parámetros de tipo y las referencias? - luan