Как создать экземпляр неизвестного типа во время выполнения? - PullRequest
12 голосов
/ 12 ноября 2009

У меня есть следующее в C #:

string typename = "System.Int32";
string value = "4";

эти две строки должны быть взяты для генерации объекта указанного типа с указанным значением ...

результат должен быть:

object o = CreateUnknownType(typename, value);
...
Int32 test = (Int32)o;

Ответы [ 8 ]

20 голосов
/ 12 ноября 2009

Это ты о чем думаешь?

object result = Convert.ChangeType("4", Type.GetType("System.Int32"));
15 голосов
/ 12 ноября 2009

Как уже говорилось, это слишком широко и не может быть решено вообще.

Вот несколько вариантов:

Type type = Type.GetType(typename);
object o = Activator.CreateInstance(type);

Это создаст экземпляр типа, который typename описывает. Он вызывает конструктор без параметров этого типа. (Недостаток: не все объекты имеют конструктор без параметров. Кроме того, он устанавливает состояние объекта с помощью value.)

Type type = Type.GetType(typename);
object o = Activator.CreateInstance(type, new[] { value });

Это создаст экземпляр типа, который typename описывает. Он вызывает конструктор этого типа, который принимает один параметр типа string. (Недостаток: не у всех объектов есть такой конструктор. Например, Int32 не имеет такого конструктора, поэтому вы столкнетесь с исключением во время выполнения.)

Type type = Type.GetType(typename);
object o = Convert.ChangeType(value, type);

Это попытается преобразовать строку value в экземпляр требуемого типа. Это может привести к InvalidCastException с хотя. Например, Convert.ChangeType("4", typeof(FileStream)) явно потерпит неудачу, как и должно быть.

Фактически, этот последний пример (создание экземпляра типа FileStream с начальным состоянием, определяемым строкой "4") показывает, насколько абсурдна общая проблема. Существуют некоторые конструкции / преобразования, которые просто невозможно сделать.

Вы можете переосмыслить проблему, которую вы пытаетесь решить, чтобы избежать этой болтовни.

3 голосов
/ 12 ноября 2009

Создание экземпляра типа, который вы знаете по имени (и который должен иметь конструктор по умолчанию):

   string typeName = "System.Int32";
   Type type = Type.GetType(type);
   object o = Activator.CreateInstance(type);

Разбор значения из строки, очевидно, будет работать только для ограниченного набора типов. Вы могли бы

  • используйте Convert.ChangeType как предложено от PhilipW
  • или, может быть, создать Dictionary<Type,Func<string,object>> который сопоставляет известные типы с известным анализом Функции
  • или используйте отражение для вызова Parse (string) метод по типу, при условии, что есть один:

       string valueText = "4";
       MethodInfo parseMethod = type.GetMethod("Parse");
       object value = parseMethod.Invoke(null, new object[] { valueText });
    
  • или, может быть, вы можете использовать инфраструктура, предоставляемая .NET компонентная модель. Вы можете получить преобразователь типа компонента и использование это так:

       TypeConverter converter = TypeDescriptor.GetConverter(type);
       object value = converter.ConvertFromString(valueText);
    
1 голос
/ 19 ноября 2009

Возможно, у вас есть набор различных типов, каждый из которых реализует известный интерфейс?

Например, если у вас есть несколько разных пользовательских элементов управления и вы хотите загрузить один из них в контейнер, каждый из них может реализовать IMyWobblyControl (известный интерфейс), но вы можете не знать до времени выполнения, какой из них загрузить, возможно, из чтения строк из какой-либо формы файла конфигурации.

В этом случае вам нужно будет использовать отражение, чтобы загрузить фактический тип из чего-то вроде полного имени сборки, а затем преобразовать его в ваш известный тип, чтобы использовать его.

Конечно, вам нужно убедиться, что ваш код обрабатывает недопустимое приведение, сборку не найдено и любые другие исключения, которые могут возникать из-за чего-то столь же шаткого, как эта ...

1 голос
/ 12 ноября 2009

Ваша логика здесь кажется немного ошибочной. Очевидно, что если вы позже непосредственно приводите объект к фактическому типу, то вы должны знать тип для начала.

Если в этом вопросе чего-то не хватает, уточните, и, возможно, есть более подходящий ответ, чем просто: «Это не имеет большого смысла».

0 голосов
/ 03 ноября 2012

Ниже приведен конкретный пример проблемы, связанной с федерациями SQL Azure ... которая разбивает данные на отдельные базы данных в соответствии с диапазоном ключей.

Ключевые типы диапазонов:

SQL / .Net SQL-тип / CLR .Net

INT / SqlInt32 / Int32, Nullable

BIGINT / SqlInt64 / Int64, Nullable

UNIQUEIDENTIFIER / SqlGuid / Guid, Nullable

VARBINARY (n), макс. N 900 / SqlBytes, SqlBinary / Byte []

В идеале, параметр функции C # может принимать либо тип .Net SQL, либо тип CLR .Net, но хорошо подходит только одна категория типа.

Будет ли подходить параметр типа "объект"? И есть ли реальный способ идентифицировать тип и преобразовать его соответственно?

Концепция примерно такая:

public void fn (объект obj, строка fedName, строка distName, bool filteringOn)

{

... выясните, какой тип obj является одним из допустимых типов ...

string key = obj.toString ();

возвращение string.Format ("ИСПОЛЬЗОВАТЬ ФЕДЕРАЦИЮ {0} ({1} = '{2}') С СБРОСОМ, ФИЛЬТРАЦИЕЙ = {3}", fedName, distName, key, (filteringOn? "ON": "ВЫКЛ «));

}

Хотя значение параметра приведено к строке, оно будет перезаписано / проверено на стороне сервера sql, поэтому проверка его на стороне приложения желательна.

0 голосов
/ 12 ноября 2009

После использования:

Type type = Type.GetType(typename);

Попробуйте этот метод расширения:

public static class ReflectionExtensions
{
    public static T CreateInstance<T>(this Type source, params object[] objects)
        where T : class
    {            
        var cons = source.GetConstructor(objects.Select(x => x.GetType()).ToArray());
        return cons == null ? null : (T)cons.Invoke(objects);
    }
}

Надеюсь, это поможет.

0 голосов
/ 12 ноября 2009

Это похоже на работу для Int32.Parse (строка). Но чтобы согласиться с остальными, кажется, что это «уникально», и, наверное, следует подумать о перчатках.

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