Holen Sie sich die Baugruppenreferenz ohne Reflektion oder einen bekannten Typ

8

In meinem aktuellen Framework-Design durchsuche ich alle Arten von spezifischen Assemblys und arbeite basierend auf den gefundenen Typen. Die durchsuchten Assemblys werden von der Anwendung bootstrapper / initializer bestimmt. Die Assemblys sind in kompiliert, so dass sie stark referenziert werden können über: typeof(SomeTypeInTheAssembly).Assembly . Das ist gut, weil der Bootstrapper-Code einen starken Verweis auf einen Typ in der Assembly hat und es keine Fummelei mit vollständig qualifizierten Namen als Inline-Strings gibt, die manuell aktualisiert werden müssen, wenn sich der qualifizierte Name der Assembly ändert. Aber ich mochte es nicht, einen völlig unabhängigen Typ in der Assembly zu referenzieren und davon abhängig zu sein, dass dieser Typ da ist. (Was passiert, wenn es in eine andere Assembly verschoben wird? Was passiert, wenn wir den Typ verwerfen / löschen? Ändern Sie seinen Namespace?) Im Code sieht es auch ein bisschen komisch aus:

%Vor%

Jetzt habe ich in meinem Bootstrapping-Code eine direkte Abhängigkeit (obwohl eine ziemlich triviale Abhängigkeit) für GraphingCalculator , die nichts mit der Bootstrap-Stufe zu tun hat (und als GraphingCalculator hat sie sicherlich nichts mit dem Erhalt von Assembly-Referenzen zu tun) ). Um dies zu vermeiden, habe ich in jeder Assembly, die ich auf diese Weise verwenden möchte, eine Klasse in ihre Wurzel eingefügt:

%Vor%

Was nicht so schlimm ist, denn dann sieht mein Bootstrapping-Code so aus:

%Vor%

Aber jetzt habe ich etwa ein Dutzend Assemblies mit dieser AssemblyReference -Klasse kopiert / eingefügt und ich erwarte nur, dass es weiter wächst, während Anwendungen auf dem Framework aufgebaut werden. Meine Frage ist also, gibt es eine nette Möglichkeit, die AssemblyReference -Klassenduplizierung zu vermeiden und trotzdem programmgesteuert Assemblyverweise an das Basisframework zu übergeben, aber die Unschärfe zu vermeiden, auf einen beliebigen / nicht verwandten Typ in der Zielassembly zu zeigen? Meine Googlings scheinen mir zu sagen, dass es keine API oder Sprachfunktion gibt, die mich stark auf eine Assembly verweisen lässt (wie typeof für Klassen), aber ich hoffe, dass jemand hier eine bessere Lösung gefunden hat als ich Duplizierung von Klassen / Codes. Außerdem ist der Code manchmal gegen Silverlight kompiliert, daher weiß ich, dass dies dazu führen kann, dass einige API / Techniken eingeschränkt werden. Danke!

EDIT: Nur um einen weiteren Schraubenschlüssel hinzuzufügen, basierend auf der Antwort des "Coon", sollte ich erwähnen, dass ich nicht immer die gleichen Baugruppen lade. Zum Beispiel könnte ich eine "CarBuilding" -Montage haben, die für einige Anwendungen, aber nicht für alle anwendbar ist. Es liegt an den Bootstrappern, mir zu sagen, welche sie verwenden möchten (zusammen mit den benutzerdefinierten, die der Entwickler einsetzt).

EDITx2: Um Jon Skeets Frage zu beantworten: Clients (oder wir intern) werden alle Projekte / DLLs erstellen, die sie für ihre Anwendung unterstützen möchten. Diese Projekte werden wiederum auf das interne Rahmenwerk Bezug nehmen. Ihre Projekte können Ressourcen (3D-Dateien, Bilder, Text, Lokalisierung usw.) und plugin-esque Klassen enthalten (sie implementieren Skripte, die wir entdecken und bei Bedarf während der Laufzeit der Anwendung instanziieren / ausführen) . Darüber hinaus stellt unser System optionale Module (DLLs) bereit, die wiederverwendbare Plugins / Inhalte enthalten, die Kunden (oder uns) bei der Erstellung spezifischer Anwendungen nutzen können. So sehen Sie vielleicht eine Projektstruktur wie:

%Vor%

Der Bootstrapper projiziert Verdrahtungsabhängigkeiten und stellt bereit, welche Projekte / DLLs (Assemblies) dem Basisframework zur Erkennung bereitgestellt werden sollen. Beachten Sie, dass "MyApp" in diesem Fall ein eigenes Mini-Framework und freigegebene Ressourcen sowohl für Android- als auch für Silverlight-Builds verwendet, aber beide über eigene Referenzen verfügen, die unabhängig voneinander sind. Die Silverlight nutzt die BaseFrameworkGraphingModule und sie haben ihre eigenen Ressourcen für die Plattform.

So in den Bootstrappern in den Projekten aussehen etwas (wenn auch vereinfacht):

%Vor%

So wird für jede Anwendung, die auf dem Basisframework erstellt wird, ein Bootstrapper erstellt, der angibt, welche Assemblys einbezogen werden sollen (und einige andere irrelevante Verdrahtungsarbeiten). Um die Frage spezifisch zu beantworten, enthält das Projekt Kompilierungsreferenzen für jede benötigte Assembly (dies stellt eine doppelte Aufgabe dar, da sichergestellt wird, dass alle DLLs für Android / Silverlight bereitgestellt werden), da sie nicht dynamisch auf das Smartphone oder die Silverlight App des Benutzers heruntergeladen werden aber im ersten Download verpackt. Ihre Frage, wie die Bootstrapper welche Baugruppen zu verwenden wissen, weiß der Entwickler und stellt die notwendigen FrameworkAssemblyReader.Read Aufrufe. Ich hoffe das hilft! Danke, dass Sie sich die Zeit genommen haben, es anzusehen. Ich habe das Gefühl, ich mache zu viel aus dem Nichts (oder vermisse eine viel bessere Lösung / Design insgesamt).

Schließlich habe ich (dumm) vergessen zu erwähnen, dass wir auch gegen Mono für Android und in naher Zukunft für WPF kompilieren. WinRT ist eine wahrscheinliche Ergänzung in der Zukunft, aber ich werde glücklich sein, diese Brücke zu überqueren, wenn wir dazu kommen.Im Allgemeinen macht es mir jedoch nichts aus schrecklich , wenn jeder auf seine eigene Weise mit seinen eigenen Plattform-Features kompiliert wird, wenn verschiedene Plattformen die Assembly-Referenzen anders einbeziehen. obwohl es schön wäre, wenn es eine einheitliche Syntax zwischen den Plattformen gäbe.

EDITx3: Ja, noch eins. Ich habe erwähnt, aber nicht mit einem Beispiel klargestellt, dass nicht alle Projekte vom Basisrahmen gelesen werden müssen oder sollen. Beispiel: Dienst- oder Geschäftslogikprojekte mit Code, der für das Basisframework nicht relevant ist, aber für die Clientanwendung relevant ist. Also aus dem obigen Beispiel:

%Vor%

MyCompanySharedUtilities könnte von MyAppGUI_Silverlight und MyAppFramework genutzt werden, aber der Entwickler führt es möglicherweise nicht durch FrameworkAssemblyReader.Read , weil es nur proprietäre Implementierungen einiger Mathe- oder Geschäftsregeln enthält.

    
Chris Sinclair 26.06.2012, 18:54
quelle

1 Antwort

4

Ich bin nicht genau sicher, wie Sie erwarten, dass Ihre Kunden diesen Code verwenden, daher mag dieser Vorschlag irrelevant sein, aber wäre es nicht sinnvoller, die Setup-Funktion aufzugeben (zumindest vor dem Client zu verstecken) ) und eine Art Konfigurationsdatei verwenden?

%Vor%

Laden Sie die Baugruppen aus der Konfigurationsdatei. Mit einem Schlüssel müssen Sie die Anwendung nicht aktualisieren, wenn sich der vollständig qualifizierte Name ändert. Aktualisieren Sie einfach die Konfigurationsdatei (und lassen Sie den Schlüssel unverändert).

Dies ist im Grunde der Ansatz, den Visual Studio mit seinen Projektdateien verwendet. Hier ist ein Beispiel aus einem meiner VB-Projekte:

%Vor%

BEARBEITEN:

Hier ist ein Gedanke ... Was wäre, wenn Sie Reflection.Emit verwenden würden, um eine Assembly aus der XML-Konfigurationsdatei zu generieren? Sie könnten der generierten Assembly eine Stub-Klasse hinzufügen, die Ihr Kernprojekt zum Erstellen einer festen Referenz auf die generierte Assembly verwenden könnte. Mit Reflection können Sie jede Referenz-Assembly (in der XML-Datei) durchsuchen, um einen festen Verweis auf ein Objekt zu erstellen in den referenzierten Assemblys. Sie müssten die Assembly neu generieren, wenn sich eine der referenzierten Assemblys ändert. Es wären jedoch keine Codeänderungen erforderlich. Sie können sogar den Assembly-Generierungscode in Ihrem Kernprojekt erstellen, sodass Benutzer ihre Projekte nach Bedarf aktualisieren können.

    
JDB 03.07.2012, 13:34
quelle