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.

PeteT
źródło
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 .

Matt Hamilton
źródło
15
Powiązane ze świetnymi przykładami: stackoverflow.com/questions/493490/...
John S.
Również ten post będzie odpowiedni, ponieważ
Brad Parks
1
Przykłady: stackoverflow.com/questions/7598088/…
profimedica
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);
Sarath Avanavu
źródło
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.

Ray Li
źródło
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.

PeteT
źródło
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.

Denny
źródło
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");
asd
źródło
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.

Greg Osborne
źródło
-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 .

Asish
źródło