Erstellen einer Portable-Klassenbibliothek über Reflection.Emit

8

Ich schreibe einen Compiler, der .NET-Assemblies auf der Festplatte mit der System.Reflection.Emit API erzeugt. Der Compiler selbst basiert auf .NET 4.5, aber der generierte Code verweist nur auf Typen von Portable Class Libraries. Beim Versuch, eine generierte Assembly von einem Windows Phone 8-Projekt aus zu referenzieren, beschwert sich Visual Studio jedoch über A reference to a higher version or incompatible assembly cannot be added to the project .

Wenn ich die generierte Assembly in einem Decompiler öffne, kann ich sehen, dass sie auf zwei PCLs plus mscorlib 4.0.0.0 verweist, während ich weiß, dass PCLs mscorlib 2.0.5.0 referenzieren sollen.

Gibt es eine Möglichkeit, die System.Reflection.Emit API dazu zu bringen, PCLs zu generieren, oder ist meine einzige Option, nach Mono.Cecil zu migrieren?

    
Trillian 20.02.2014, 00:15
quelle

1 Antwort

4

Okay, ich werde meine eigene Frage beantworten.

Ich habe keinen Hinweis gefunden, dass die System.Reflection.Emit APIs Assemblys generieren können, die auf eine andere Version von mscorlib verweisen als die, die vom aktuellen Prozess verwendet wird. Tatsächlich fügen die APIs, die System.Type -Parameter und andere Reflektionsobjekte verwenden, vermutlich einen Verweis auf das Ergebnis der Abfrage ihrer Eigenschaft Type.Assembly hinzu, was der Version von mscorlib in Verwendung entspricht.

Portable Klassenbibliotheken unterscheiden sich jedoch nicht wesentlich von dem, was System.Reflection.Emit generiert, daher ist es möglich, die Assemblies nachträglich zu patchen, um sie "portierbar" zu machen. Haftungsausschluss : Dies erfordert Vertrautheit mit dem PE-Dateiformat und könnte unvorhergesehene Nebenwirkungen haben, aber es funktioniert für mich:

  • Verwenden Sie beim Generieren der Assembly AssemblyBuilder.SetCustomAttribute , um dieses Attribut der Assembly hinzuzufügen:

    %Vor%
  • Hier wird es skizzenhaft: Nachdem Sie AssemblyBuilder.Save aufgerufen haben, öffnen Sie einen Lese- / Schreib-Datenstrom zur generierten Assembly, gehen Sie durch die Tabellenköpfe PE, COFF, COM, CLI und Metadaten, um den% zu finden. co_de% Tabellenzeile für AssemblyRef . Ändern Sie die referenzierte Version von mscorlib auf mscorlib , fügen Sie 2.0.5.0 zu ihren Flags hinzu ("retargetable") und aktualisieren Sie ihr Token-Blob für öffentliche Schlüssel auf 0x100 .

Beachten Sie, dass Sie, wenn Sie andere Framework-Assemblys verwenden, möglicherweise auch ihre Referenzen patchen müssen (ich habe dies nicht getestet). Sonst, voilà! Die Assembly ist jetzt portabel und kann beispielsweise in einem Windows Phone-Projekt verwendet werden.

(... oder verwende einfach 0x7CEC85D7BEA7798E / Mono.Cecil ...)

Bearbeiten : Der Code, den ich verwendet habe, kann gefunden werden auf github . Dies ist ein großer Hack, so dass die üblichen Haftungsausschlüsse gelten, verwenden Sie auf eigene Gefahr.

    
Trillian 24.02.2014, 13:51
quelle