Ausnahme beim Abrufen von Attributkonstruktorargumenten mit mehreren Enumerationsarrays

8

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:

%Vor%

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.

    
Julien Pires 15.09.2016, 12:51
quelle

3 Antworten

2

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)

%Vor%

ILDASM

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 )

%Vor%

während für

%Vor%

Sie sehen

%Vor%

CLR virtuelle Maschine

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 )

%Vor%

Möglicher Fehler

Der kritische Punkt für einen möglichen Fehler ist

%Vor%

wurde in

implementiert %Vor%

vielleicht könnte das folgende überprüft werden ...

%Vor%

Vorgeschlagene Korrektur

Sie können dieses Problem zu CoreCLR mit einem vorgeschlagenen FIX von github finden. p>     

user6996876 15.09.2016, 23:47
quelle
1

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.

    
user6996876 18.09.2016 19:24
quelle
0

Ich vermute, dass es ein .NET-Bug ist!

Aber wenn Sie eine Problemumgehung benötigen, können Sie die Konstruktorargumente in Mitglieder kopieren und auf method.GetCustomAttribute<TestAttribute>().valuesOne etc. zugreifen.

    
ubi 15.09.2016 13:03
quelle

Tags und Links