Laden einer Baugruppe und Anwenden eines Prädikats auf ihre Typen in einer anderen Anwendungsdomäne

8

Bitte lesen Sie die ganze Frage. Ich habe eine einzigartige Situation mit mehreren Einschränkungen, die ich gerne lösen würde.

In meinem Code habe ich einen Ausdrucksbaum, der zu einem Predicate<System.Type> kompiliert wird. Mein Ziel ist es, eine Assembly zu laden, ohne sie zu sperren (es ist die Ausgabeassembly des Projekts, die ständig neu erstellt wird), dieses Prädikat auf die Liste ihrer Typen anzuwenden und eine Liste der resultierenden Namen :

%Vor%

Diese Assembly sollte in eine andere Appdomain geladen werden, da ich sie entladen möchte, sobald ich die benötigten Informationen habe.

Hier wird es schwierig. Es gibt mehrere Probleme, mit denen ich konfrontiert bin:

Wenn ich die Assembly in eine andere Appdomain lade und einfach ein Array mit allen Typen zurücksende, damit ich das Prädikat wieder in meiner Hauptanwendungsdomäne anwenden kann, bekomme ich, sobald die Typen in meine Hauptanwendungsdomäne zurückgemeldet werden FileNotFoundException , wobei angegeben wird, dass diese Assembly nicht gefunden wird. Dies ist sinnvoll, da die Assembly nur in eine andere von mir erstellte App-Domain geladen wird. Laden Sie es auch in der Haupt-App-Domain wird den Zweck zu besiegen.

Wenn ich alternativ versuche, das Prädikat in die andere App-Domäne zu übernehmen, es dort anzuwenden und ein Array von Strings zurück zu erhalten (vollständiger Typname), bekomme ich SerializationException: "Cannot serialize delegates over unmanaged function pointers, dynamic methods or methods outside the delegate creator's assembly." , weil das Prädikat eine Dynamische Methode ist ( kompiliert aus einem Ausdrucksbaum).

Beim Laden in die primäre Anwendungsdomäne treten diese Probleme nicht auf. Da jedoch eine geladene Assembly nicht entladen werden kann, ohne die gesamte Anwendungsdomäne zu entladen, sobald die Assembly geändert wird (nach der Neuerstellung), wird versucht, eine Assembly mit zu laden Derselbe Name würde zu einer Ausnahme führen.

Kontext:
Ich baue ein Plugin für ReSharper namens Agent Mulder . Die Idee hinter dem Plugin ist es, DI / IoC Container Registrierungen in Ihrer Lösung zu analysieren und ReSharper dabei zu helfen, die Verwendung von über einen DI Container registrierten Typen herauszufinden (Sie können sich ein kurzes Video ansehen, wie es funktioniert hier ).

Die Analyse der Containerregistrierung ist größtenteils unkompliziert - ich muss nur genügend Informationen finden, um zu wissen, welche konkreten Typen betroffen sind. In diesem Beispiel mit Castle Windsor: Component.For<IFoo>().ImplementedBy<Foo>() ist der resultierende Typ offensichtlich, also ist AllTypes.FromThisAssembly().BasedOn<IFoo>() - was mir gerade genug Informationen gibt, um die Betontypen, die von dieser Linie betroffen sind, zu animieren. Beachten Sie jedoch diese Registrierung in Castle Windsor:

%Vor%

( Quelle )

Hier hängt die Information von einem Prädikat ab, das nur zur Laufzeit ausgewertet wird.

Da ich alles nur statisch analysieren kann, habe ich in der Hand die ReSharper-AST-Darstellung (PSI in ReSharper genannt) des Lambda-Ausdrucks aus der Where -Klausel. Ich kann diesen AST in einen LINQ-Ausdrucksbaum konvertieren und ihn dann in einen Delegaten zusammenstellen.

Meine Idee war, die Ausgabebaugruppe (bestimmt durch den Deskriptor FromAssembly* ) über Reflektion zu laden und diesen Delegaten auf die Typen der Assembly anzuwenden, um die Typnamen zu erhalten (ich brauche nur die Namen). Dies muss jedes Mal neu bewertet werden, wenn sich auch die Baugruppe ändert (ich bin an dieser Stelle nicht über die Leistung besorgt).

Zusammenfassend: Wenn jemand nicht eine bessere Methode zur Bestimmung der vom Prädikat betroffenen Typen empfehlen könnte, würde ich gerne wissen, wie man das mit Nachdenken macht (leider hatte ich andere Metadaten-Leser nicht berücksichtigt, weil ich es getan hätte irgendwie den Lambda Ausdruck AST zu einem Prädikat des unterschiedlichen Datentyps umwandeln, und ich weiß nicht, ob es eine 1-zu-1 Umwandlung gibt).

Danke fürs Lesen. Diese Frage wird eine 500-Punkte-Prämie haben, sobald sie verfügbar ist.

    
Igal Tabachnik 07.05.2012, 11:15
quelle

2 Antworten

2

Sie müssen die Assembly laden, um die Type Instanzen zu erhalten, sodass eine separate AppDomain wie die richtige Lösung erscheint.

Sie müssen also das Prädikat Expression in das AppDomain bringen, was bedeutet, dass Sie es serialisieren / deserialisieren müssen.

Diese Anforderung wird aus verschiedenen Gründen immer häufiger. Ich habe mir das angeschaut, weil ich Linq zu Entities-Ausdrücken über einen WCF-Dienst squirten wollte.

Glücklicherweise gibt es einige vorhandene Implementierungen.

Ich habe folgendes gefunden: CodePlex - Expression Tree Serializer

Ich habe es gerade mit Types getestet, und das funktioniert:

%Vor%     
Nicholas Butler 07.05.2012, 11:50
quelle
1

Lässt die Prädikatdelegateninstanz mit dem MBR-Objekt umbrechen, der Parameter vom Typ Type wird von einer anderen Domäne ordnungsgemäß gemarshallt:

%Vor%

Erstellen Sie einen Typ zum Laden, zum Durchsuchen der Assembly und zum Zurückgeben der Ergebnisse an die Hauptdomäne:

%Vor%

Mache all das:

%Vor%     
ControlFlow 07.05.2012 13:20
quelle