Frage Wie kann ich generischen Typ aus einer Zeichenfolgendarstellung erhalten?


ich habe MyClass<T>.

Und dann habe ich das string s = "MyClass<AnotherClass>";. Wie kann ich Typ aus der Zeichenfolge abrufen? s?

Ein Weg (hässlich) besteht darin, das "<" und ">" auszuwerten und zu tun:

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

Aber gibt es eine sauberere Möglichkeit, den endgültigen Typ ohne Parsing usw. zu erhalten?


76
2018-04-06 15:03


Ursprung


Antworten:


Das Format für Generika ist der Name, ein `Zeichen, die Anzahl der Typparameter, gefolgt von einer durch Kommas getrennten Liste der Typen in Klammern:

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

Ich bin mir nicht sicher, ob es eine einfache Möglichkeit gibt, von der C # -Syntax für Generika in die Art von Zeichenfolge zu konvertieren, die die CLR wünscht. Ich fing an, eine schnelle Regex zu schreiben, um es so zu analysieren, wie Sie in der Frage erwähnt haben, erkannte aber, dass das Parsen sehr kompliziert wird, wenn Sie nicht die Möglichkeit aufgeben, geschachtelte Generika als Typparameter zu haben.


91
2018-04-06 15:36



Auschecken Activator.CreateInstance - Sie können es mit einem Typ aufrufen

Activator.CreateInstance(typeof(MyType))

oder mit einer Assembly und dem Typnamen als string

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

Dadurch erhalten Sie eine Instanz des von Ihnen benötigten Typs.

Wenn du das brauchst Type anstatt der Instanz verwenden Sie die Type.GetType() Methode und der vollständig qualifizierte Name des Typs, an dem Sie interessiert sind, z.

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

Das wird dir das geben Type fraglich.


38
2018-04-06 15:06



Ich habe so etwas gebraucht und am Ende habe ich etwas Code geschrieben, um die einfachen Namen zu analysieren, die ich brauchte. Natürlich gibt es Raum für Verbesserungen, da es keine generischen Typnamen wie z List<string>, aber es ist gut für string, int[], decimal? und derartige. Teilen, falls dies jemandem hilft.

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

Die Verwendung ist so einfach wie das Schreiben:

Type t;

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

26
2018-02-09 14:00



Verwenden Sie Folgendes, um das Typobjekt aus der Zeichenfolge zu erhalten:

Type mytype = Type.GetType(typeName);

Sie können dies dann an weitergeben Activator.CreateInstance():

Activator.CreateInstance(mytype);

3
2018-04-06 15:12



Ich habe nicht viel Zeit, dies zu analysieren, obwohl ich glaube, dass ich ähnliche Antworten gesehen habe. Insbesondere denke ich, dass sie genau das tun, was Sie hier tun wollen:

Allgemeiner Repository-Fehler des Entity Framework

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

Hoffentlich hilft das, lassen Sie mich genauer wissen, wenn das nicht ist.


0
2018-04-06 15:10