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




genérica generics (14)

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 hago una instancia de la clase, la T 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 lista llamada Bar o la variable local baz , ¿qué tipo de T ?

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


Answers

public string ListType<T>(T value){
    var valueType = value.GetType().GenericTypeArguments[0].FullName;
    return value;
}

Puede utilizar este para volver a ejecutar el tipo de lista genérica.


public bool IsCollection<T>(T value){
  var valueType = value.GetType();
  return valueType.IsArray() || typeof(IEnumerable<object>).IsAssignableFrom(valueType) || typeof(IEnumerable<T>).IsAssignableFrom(valuetype);
}

Si no necesita la variable Tipo completa y solo desea verificar el tipo, puede crear fácilmente una variable temporal y usarla como operador.

T checkType = default(T);

if (checkType is MyClass)
{}

Con el siguiente método de extensión puedes alejarte 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

El método GetGenericArgument() debe configurarse 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();

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

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

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.


(nota: supongo que todo lo que sabe es un object o una lista o similar, y que la lista podría ser de cualquier tipo en tiempo de ejecución)

Si sabes que es una List<T> , entonces:

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

Otra opción es mirar el indexador:

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

Usando el nuevo TypeInfo:

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

Eso es trabajo para mí. Donde myList es algún tipo de lista desconocida.

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

Tratar

list.GetType().GetGenericArguments()

Tipo:

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

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

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

Type typeParameterType = typeof(T);

Si estás en la situación de suerte de tener un object como parámetro de tipo, consulta la respuesta de Marc .


Consulte este post. Tipo genérico de Java como argumento para GSON

Tengo mejor solución para esto. Aquí está la clase de envoltorio para la lista, de modo que el envoltorio pueda almacenar exactamente el tipo de lista.

public class ListOfJson<T> implements ParameterizedType
{
  private Class<?> wrapped;

  public ListOfJson(Class<T> wrapper)
  {
    this.wrapped = wrapper;
  }

  @Override
  public Type[] getActualTypeArguments()
  {
      return new Type[] { wrapped };
  }

  @Override
  public Type getRawType()
  {
    return List.class;
  }

  @Override
  public Type getOwnerType()
  {
    return null;
  }
}

Y luego, el código puede ser simple:

public static <T> List<T> toList(String json, Class<T> typeClass)
{
    return sGson.fromJson(json, new ListOfJson<T>(typeClass));
}






c# .net generics