2010-02-18 6 views
5

Angenommen, ich habe eine Factory-Methode, die eine Instanz eines Typs erstellen möchte, der zur Laufzeit über Reflektion ausgewählt wird. Angenommen, meine Factory-Methode ist ein generischer Code, der nicht direkt auf die Assembly verweist, die den angegebenen Typ enthält, obwohl sie innerhalb einer Anwendung ausgeführt wird, auf die die erforderliche Assembly verweist.Wie kann ich einen Typ von einer referenzierten Baugruppe über Reflexion erhalten

Wie schreibe ich Code, der diesen Typ finden kann? Wenn ich Folgendes tue

public object CreateInstance(string typeName) 
{ 
    Type desiredType = Assembly.GetExecutingAssembly().GetType(typename); 

    // Instantiate the type... 
} 

scheint dies fehlzuschlagen, da der Typ nicht in der ausführenden Assembly definiert ist. Wenn ich alle Assemblys zur Laufzeit verfügbar machen könnte, könnte ich über sie iterieren und herausfinden, welche den gewünschten Typ enthält. Aber ich sehe keinen Weg, das zu tun. AppDomain.CurrentDomain.GetAssemblies() sieht vielversprechend aus, aber gibt nicht alle Assemblys zurück, auf die ich in meinem Projekt verwiesen habe.

Bearbeiten: Mehrere Leute haben darauf hingewiesen, dass ich die Baugruppe laden muss. Das Problem ist, dass dieser Codeabschnitt nicht weiß, welche Assembly er laden soll, da ich versuche, diesen Code so zu schreiben, dass er nicht von den anderen Assemblies abhängt.

Ich habe bewusst die Details von typeName weggelassen, da die Zuordnung von String zu Typ in meinem echten Code tatsächlich komplizierter ist. In der Tat wird der Typ durch ein benutzerdefiniertes Attribut identifiziert, das die angegebene Zeichenfolge enthält. Wenn ich jedoch eine Liste von Typen abrufen kann, habe ich kein Problem, die Liste auf den gewünschten Typ zu beschränken.

+0

Was ist der Wert in typeName? Ist es der voll qualifizierte Name? –

Antwort

9

Der Aufruf an AppDomain.CurrentDomain.GetAssemblies() gibt nur den Satz von DLLs zurück, die derzeit in AppDomain geladen werden. DLLs werden bei Bedarf in einen CLR-Prozess geladen; Daher wird es nicht alle DLLs enthalten, auf die in Ihrem Projekt verwiesen wird, bis eines tatsächlich verwendet wird.

Was Sie tun könnten, ist, zwingen Sie die Baugruppe in den Prozess mit einem Ausdruck typeof. Zum Beispiel

var force1 = typeof(SomeTypeInTheProject).Assembly; 
var force2 = typeof(SomeTypeInProject2).Assembly; 
+0

Danke, das scheint zu funktionieren - und da alle möglichen Typen in der gleichen Baugruppe sind, muss ich es nur für einen Typ machen. Es fühlt sich jedoch ziemlich hässlich an. –

2

AppDomain.CurrentDomain.GetAssemblies() gibt nur die geladenen Baugruppen zurück. Sie müssen also die referenzierte Assembly laden, wenn sie nicht bereits geladen wurde.

10

könnten Sie GetReferencedAssemblies und eine Schleife durch alle Arten verwenden, bis Sie die Art finden, die Sie suchen.

var t = Assembly 
    .GetExecutingAssembly() 
    .GetReferencedAssemblies() 
    .Select(x => Assembly.Load(x)) 
    .SelectMany(x => x.GetTypes()).First(x => x.FullName == typeName); 

Obwohl es nicht die performantesten sein könnte. Dann wieder, Sie sind mit Reflexion.

+0

Gute Idee. Es funktioniert nicht ganz für mich, da die Assembly nicht direkt referenziert wird, sondern indirekt von der aufrufenden Assembly referenziert wird; Vermutlich könnte ich es finden, indem ich .GetReferencedAssemblies() für jede der gefundenen Assemblys rekursiv aufruft (und von .GetEntryAssembly() statt .GetExecutingAssembly()). Und ja, es ist nicht gut für die Leistung, aber das ist in Ordnung für mich, da es Start-Code ist und nur einmal ausgeführt. –

Verwandte Themen