Ist das Backing-Feld eines Compiler-generierten Ereignisses immer garantiert denselben Namen wie das Event?

8

C # ermöglicht es uns benutzerdefinierte Ereignisaccessoren zu erstellen .

%Vor%

Wenn Sie sie nicht angeben, erstellt der Compiler sie für Sie . C # -Sprachspezifikation:

  

Beim Kompilieren eines feldähnlichen Ereignisses erstellt der Compiler automatisch   Speicher, um den Delegaten zu halten, und erstellt Accessoren für das Ereignis, das   Hinzufügen oder Entfernen von Ereignishandlern zum Delegatenfeld.

Der dekompilierte Quellcode mit dotPeek für ein einfaches public event Action Public; sieht folgendermaßen aus:

%Vor%

Bemerkenswert ist, dass das Feld und das Ereignis denselben Namen verwenden . Dies hat dazu geführt, dass einige Personen zu dem Schluss kommen, dass Sie Informationen zum Hintergrundfeld während der Reflexion finden können, indem Sie das Feld in der Klasse nachschlagen mit dem gleichen Namen wie das Ereignis. Ich habe das folgendermaßen umgesetzt:

%Vor%

Das funktioniert, wirft aber die Frage auf: Ist das Hintergrundfeld eines vom Compiler erzeugten Ereignisses immer garantiert der gleiche Name wie das Ereignis?

Es ist nicht möglich, benutzerdefinierte Ereignisaccessoren zu erstellen, die mit Visual Studio auf einen Delegaten mit demselben Namen zugreifen. Dies führt zu der Nachricht: "Mitglied mit demselben Namen ist bereits deklariert." Ich frage mich, ob Sie zu dem Schluss kommen könnten, dass ein Ereignis, für das kein unterstützender Delegat mit demselben Namen verfügbar ist, ein Ereignis mit benutzerdefinierten Werten ist Accessoren.

    
Steven Jeuris 23.03.2012, 22:43
quelle

3 Antworten

9
  

Ist das Backing-Feld eines Compiler-generierten Ereignisses immer garantiert denselben Namen wie das Event?

Jon und Marc stimmen völlig mit "Nein".

Dies ist ein undokumentiertes Implementierungsdetail des Compilers, das explizit in der Spezifikation als solches aufgeführt ist und jederzeit geändert werden kann.

In der Praxis wird sich dies wahrscheinlich nicht ändern. Wir verwenden die Tatsache, dass das Feld und das Ereignis denselben Namen haben wie die einfachste Möglichkeit, sie im Compiler logisch miteinander zu verknüpfen.

  

Es ist nicht möglich, benutzerdefinierte Ereignisaccessoren zu erstellen, die mit Visual Studio auf einen Delegaten mit demselben Namen zugreifen. Dies führt zu der Nachricht: "Mitglied mit demselben Namen ist bereits deklariert."

Korrigieren.

  

Ich frage mich, ob Sie daraus schließen können, dass jedes Ereignis, für das kein unterstützender Delegat mit demselben Namen verfügbar ist, ein Ereignis mit benutzerdefinierten Zugriffsmethoden ist.

Ich würde mich nicht wohl fühlen, eine solche Schlussfolgerung zu machen. Sie könnten diese Schlussfolgerung ziehen, wenn Sie wüssten, dass die betreffende Assembly vom C # -Compiler ausgegeben wurde. Aber wir sind nicht das einzige Spiel in der Stadt, wenn es darum geht, Baugruppen zu emittieren. Du kannst mit ILDASM ziemlich komische Sachen machen.

Darf ich fragen, warum Sie dieses Zeug wissen wollen? Ich stimme Marc zu; Wenn Sie über Reflection auf ein Feld zugreifen, tun Sie wahrscheinlich etwas falsches. Sie sollten in der Lage sein, auf das Feld innerhalb der Klasse zuzugreifen, kein Problem (weil es nur ein privates Feld ist), und von außerhalb der Klasse haben Sie nichts damit zu tun, die privaten Implementierungsdetails einer anderen Klasse zu betrachten. Es ist besonders ungeheuerlich, Reflektionen zu verwenden, um die Thread-Sicherheit der Accessoren zu umgehen. Diese Accessoren sind zu Ihrem Schutz da; lauf nicht herum.

    
Eric Lippert 23.03.2012, 23:08
quelle
6

Nein - aus der Spezifikation C # 4 (Abschnitt 10.8.1):

  

Innerhalb der Klasse X werden Verweise auf Ev kompiliert, um stattdessen auf das verborgene Feld _ Ev zu verweisen. Der Name " _Ev" ist beliebig; Das versteckte Feld könnte einen beliebigen Namen oder keinen Namen haben.

Obwohl die Kompatibilität mit dem Quellcode gewährleistet ist, gibt es keine Garantie für den Namen des generierten Feldes. (In der Praxis würde ich nicht erwarten, dass sich dies im MS-Compiler bald ändern wird - aber es ist nicht garantiert, also sollten Sie keine Annahmen machen.)

    
Jon Skeet 23.03.2012 22:48
quelle
5

Die Implementierung eines Ereignisses ist ein Compiler-Implementierungsdetail und unterscheidet zwischen Compilern (MS c # 4 hat eine andere Implementierung als MS c # & lt; 4, und selbst die MS- und ECMA-Spezifikationen stimmen nicht überein).

Persönlich würde ich sagen: Wenn Sie über Reflektion auf das Backing-Feld zugreifen müssen, verwenden Sie wahrscheinlich keine Ereignisse richtig.

    
Marc Gravell 23.03.2012 22:49
quelle