Як я можу отримати загальний тип із подання рядка?


79

Я маю MyClass<T>.

І тоді у мене це є string s = "MyClass<AnotherClass>";. Як я можу отримати Type із рядка s?

Один із способів (потворний) - проаналізувати "<" та ">" і виконати:

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

Але чи є більш чистий спосіб отримати остаточний тип без будь-якого аналізу тощо?

Відповіді:


94

Формат для відтворених є ім'я, символ `, число параметрів типу, за яким слід розділений комами список типів в дужках:

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

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


+1 - чудова відповідь, дякую! Я возився навколо, намагаючись з’ясувати, як поводитися із дженериками!
marc_s

Дякую. Це працює, і я повинен змінити код, щоб відформатувати рядок таким чином. Однак цікавився, чи існує ще спосіб просто використовувати: "MyClass <AnotherClass>" саме так, як це показано в рядку для отримання екземпляра Type. Виглядає набагато чистіше.
DeeStackOverflow

Вам не потрібно модифікувати код для форматування рядка таким чином, просто зателефонуйте ToString () на Type.
Раш Фрісбі,

38

Перевірте 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питання.


3
Це просто отримує екземпляр типу, а не екземпляр System.Type, який на основі фрагмента коду, здається, є тим, що шукає OP.
Даніель Шаффер,

26

Мені потрібно було щось подібне, і в підсумку я написав якийсь код для синтаксичного аналізу простих імен типів, які мені потрібні. Звичайно , є місце для вдосконалення, так як він не буде визначати загальні імена типів , такі як 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?");

1
Короткий, ідеальний, надзвичайно корисний! Подяка
xrnd

3

Щоб просто отримати об'єкт типу зі рядка, використовуйте:

Type mytype = Type.GetType(typeName);

Потім ви можете передати це Activator.CreateInstance():

Activator.CreateInstance(mytype);

0

У мене не так багато часу, щоб проаналізувати це, хоча, думаю, я бачив кілька подібних відповідей. Зокрема, я думаю, що вони роблять саме те, що ти хочеш робити тут:

Помилка загального сховища Entity Framework

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

Сподіваємось, це допомагає, повідомте мені більш конкретно, якщо це не так.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.