Как я могу получить универсальный тип из строкового представления? - PullRequest
77 голосов
/ 06 апреля 2009

у меня MyClass<T>.

И тогда у меня есть это string s = "MyClass<AnotherClass>";. Как я могу получить Type из строки s?

Один из способов (безобразно) - разобрать "<" и ">" и сделать:

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

Но есть ли более чистый способ получения окончательного типа без разбора и т. Д .?

Ответы [ 5 ]

92 голосов
/ 06 апреля 2009

Формат для шаблонов - это имя, символ `, число параметров типа, за которым следует разделенный запятыми список типов в скобках:

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

Я не уверен, что есть простой способ преобразовать синтаксис C # для обобщенных типов в строку, которую хочет CLR. Я начал писать быстрое регулярное выражение, чтобы разобрать его, как вы упомянули в вопросе, но понял, что если вы не откажетесь от возможности иметь вложенные шаблоны в качестве параметров типа, синтаксический анализ будет очень сложным.

38 голосов
/ 06 апреля 2009

Выезд Activator.CreateInstance - вы можете позвонить с типом

Activator.CreateInstance(typeof(MyType))

или с именем сборки и типа string

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

Это даст вам экземпляр нужного вам типа.

Если вам нужен Type, а не экземпляр, используйте метод Type.GetType() и полное имя интересующего вас типа, например ::

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

Это даст вам Type в вопросе.

26 голосов
/ 09 февраля 2011

Мне нужно что-то вроде этого, и я закончил тем, что написал некоторый код для анализа простых имен типов, которые мне были нужны. Конечно, есть возможности для улучшения, так как он не будет идентифицировать имена общих типов, такие как List<string>, но он прекрасно подходит для string, int[], decimal? и тому подобное. Обмен в случае, если это кому-нибудь поможет.

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

Использовать это так же просто, как написать это:

Type t;

t = TypeExtensions.GetTypeFromSimpleName("string");
t = TypeExtensions.GetTypeFromSimpleName("int[]");
t = TypeExtensions.GetTypeFromSimpleName("decimal?");
3 голосов
/ 06 апреля 2009

Чтобы просто получить объект типа из строки, используйте:

Type mytype = Type.GetType(typeName);

Затем вы можете передать это Activator.CreateInstance():

Activator.CreateInstance(mytype);
0 голосов
/ 06 апреля 2009

У меня не так много времени, чтобы разобраться в этом, хотя я думаю, что видел несколько похожих ответов. В частности, я думаю, что они делают именно то, что вы хотите сделать здесь:

Общая ошибка хранилища Entity Framework

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

Надеюсь, это поможет, дайте мне знать, если это не так.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...