Ich spielte mit Attributen und Überlegungen, als ich einen seltsamen Fall fand. Der folgende Code gab mir eine Ausnahme zur Laufzeit, wenn ich versuche, Konstruktorargumente von benutzerdefinierten Attributen zu erhalten.
%Vor% Das Problem scheint die Parameter zu sein, die an den Test
Attributkonstruktor übergeben wurden. Wenn einer von ihnen null ist, löst ConstructorArguments
eine Ausnahme aus. Die Ausnahme ist ArgumentException
mit name
als Ausnahmebedingungsnachricht.
Hier ist der Stack-Trace von ConstructorArguments
call:
Wenn ich für jeden Parameter einen Nicht-Null-Wert festlege, gibt es keine Ausnahme. Es scheint nur mit enum array zu passieren. Wenn ich einen weiteren Parameter wie string hinzufüge und sie auf null setze, gibt es kein Problem.
Eine Lösung könnte darin bestehen, immer einen Wert wie ein leeres Array zu übergeben, aber hier möchte ich die Fähigkeit, einen Nullwert zu übergeben, behalten, weil es in meinem Fall eine besondere Bedeutung hat.
Dies hat mit der Struktur des Blobs zu tun wo das benutzerdefinierte attribut e angegeben ist.
Array-Werte beginnen mit einer Ganzzahl, die die Anzahl der Elemente angibt Im Array werden dann die Item-Werte zusammengehandelt.
Ein Null-Array wird mit einer Länge von -1 dargestellt.
Ein enum-Argument wird mit dem Byte 0x55 gefolgt von a dargestellt Zeichenfolge, die den Namen und die Assembly des Aufzählungstyps angibt.
Leider passiert, wenn Sie ein Array von enum als null übergeben, dass der enum Name verloren ist.
In Bezug auf natives Debugging ist dies der relevante Quellcode
%Vor%Und so wird der c.tor-Parameter instanziiert
%Vor% Das Problem ist, dass der enum-Wert einfach mit dem zugrunde liegenden Wert dargestellt wird (im Grunde ein int):
Die CLR-Implementierung ( RuntimeType
) muss die Attributkonstruktorsignatur betrachten, um sie zu interpretieren, aber benutzerdefinierte Attributsignaturen unterscheiden sich ein wenig von anderen in a kodierten Signatortypen .NET Assembly.
Genauer gesagt, ohne eine definierte encodedArrayType
(von GetElementType
), wird das folgende wenn false (und enumName
bleibt null)
Sie finden die .custom-Instanz des Main von ildasm
im Falle von
%Vor% ist es (beachte die FF FF FF FF
bedeutet eine Array-Größe von -1 )
während für
%Vor%Sie sehen
%Vor%Schließlich haben Sie eine Bestätigung, dass der CLR virtuelle Computer liest den Blob eines benutzerdefinierten Attributs nur dann in ein Array, wenn die Größe von -1
abweicht %Vor% Zusammenfassend werden in diesem Fall die Konstruktorargumente nicht innerhalb von C # instanziiert, so dass sie nur vom Konstruktor selbst abgerufen werden können: tatsächlich wird das benutzerdefinierte Attribut (über CreateCaObject
) in erstellt die virtuelle CLR-Maschine durch Aufrufen ihres Konstruktors mit unsicheren Zeigern (direkt auf das Blob )
Der kritische Punkt für einen möglichen Fehler ist
%Vor%wurde in
implementiert %Vor%vielleicht könnte das folgende überprüft werden ...
%Vor%Sie können dieses Problem zu CoreCLR mit einem vorgeschlagenen FIX von github finden. p>
In meiner vorherigen Antwort habe ich herausgefunden, wie der Name Enum durch den aktuellen .Net-Standardcode von mscorlib verloren geht ... und so die Ursache dieser Ausnahme
Nun möchte ich nur ein konkretes benutzerdefiniertes Reengineering der Konstruktorargumente basierend auf Ihrer spezifischen Test-Enumerationsdefinition zeigen (daher ist das Folgende nicht Standard genug, um als tatsächliche Verbesserung vorgeschlagen zu werden, aber es ist nur ein ergänzender Teil der Erklärung )
%Vor% So wird results
eine Liste der Test[]
Argumente enthalten, die im Konstruktor verwendet werden.
Tags und Links .net c# system.reflection