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

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

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

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

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

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

8 ответов


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

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

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

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

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 экземпляру требуемого типа. Это может привести к ы. Например, Convert.ChangeType("4", typeof(FileStream)) очевидно, потерпит неудачу, как и должно быть.

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

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


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

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

извлечение значений из строк, очевидно, будет работать только для ограниченного набора типов. Ты мог бы!--6-->

  • использовать 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);
    

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

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


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

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

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

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


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


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

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

среда 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[]

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

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

концепция что-то вроде:

public void fn (object obj, string fedName, string distName, bool filteringOn)

{

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

string key = obj.toString ();

возвращает строку.Формат ("использовать Федерацию {0} ({1}='{2}') с RESET, FILTERING = {3}", fedName, distName, key, (filteringOn ? "ON": "OFF"));

}

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


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

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

надеюсь, что это помогает.