Utwórz instancję klasy z łańcucha


218

Czy istnieje sposób utworzenia instancji klasy na podstawie tego, że znam nazwę klasy w czasie wykonywania. Zasadniczo miałbym nazwę klasy w ciągu.


Wygląda na to, że opisałeś rozwiązanie, które chcesz wdrożyć, ale nie problem, który próbujesz rozwiązać. Być może próbujesz zrobić coś z rozszerzalnością, w takim przypadku sugeruję sprawdzenie Managed Extensibility Framework .
Jay Bazuzi

Odpowiedzi:


159

Spójrz na metodę Activator.CreateInstance .


15
Powiązane ze świetnymi przykładami: stackoverflow.com/questions/493490/...
John S.

Również ten post będzie odpowiedni, ponieważ
Brad Parks


4
Na przykład:var driver = (OpenQA.Selenium.IWebDriver)Activator.CreateInstance("WebDriver", "OpenQA.Selenium.Firefox.FirefoxDriver").Unwrap();
Endy Tjahjono

2
Ważna uwaga tutaj: .Unwrap (), aby ominąć uchwyt zdalny, aby móc faktycznie wykonywać rzutowania. @Endy - Dzięki
Roger Willcocks,

77

To całkiem proste. Załóżmy, że twoja nazwa klasy to Cari przestrzeń nazw to Vehicles, a następnie przekaż parametr, Vehicles.Carktóry zwraca obiekt typu Car. W ten sposób możesz dynamicznie tworzyć dowolne wystąpienia dowolnej klasy.

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

Jeśli twoje w pełni kwalifikowane nazwisko (tj. Vehicles.CarW tym przypadku) znajduje się w innym zestawie, Type.GetTypebędzie puste. W takich przypadkach przeglądasz wszystkie zestawy i odnajdujesz Type. W tym celu możesz użyć poniższego kodu

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

Teraz, jeśli chcesz wywołać sparametryzowanego konstruktora, wykonaj następujące czynności

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

zamiast

Activator.CreateInstance(t);

Jak korzystać z niego bez rzutowania i jak wykonać rzut z podanego ciągu ?
TaW,

1
@TaW - aby użyć instancji klasy, musisz mieć pewną wiedzę o tym, co ona zrobi - w przeciwnym razie nie będziesz w stanie jej użyć. Najczęstszym przypadkiem użycia tego jest rzutowanie na interfejs, który daje wstępnie zdefiniowaną umowę. (To obowiązuje, chyba że używasz dynamickodu - patrz stackoverflow.com/a/2690661/904521 )
Tomer Cagan

1
Nie koduje typ zmiennej w jego nazwę, np. Nie ma potrzeby, aby prefiks strFullyQualifiedNamez str, fullyQualifiedNamebędzie wykonać zadanie.
Mehdi Dehghani,

Słowo kluczowe strjest używane jako część konwencji nazewnictwa zmiennych. Niektóre organizacje i projekty nalegają na przestrzeganie tego, dlatego wykorzystałem. Jeśli będziesz pracował w niektórych organizacjach / projektach, będziesz o tym wiedział. Jak powiedziałeś bez, strrównież wykona zadanie :) @MehdiDehghani
Sarath Avanavu

1
Wiem, że nie trzeba pracować w żadnej organizacji, aby wiedzieć o konwencjach nazewnictwa, ta konwencja znana jako notacja węgierska i jest jedną z tych złych i przestarzałych konwencji nazewnictwa. specjalnie dla C #
Mehdi Dehghani,

55

Z powodzeniem zastosowałem tę metodę:

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

Musisz rzutować zwrócony obiekt na wybrany typ obiektu.


9
Próbuję wyobrazić sobie scenariusz, w którym utworzenie obiektu za pomocą nazwy klasy, a następnie rzutowanie go jako tego typu, miałoby w ogóle sens.
MusiGenesis

13
Rozumiem, co masz na myśli. Wydaje się zbędny. Jeśli znasz nazwę klasy, dlaczego potrzebujesz ciągu dynamicznego? Jedną z sytuacji może być to, że rzutujesz na klasę podstawową, a ciąg znaków reprezentuje potomków tej klasy bazowej.
Ray Li

4
Jeśli znana jest klasa podstawowa, możesz użyć klasy bazowej lub jej interfejsu jako argumentu do przekazania potomków bez refleksji.
Garet Claborn,

3
Przydatny scenariusz: potrzebujesz tylko interfejsów serializacji lub innego dość powszechnego interfejsu. Nie rzucisz go na klasę, ale przynajmniej na coś więcej niż obiekt
Harald Coppoolse

2
Jak wykonać rzut z podanego ciągu ?
TaW,

23

Prawdopodobnie moje pytanie powinno być bardziej szczegółowe. Znam klasę bazową dla łańcucha, więc rozwiązałem ją przez:

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

Klasa Activator.CreateInstance ma różne metody osiągania tego samego na różne sposoby. Mógłbym rzucić go na obiekt, ale powyższe jest najbardziej przydatne w mojej sytuacji.


4
Zamiast odpowiadać w sekcji pytań, sugeruję edycję pytania i zwrócenie uwagi na zmiany. Otrzymasz więcej / lepsze odpowiedzi za zrobienie tego.
Jason Jackson

Dziękujemy za opublikowanie konkretnego wiersza kodu, który działał dla Ciebie. Sortowanie przez wszystkie przeciążenia CreateInstance i różne sposoby generowania typów zajęło mi dużo czasu, co mi oszczędziłeś.
Ethel Evans,

4

Wiem, że spóźniłem się na grę ... ale rozwiązaniem, którego szukasz, może być kombinacja powyższego i użycie interfejsu do zdefiniowania obiektów publicznie dostępnych aspektów.

Następnie, jeśli wszystkie twoje klasy, które zostałyby wygenerowane w ten sposób, implementują ten interfejs, możesz po prostu rzutować jako typ interfejsu i pracować z wynikowym obiektem.


4

Aby utworzyć instancję klasy z innego projektu w rozwiązaniu, możesz uzyskać zestaw wskazany nazwą dowolnej klasy (na przykład BaseEntity) i utworzyć nową instancję:

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

3

Na przykład, jeśli przechowujesz wartości różnych typów w polu bazy danych (przechowywane jako ciąg znaków) i masz inne pole z nazwą typu (tj. String, bool, int, MyClass), to na podstawie danych tego pola możesz, utwórz klasę dowolnego typu przy użyciu powyższego kodu i wypełnij ją wartością z pierwszego pola. Zależy to oczywiście od rodzaju przechowywanego typu, który ma metodę parsowania ciągów znaków na poprawny typ. Używałem tego wiele razy do przechowywania ustawień preferencji użytkownika w bazie danych.


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

dlaczego chcesz napisać taki kod? Jeśli masz klasę „ReportClass” jest dostępna, możesz utworzyć ją bezpośrednio, jak pokazano poniżej.

ReportClass report = new ReportClass();

Kod ReportClass report = (ReportClass)Activator.CreateInstance(Type.GetType(reportClass));jest używany, gdy nie masz dostępnej niezbędnej klasy, ale chcesz utworzyć instancję i / lub wywołać metodę dynamicznie.

Mam na myśli, że jest to przydatne, gdy znasz zestaw, ale podczas pisania kodu nie masz ReportClassdostępnej klasy .

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.