Создать экземпляр класса из строки

218

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

PeteT
источник
Похоже, вы описали решение, которое хотите реализовать, но не проблему, которую пытаетесь решить. Возможно, вы пытаетесь сделать что-то с расширяемостью, и в этом случае я предлагаю вам проверить Managed Extensibility Framework .
Джей Базузи

Ответы:

159

Взгляните на метод Activator.CreateInstance .

Мэтт Гамильтон
источник
15
Связано с прекрасными примерами: stackoverflow.com/questions/493490/…
Джон С.
Также этот пост будет актуален, так как ваш тип должен быть найден: stackoverflow.com/questions/1825147/…
Брэд Паркс
1
Примеры: stackoverflow.com/questions/7598088/…
profimedica
4
Например:var driver = (OpenQA.Selenium.IWebDriver)Activator.CreateInstance("WebDriver", "OpenQA.Selenium.Firefox.FirefoxDriver").Unwrap();
Энди Тяхджоно
2
Важное примечание: .Unwrap (), чтобы обойти дескриптор удаленного взаимодействия, чтобы вы могли на самом деле делать приведения. @Endy - Спасибо
Роджер Уиллкокс
77

Это довольно просто. Предположим, что ваше имя класса Carи пространство имен Vehicles, а затем передать параметр, Vehicles.Carкоторый возвращает объект типа Car. Таким образом, вы можете динамически создавать любой экземпляр любого класса.

public object GetInstance(string strFullyQualifiedName)
{         
     Type t = Type.GetType(strFullyQualifiedName); 
     return  Activator.CreateInstance(t);         
}

Если ваше полное имя (т.е. Vehicles.Carв данном случае) находится в другой сборке, оно Type.GetTypeбудет нулевым. В таких случаях вы можете просмотреть все сборки и найти Type. Для этого вы можете использовать следующий код

public object GetInstance(string strFullyQualifiedName)
{
     Type type = Type.GetType(strFullyQualifiedName);
     if (type != null)
         return Activator.CreateInstance(type);
     foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
     {
         type = asm.GetType(strFullyQualifiedName);
         if (type != null)
             return Activator.CreateInstance(type);
     }
     return null;
 }

Теперь, если вы хотите вызвать параметризованный конструктор, сделайте следующее

Activator.CreateInstance(t,17); // Incase you are calling a constructor of int type

вместо того

Activator.CreateInstance(t);
Сарат Аванаву
источник
Как использовать его без приведения и как выполнить приведение из заданной строки ??
TaW
1
@TaW - для того, чтобы использовать экземпляр класса, вам нужно иметь некоторые знания о том, что он собирается делать, иначе вы не сможете его использовать. Наиболее распространенным вариантом использования для этого будет приведение к некоторому интерфейсу, который даст вам заранее определенный контракт. (Это верно, если вы не используете dynamicкод - см. Stackoverflow.com/a/2690661/904521 )
Томер Кейган
1
Не кодировать тип переменных в этом имени, например:. Нет необходимости префикса strFullyQualifiedNameс str, fullyQualifiedNameбудет делать эту работу.
Мехди Дехгани
Ключевое слово strиспользуется как часть соглашения об именовании переменных. Некоторые организации и проекты настаивают на том, чтобы следовать этому, поэтому я использовал. Если бы вы работали в определенных организациях / проектах, вы будете знать это. Как вы сказали и без strнего, он тоже сделает свою работу :) @MehdiDehghani
Сарат Аванаву
1
Я знаю, что нет никакой необходимости работать в какой-либо организации, чтобы знать о соглашениях об именах, хотя это соглашение известно как венгерская нотация и является одним из плохих и устаревших соглашений об именах. специально для C #
Мехди
55

Я успешно использовал этот метод:

System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(string className)

Вам нужно привести приведенный объект к нужному типу объекта.

Рэй Ли
источник
9
Я пытаюсь представить сценарий, в котором создание объекта с помощью имени класса и последующее приведение его к типу будет иметь какой-либо смысл.
MusiGenesis
13
Я понимаю что ты имеешь ввиду. Это кажется излишним. Если вы знаете имя класса, зачем вам динамическая строка? Одной из ситуаций может быть то, что ваше приведение к базовому классу и строка представляют потомков этого базового класса.
Рэй Ли
4
Если базовый класс известен, вы можете использовать базовый класс или его интерфейс в качестве аргумента для передачи потомков без отражения.
Гарет Клаборн
3
Полезный сценарий: вам нужны только интерфейсы сериализации или любой другой довольно распространенный интерфейс. Вы не приведете его к классу, но, по крайней мере, к чему-то большему, чем объект
Харальд Копполс
2
Как сделать приведение из заданной строки ??
TaW
23

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

ReportClass report = (ReportClass)Activator.CreateInstance(Type.GetType(reportClass));

Класс Activator.CreateInstance имеет различные методы для достижения одного и того же по-разному. Я мог бы привести его к объекту, но вышеизложенное наиболее полезно для моей ситуации.

PeteT
источник
4
Вместо того, чтобы отвечать в разделе вопросов, я бы предложил вам отредактировать свой вопрос и отметить изменения. Вы получите больше / лучше ответов за это.
Джейсон Джексон
Спасибо за публикацию конкретной строки кода, которая работает для вас. Сортировка по всем перегрузкам CreateInstance и различным способам генерации типов заняла у меня много времени, что вы спасли меня.
Этель Эванс
4

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

Затем, если все ваши классы, которые будут сгенерированы таким образом, реализуют этот интерфейс, вы можете просто привести их как тип интерфейса и работать с результирующим объектом.

Denny
источник
4

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

  var newClass = System.Reflection.Assembly.GetAssembly(typeof(BaseEntity)).CreateInstance("MyProject.Entities.User");
ASD
источник
3

Например, если вы храните значения различных типов в поле базы данных (хранятся в виде строки) и имеете другое поле с именем типа (т. Е. String, bool, int, MyClass), то из данных этого поля вы можете, предположительно, создайте класс любого типа, используя приведенный выше код, и заполните его значением из первого поля. Это, конечно, зависит от типа, который вы храните, имея метод для анализа строк в правильный тип. Я использовал это много раз, чтобы сохранить настройки пользовательских настроек в базе данных.

Грег Осборн
источник
-11
ReportClass report = (ReportClass)Activator.CreateInstance(Type.GetType(reportClass));

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

ReportClass report = new ReportClass();

Код ReportClass report = (ReportClass)Activator.CreateInstance(Type.GetType(reportClass));используется, когда у вас нет необходимого класса, но вы хотите создать экземпляр и / или вызвать метод динамически.

Я имею в виду, что это полезно, когда вы знаете сборку, но при написании кода у вас нет ReportClassдоступного класса .

Asish
источник