Створіть екземпляр класу з рядка


218

Чи є спосіб створити екземпляр класу виходячи з того, що я знаю ім'я класу під час виконання. В основному я б мала назву класу в рядку.


Здається, ви описали рішення, яке хочете реалізувати, але не проблему, яку ви намагаєтеся вирішити. Можливо, ви намагаєтесь зробити щось із розширенням, і тоді я пропоную вам перевірити керовану рамку розширення .
Джей Базузі

Відповіді:


159

Погляньте на метод Activator.CreateInstance .


15
Пов’язане із чудовими прикладами: stackoverflow.com/questions/493490/…
Джон С.

Також ця публікація буде доречною і тому, що потрібно знайти ваш тип: stackoverflow.com/questions/1825147/…
Brad Parks


4
Наприклад:var driver = (OpenQA.Selenium.IWebDriver)Activator.CreateInstance("WebDriver", "OpenQA.Selenium.Firefox.FirefoxDriver").Unwrap();
Endy Tjahjono

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 )
Tomer Cagan

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 має різні методи досягнення одного і того ж різними способами. Я міг би кинути його на об'єкт, але вищезазначене найбільше користь для моєї ситуації.


4
Замість відповіді в розділі запитань я б запропонував вам відредагувати своє запитання та зазначити зміни. Ви отримаєте більше / кращі відповіді за це.
Джейсон Джексон

Дякуємо, що опублікували конкретний рядок коду, який працював для вас. Сортування всіх перевантажень CreateInstance та різних способів генерування типів забирало у мене багато часу, і ти мене врятував.
Етел Еванс

4

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

Потім, якщо всі ваші класи, які були б створені таким чином, реалізують цей інтерфейс, ви можете просто представити як тип інтерфейсу та працювати з отриманим об'єктом.


4

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

  var newClass = System.Reflection.Assembly.GetAssembly(typeof(BaseEntity)).CreateInstance("MyProject.Entities.User");

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.

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