Pytanie Jak mogę uzyskać ogólny typ z reprezentacji ciągów?


mam MyClass<T>.

A potem mam to string s = "MyClass<AnotherClass>";. Jak mogę uzyskać typ z ciągu znaków? s?

Jednym ze sposobów (brzydki) jest sparsować "<" i ">" i zrobić:

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

Ale czy istnieje czystszy sposób na uzyskanie ostatecznego typu bez analizy składniowej itp.?


76
2018-04-06 15:03


pochodzenie




Odpowiedzi:


The format dla leków generycznych jest nazwą, znakiem `` `` `` `` `` `` `` `` `` `` `` `` `` `` `` `` `` `` `` `` `` `` `` `` `` `` `` `` `` "," "," "," ".

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

Nie jestem pewien, czy istnieje łatwy sposób konwertowania ze składni C # dla generycznych na typ ciągu, który chce CLR. Zacząłem pisać szybkie wyrażenie, aby je przetworzyć, tak jak wspomniałeś w pytaniu, ale zdałem sobie sprawę, że dopóki nie zrezygnujesz z możliwości zagnieżdżenia generycznych jako parametrów typu, parsowanie stanie się bardzo skomplikowane.


91
2018-04-06 15:36



+1 - świetna odpowiedź, dzięki! Bawiłem się, próbując dowiedzieć się, jak poradzić sobie z lekami generycznymi! - marc_s
Dzięki. To działa i muszę zmodyfikować kod, aby sformatować ciąg w ten sposób. Zastanawiał się jednak, czy nadal istnieje sposób, aby po prostu użyć: "MyClass <AnotherClass>" dokładnie tak, jak jest pokazany w ciągu znaków, aby uzyskać instancję typu. Wygląda o wiele czystsze. - DeeStackOverflow
Nie musisz modyfikować kodu, aby sformatować ciąg znaków w ten sposób, wystarczy wywołać ToString () na typie. - Rush Frisby


Sprawdzić Activator.CreateInstance - możesz nazwać go typem

Activator.CreateInstance(typeof(MyType))

lub z zestawem i nazwą typu jako string

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

To da ci typ jakiego potrzebujesz.

Jeśli potrzebujesz Type zamiast instancji, użyj Type.GetType() metoda i pełna nazwa typu, który Cię interesuje, np .:

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

To da ci Type w pytaniu.


38
2018-04-06 15:06



To właśnie dostaje instancję typu, a nie instancję System.Type, która na podstawie fragmentu kodu wydaje się być tym, czego szuka OP. - Daniel Schaffer


Potrzebowałem czegoś takiego i skończyło się na tym, że napisałem jakiś kod, żeby przeanalizować proste nazwy, których potrzebowałem. Oczywiście jest miejsce na ulepszenia, ponieważ nie będzie to oznaczać nazw rodzajów ogólnych, takich jak List<string>, ale to jest w porządku string, int[], decimal? i taki. Dzielenie się w przypadku, gdy to pomaga każdemu.

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

Używanie go jest tak proste jak pisanie tego:

Type t;

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

26
2018-02-09 14:00



To niesamowicie użyteczny fragment kodu. - The Communist Duck
Krótki, doskonały, wyjątkowo przydatny! Dzięki - xrnd


Aby pobrać obiekt typu z ciągu znaków, użyj:

Type mytype = Type.GetType(typeName);

Możesz wtedy przekazać to do Activator.CreateInstance():

Activator.CreateInstance(mytype);

3
2018-04-06 15:12





Nie mam zbyt wiele czasu na przeanalizowanie tego, choć wydaje mi się, że widziałem podobne odpowiedzi. W szczególności myślę, że robią dokładnie to, co chcesz zrobić tutaj:

Błąd generycznego repozytorium Entity Framework

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

Mam nadzieję, że to pomoże, daj mi znać bardziej szczegółowo, jeśli tak nie jest.


0
2018-04-06 15:10