2008-11-17 24 views
15

Mam zestaw klas, każdy z nich jest inny strategy do wykonania tej samej pracy.Utwórz obiekt, znając tylko nazwę klasy?

namespace BigCorp.SuperApp 
{ 
    public class BaseClass { } 
    public class ClassA : BaseClass { } 
    public class ClassB : BaseClass { } 
} 

Wybór strategii do użycia jest konfigurowalny. Chcę skonfigurować tylko nazwę klasy "ClassB" zamiast pełnej nazwy typu "BigCorp.SuperApp.ClassB" w pliku app.config.

<appConfig> 
    <SuperAppConfig> 
     <Handler name="ClassB" /> 
    </SuperAppConfig> 
</appConfig> 

Jednak wywołania refleksji nie dlatego, że oczekują pełnej nazwy typu, szczególnie

Type t = Type.GetType("ClassB"); // results in t == null 
BaseClass c = Activator.CreateInstance(t) as BaseClass; // fails 

Jak mogę uzyskać to do pracy podczas konfigurowania tylko nazwę klasy? Łączenie przestrzeni nazw z nazwą klasy dla pełnej nazwy typu? Czy istnieje inne wezwanie do refleksji, które działa?

Jeśli uważasz, że jest to bezużyteczne i powinienem oczekiwać, że konfiguracja zawiera pełną nazwę typu, jestem otwarty na to rozwiązanie! Podaj uzasadnienie, aby mnie przekonać.

(nie będzie ładowania typ spoza tego montażu/nazw)

+0

Mogłem po prostu użyć kontenera IoC, radzić sobie z długimi nazwami i zrobić dla mnie tworzenie obiektów! –

Odpowiedz

6

Ponieważ wiesz, wszystkie klasy będą pochodzić z tej samej przestrzeni nazw, należy skonfigurować go raz i używać:

<appConfig> 
    <SuperAppConfig handlerNamespace="BigCorp.SuperApp"> 
     <Handler class="ClassB" /> 
    </SuperAppConfig> 
</appConfig> 

Edit: Zmieniłem nazwa do klasa celu lepszego określenia znaczenia ten atrybut.

+0

Doceniam odpowiedzi, kod i omówienie ładowania zespołu. Ale podoba mi się odpowiedź Bryana na skupienie się na konfiguracji (ponieważ nie mogę uciec od pełnej nazwy). –

18

Albo użyć nazwa-montażowej wykwalifikowany lub zdobyć Zgromadzenia i używać Assembly.GetType(name). W tym przypadku, ponieważ chcesz typy w pliku konfiguracyjnym, zespół wykwalifikowanych jest ważna droga - ale skoro wiesz, wszystkie typy są w tym samym zespole:

zasady
Assembly assembly = typeof(SomeKnownType).Assembly; // in the same assembly! 
Type type = assembly.GetType(name); // full name - i.e. with namespace (perhaps concatenate) 
object obj = Activator.CreateInstance(type); 

Statyczny Type.GetType(string) został sondowania które często powodują dezorientację ... analizuje zestaw wywołujący i kilka zestawów systemowych - ale nie wszystkie wczytane złożenia.

+0

Mam odwołanie usługi, które chcę wywołać za pomocą tego, ale nie pojawi się na liście typu zespołu (wykonane z klasy). Mimo że mogę utworzyć obiekt odniesienia, wywołując hardcode konstruktora. – MrFox

5
(I will not be loading a type from outside this assembly/namespace)

ze względu na powyższą linię, można bezpiecznie założyć, że wiesz, czym jest przestrzeń nazw. Nie można zrobić coś takiego:

Type t = Type.GetType("Namespace." + className); 
BaseClass c = Activator.CreateInstance(t) as BaseClass; 

planujący ewentualnie móc dodawać dodatkowe zajęcia strategy być załadowane w przyszłości, być może za pośrednictwem dodatkowego montażu, trzeba by w pełni zakwalifikować swoją nazwę klasy. Jest to zalecane, ponieważ będziesz w stanie zapewnić rozszerzoną rozszerzalność swojej aplikacji.

+0

To faktycznie zależy od tego, gdzie jest ten kod (i jak interpretujesz "z zewnątrz" - tj. Czy jest to klasa? Czy dzwoniący?). Bez nazwy kwalifikowanej do zestawu Type.GetType (string) * tylko * spojrzy na bieżący zestaw i kilka zestawów systemowych. Nie znajdzie typów w bibliotekach losowych. –

2

Idę z pełną nazwą typu w konfiguracji aplikacji.Poniżej znajduje się nieco bardziej kompletne, ale nadal trywialny przykład

<SuperAppConfig> 
    <ObjectConfig provider="BigCorp.SuperApp.ClassA"> 
     <add name="one" /> 
     <add name="two" /> 
    </ObjectConfig> 
</SuperAppConfig> 

I klasa fabryka, która faktycznie tworzy to

private static Assembly a = typeof(IFactoryObject).Assembly; 
public static IFactoryObject CreateObject(String providerName) 
{ 
    Type t = a.GetType(providerName) 
    IFactoryObject o = Activator.CreateInstance(t) as IFactoryObject; 
    return o; 
} 
1
BaseClass c = Activator.CreateInstance(t) as BaseClass; // fails 

może również wynikać z faktu, że CreateInstance nie zwraca instancję BaseClass, zamiast instancji klasy BaseClass opakowanej w ObjectHandle.

Wrzuć do swojej BaseClass po użyciu metody UnWrap.