Pregunta ¿Cómo puedo obtener un tipo genérico a partir de una representación de cadena?


yo tengo MyClass<T>.

Y luego tengo esto string s = "MyClass<AnotherClass>";. ¿Cómo puedo obtener el tipo de la cadena? s?

Una forma (fea) es analizar el "<" y ">" y hacer:

Type acType = Type.GetType("AnotherClass");  
Type whatIwant = typeof (MyClass<>).MakeGenericType(acType);

Pero, ¿hay una manera más clara de obtener el tipo final sin ningún análisis sintáctico, etc.?


76
2018-04-06 15:03


origen


Respuestas:


los formato para genéricos es el nombre, un carácter `, el número de parámetros de tipo, seguido de una lista delimitada por comas de los tipos entre paréntesis:

Type.GetType("System.Collections.Generic.IEnumerable`1[System.String]");

No estoy seguro de que haya una manera fácil de convertir la sintaxis de C # para los genéricos al tipo de cadena que quiere el CLR. Empecé a escribir una expresión regular rápida para analizarla como mencionaste en la pregunta, pero me di cuenta de que a menos que abandones la capacidad de tener genéricos anidados como parámetros de tipo, el análisis se volverá muy complicado.


91
2018-04-06 15:36



Revisa Activator.CreateInstance - puedes llamarlo con un tipo

Activator.CreateInstance(typeof(MyType))

o con un ensamblaje y nombre de tipo como string

Activator.CreateInstance("myAssembly", "myType")

Esto le dará una instancia del tipo que necesita.

Si necesitas el Type en lugar de la instancia, usa el Type.GetType() método y el nombre completo del tipo que le interesa, p. ej .:

string s = "System.Text.StringBuilder";
Type myClassType = Type.GetType(s);

Eso te dará el Type en cuestión.


38
2018-04-06 15:06



He necesitado algo así y terminé escribiendo un código para analizar los nombres de tipos simples que necesitaba. Por supuesto, hay margen de mejora, ya que no identificará nombres de tipos genéricos como List<string>, pero no tiene problema string, int[], decimal? y tal. Compartir en caso de que esto ayude a alguien.

public static class TypeExtensions
{
  public static Type GetTypeFromSimpleName(string typeName)
  {
    if (typeName == null)
      throw new ArgumentNullException("typeName");

    bool isArray = false, isNullable = false;

    if (typeName.IndexOf("[]") != -1)
    {
      isArray = true;
      typeName = typeName.Remove(typeName.IndexOf("[]"), 2);
    }

    if (typeName.IndexOf("?") != -1)
    {
      isNullable = true;
      typeName = typeName.Remove(typeName.IndexOf("?"), 1);
    }

    typeName = typeName.ToLower();

    string parsedTypeName = null;
    switch (typeName)
    {
      case "bool":
      case "boolean":
        parsedTypeName = "System.Boolean";
        break;
      case "byte":
        parsedTypeName = "System.Byte";
        break;
      case "char":
        parsedTypeName = "System.Char";
        break;
      case "datetime":
        parsedTypeName = "System.DateTime";
        break;
      case "datetimeoffset":
        parsedTypeName = "System.DateTimeOffset";
        break;
      case "decimal":
        parsedTypeName = "System.Decimal";
        break;
      case "double":
        parsedTypeName = "System.Double";
        break;
      case "float":
        parsedTypeName = "System.Single";
        break;
      case "int16":
      case "short":
        parsedTypeName = "System.Int16";
        break;
      case "int32":
      case "int":
        parsedTypeName = "System.Int32";
        break;
      case "int64":
      case "long":
        parsedTypeName = "System.Int64";
        break;
      case "object":
        parsedTypeName = "System.Object";
        break;
      case "sbyte":
        parsedTypeName = "System.SByte";
        break;
      case "string":
        parsedTypeName = "System.String";
        break;
      case "timespan":
        parsedTypeName = "System.TimeSpan";
        break;
      case "uint16":
      case "ushort":
        parsedTypeName = "System.UInt16";
        break;
      case "uint32":
      case "uint":
        parsedTypeName = "System.UInt32";
        break;
      case "uint64":
      case "ulong":
        parsedTypeName = "System.UInt64";
        break;
    }

    if (parsedTypeName != null)
    {
      if (isArray)
        parsedTypeName = parsedTypeName + "[]";

      if (isNullable)
        parsedTypeName = String.Concat("System.Nullable`1[", parsedTypeName, "]");
    }
    else
      parsedTypeName = typeName;

    // Expected to throw an exception in case the type has not been recognized.
    return Type.GetType(parsedTypeName);
  }
}

Usarlo es tan simple como escribir esto:

Type t;

t = TypeExtensions.GetTypeFromSimpleName("string");
t = TypeExtensions.GetTypeFromSimpleName("int[]");
t = TypeExtensions.GetTypeFromSimpleName("decimal?");

26
2018-02-09 14:00



Para obtener el objeto tipo de la cadena, use:

Type mytype = Type.GetType(typeName);

Puede pasar esto a Activator.CreateInstance():

Activator.CreateInstance(mytype);

3
2018-04-06 15:12



No tengo mucho tiempo para analizar todo esto, aunque creo que he visto algunas respuestas similares. En particular, creo que están haciendo exactamente lo que quieres hacer aquí:

Error de repositorio genérico de Entity Framework

(String.Format("[{0}]", baseType.Name.ToString())).OfType<T>();

Espero que esto ayude, hágamelo saber más específicamente si esto no es así.


0
2018-04-06 15:10