Как создать экземпляр неизвестного типа во время выполнения?

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

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

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

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

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

Ответ 1

Это то, о чем вы думаете?

object result = Convert.ChangeType("4", Type.GetType("System.Int32"));

Ответ 2

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

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

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

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

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

Ответ 4

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

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

Ответ 5

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

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

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

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

Ответ 6

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

Ответ 7

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

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

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

Ответ 8

Здесь приведен конкретный пример проблемы с Azure SQL Federations..., которая разбивает данные на отдельные db в соответствии с диапазоном клавиш.

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

SQL/.Net Тип SQL/ CLR.Net

INT/SqlInt32/Int32, Nullable

BIGINT/SqlInt64/Int64, Nullable

UNIQUEIDENTIFIER/SqlGuid/Guid, Nullable

VARBINARY (n), max n 900/SqlBytes, SqlBinary/Byte []

В идеале, параметр функции С# может принимать либо .NET тип SQL, либо тип CLR.Net, но только для одной категории типов.

Может ли тип объекта "объект" быть способным? И есть ли способ определить тип и преобразовать его соответственно?

Концепция выглядит примерно так:

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

{

... выяснить, какой тип obj должен гарантировать, что это один из приемлемых типов...

string key = obj.toString();

return string.Format( "USE FEDERATION {0} ({1} = '{2}') WITH RESET, FILTERING = {3}", fedName, distName, key, (filteringOn? "ON": "OFF" ));

}

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