¿Cómo obtener el tipo de T de un miembro de una clase o método genérico?

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?

preguntado el 17 de febrero de 09 a las 13:02

16 Respuestas

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

Me encanta lo legible typeof es. Si quieres saber el tipo de T, solo usa typeof(T) :) - demonio codigo

De 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

(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

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

Esto solo es útil si ya conoce el tipo de T en tiempo de compilación. En cuyo caso, realmente no necesita ningún código. - recursiva

@recursive: es útil si está trabajando con una lista de tipo anónimo. - JJJ

Trata

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

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

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

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

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

El 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

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

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

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

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

Si desea conocer el tipo subyacente de una propiedad, intente esto:

propInfo.PropertyType.UnderlyingSystemType.GenericTypeArguments[0]

Respondido 13 Oct 16, 12:10

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

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 or haz tu propia pregunta.