Ich schreibe eine einfache Desktop-Client / Server-Anwendung in C #. Für selbstlernende Zwecke habe ich ein eigenes Serialisierungssystem für die Nachrichten (definiert als Klassen) erstellt, die zwischen den beiden Anwendungen über eine tcp / ip-Socket-Verbindung hin und her gesendet werden. Das System verwendet die Reflexion zur Initialisierungszeit, um Serialisierungs- / Deserialisierungsmethoden für jeden Nachrichtentyp durch Ausgeben von IL zu erstellen.
Die erste Version dieses Systems verwendete DynamicMethod und übergab dem Konstruktor true, damit die generierte IL (die auf beliebigen Feldern im Nachrichtentyp operiert) die Zugriffsberechtigungen ignoriert. Das funktionierte und die Leute freuten sich, aber ich war unzufrieden damit, wie schmerzhaft das Debugging der resultierenden Funktionen war. Also beschloss ich, DynamicMethod zu entfernen und die * Builder-Klassen zu verwenden, um eine dynamische Assembly zu erstellen, die ich optional auf einem Datenträger speichern und mit einem Werkzeug wie .NET Reflector untersuchen konnte.
Ich habe das System umstrukturiert und dann ein bisschen von einer Ziegelmauer getroffen. Immer wenn eine der neuen Serialisierungsfunktionen versucht, auf ein privates Feld oder eine private Methode in einem meiner Nachrichtentypen zuzugreifen, erhalte ich eine FieldAccessException oder eine MethodAccessException. Nach vielem Googlen und Zähneknirschen, glaube ich, habe ich das Problem auf eine der Berechtigungen eingeschränkt; Insbesondere denke ich, dass meine dynamisch erstellte Assembly die ReflectionPermissionFlag.MemberAccess-Berechtigung in Bezug auf die aufrufende / konstruierende Assembly fehlt (wo alle reflektierten Typen sitzen).
Leider kann ich nicht herausfinden, wie der Prozess der dynamischen Assemblierung so geändert werden kann, dass die Assembly die Reflektionsberechtigung zurück in die erschaffende Assembly hat. Die Berechtigungsparameter für DefineDynamicAssembly scheinen mit dem Einschränken der Berechtigung verbunden zu sein, ohne sie zu gewähren, was uns den Parameter Evidence zurücklässt. Beweise scheinen sich magisch in eine Reihe von Berechtigungen zu übersetzen, aber ich kann keine nützlichen Beispiele oder Erklärungen dafür finden, wie dies geschieht.
Meine Fragen sind also:
(1) Korrigiere ich meine Annahme, dass mein Problem ein Mangel an Berechtigungen für meine dynamisch erstellte Assembly ist?
(2) Wenn ja, wie erteile ich als rufende Versammlung der dynamischen Versammlung die notwendige Erlaubnis?
Der aktuelle Code für die dynamische Assemblierung:
%Vor%Beachten Sie, dass mein Projekt auf .NET 3.5 abzielt; Die Dokumentation behauptet, dass .NET 4.0 einen anderen Sicherheitsbegriff verwendet und die auf Evidence / PemissionSet basierenden Methoden in DefineDynamicAssembly nicht mehr unterstützt.
Um ein konkretes Beispiel zu geben: Angenommen, ich hätte eine Klasse wie:
%Vor%Wenn mein serialization-System während der init-Reflektion darauf stößt, würde grob mit type = typeof enden (cut-and-paste ist hier nicht möglich) (CTestMessage):
%Vor%Wenn die Methode anschließend ausgeführt wird, wird die Ausnahme für die LDFLD-Anweisung ausgelöst.
Bearbeiten: Mehr Details zeigen, dass das, wonach ich frage, möglich sein sollte. Nehmen Sie das obige Code-Snippet, aber ersetzen Sie MethodBuilder durch DynamicMethod:
%Vor%Erstellen Sie jetzt einen Delegaten aus der DynamicMethod:
%Vor%Dieser Delegat wird JITed und führt ordnungsgemäß ohne Fehler aus:
%Vor%Das Problem ist, dass das Feld privat ist. Wenn Sie es öffentlich machen, funktioniert die externe Methode gut. Die DynamicMethod-Methode funktioniert trotz ihrer privaten Eigenschaft, da die CLR offenbar den Zugriff innerhalb eines Moduls auf private Felder zulässt - von der SSCLI aus clsload.cpp@2659:
%Vor%Um auf private Felder extern zuzugreifen, müssen Sie wahrscheinlich eine Reflexion verwenden, die den Zweck ziemlich vereitelt.
Bearbeiten Um zu verdeutlichen, was Sie gepostet haben, verwendet Reflektion, um die Assembly zu erstellen, aber die von Ihnen generierte IL verwendet keine Reflektion, um auf das Feld zuzugreifen - das ist ein einfacher alter direkter Feldzugriff, der explodiert weil das Zielfeld extern und privat ist. Sie müssten IL senden, die selbst Type.GetField () verwendet. GetValue () was ziemlich sinnlos ist.
Ja, dynamische Assemblies erlauben keinen solchen Zugriff, weder in .NET 3.5 noch in 4+. Ich hatte das gleiche Problem. Meine Problemumgehung besteht darin, den eigentlichen IL-Emitting-Code in eine ILGenerator-Funktion zu zerlegen und sie zweimal mit anderen Argumenten gleich zu benennen, einmal (optional) mit einem ILGenerator aus einer Methode in einer dynamischen Assembly, die ich auf Festplatte speichern würde peverify / ildasm / etc. und einmal mit einem ILGenerator von einer DynamicMethod. Auf diese Weise wird identische IL in beide Methoden emittiert.
Tags und Links .net c# reflection cil