¿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, así que:

public class Foo<T>
{
    public List<T> Bar { get; set; }

    public void Baz()
    {
        // get type of T
    }   
}

Cuando instancio la clase, el T se convierte en MyTypeObject1, por lo que la clase tiene una propiedad genérica list: 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. Así que la propiedad list llamada Bar o la variable local baz, contiene qué tipo de T?

No puedo hacer Bar[0].GetType(), porque la lista podría contener cero elementos. ¿Cómo puedo hacerlo?

Author: CodeCaster, 2009-02-17

16 answers

Si entiendo correctamente, su lista tiene el mismo parámetro de tipo que la propia clase contenedor. Si este es el caso, entonces:

Type typeParameterType = typeof(T);

Si tienes la suerte de tener object como parámetro de tipo, consulta La respuesta de Marc.

 564
Author: Tamas Czinege,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-19 12:27:21

(nota: Asumo que todo lo que sabes es object o 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 un nuevo TipoInfo:

using System.Reflection;
// ...
var type = abc.GetType().GetTypeInfo().GenericTypeArguments[0];
 468
Author: Marc Gravell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-29 22:29:14

Con el siguiente método de extensión puede escapar sin reflexión:

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
 41
Author: 3dGrabber,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-06 13:49:38

Intenta

list.GetType().GetGenericArguments()
 29
Author: Rauhotz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-07-14 01:49:22

Eso es trabajo para mí. Donde myList es una especie de lista desconocida.

IEnumerable myEnum = myList as IEnumerable;
Type entryType = myEnum.AsQueryable().ElementType;
 13
Author: Carlos Rodriguez,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-18 10:01:22

Considere esto: Lo uso para exportar 20 lista mecanografiada 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);
    }
}
 9
Author: Ferenc Mucsi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-07 10:20:52
public string ListType<T>(T value){
    var valueType = value.GetType().GenericTypeArguments[0].FullName;
    return value;
}

Puede usar este para el tipo de lista genérica de repetición.

 7
Author: vishal kumar Saxena,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-13 11:00:49

Si no necesita toda la variable de 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)
{}
 6
Author: Sebi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-20 14:03:59

El método GetGenericArgument() 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();
 5
Author: Thomas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-13 15:35:23

Puede obtener el tipo de " T " de cualquier tipo de colección que implementeerableumerable 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 colecciones que implementanEnumerable dos veces, por ejemplo,

public class WierdCustomType : IEnumerable<int>, IEnumerable<string> { ... }

Supongo que podría devolver una matriz de tipos si necesita soportar esto...

También es posible que desee almacenar en caché el resultado por tipo de colección si está haciendo esto mucho (por ejemplo, en un bucle).

 3
Author: Dan Malcolm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-16 23:00:38

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

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ás buscando, pero es útil para demostrar las técnicas involucradas.

 2
Author: Ken Smith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-28 00:07:52

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();
 1
Author: fantastory,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-06-03 14:41:40
public bool IsCollection<T>(T value){
  var valueType = value.GetType();
  return valueType.IsArray() || typeof(IEnumerable<object>).IsAssignableFrom(valueType) || typeof(IEnumerable<T>).IsAssignableFrom(valuetype);
}
 0
Author: Karanvir Kang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-05 18:23:26

Si quieres saber el tipo subyacente de una propiedad, prueba esto:

propInfo.PropertyType.UnderlyingSystemType.GenericTypeArguments[0]
 0
Author: Fatih Çelik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-13 11:38:09

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

O

var item = Activator.CreateInstance(Bar.GetType().GetElementType());
 0
Author: Alen.Toma,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-27 21:47:00

Tipo:

type = list.AsEnumerable().SingleOrDefault().GetType();
 -9
Author: Ferenc Mucsi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-07-14 01:49:41