Frage

Ich habe eine Frage in Bezug auf Typenkonstruktoren innerhalb eines Werttyps . Diese Frage wurde von etwas inspiriert, das Jeffrey Richter in CLR über c # 3rd ed schrieb, er sagt (auf Seite 195 - Kapitel 8), dass Sie niemals einen Typkonstruktor innerhalb eines Werttyps definieren sollten, da es Zeiten gibt, wenn der CLR nicht anrufen wird es.

so, zum Beispiel (gut ... Jeffrey Richters Beispiel eigentlich), ich kann nicht herausfinden, selbst wenn der IL anseht, warum der Typ-Konstruktor nicht im folgenden Code aufgerufen wird:

generasacodicetagpre.

Wenn Sie also die folgenden Regeln für Typ-Konstruktoren anwenden, kann ich nicht sehen, warum der oben oben genannte Werttyp-Konstruktor nicht überhaupt aufgerufen wird.

    .
  1. Ich kann einen statischen Werttyp-Konstruktor definieren, um den Anfangszustand des Typs einzustellen.
  2. Ein Typ kann nicht mehr als einen Konstruktor haben - es gibt keine Standardeinstellung.
  3. Typenkonstruktoren sind implizit privat
  4. Der JIT-Compiler prüft, ob der Typ des Typs des Typs bereits in dieser AppDomain ausgeführt wurde. Wenn nicht, dass er den Anruf in den nativen Code ausgibt, sonst nicht, da er nicht weiß, dass der Typ bereits "initialisiert" ist.
  5. Also ... ich kann einfach nicht trainieren, warum ich nicht sehen kann, dass dieses Typ-Array konstruiert ist.

    Meine beste Vermutung wäre, dass es sein könnte:

      .
    1. Die Art und Weise, wie das CLR ein Typ-Array baut. Ich hätte gedacht, dass der statische Konstruktor aufgerufen würde, wenn der erste Artikel erstellt wurde
    2. Der Code im Konstruktor initialisiert keine statischen Felder, sodass sie ignoriert wird. Ich habe mit dem Initialisieren von privaten statischen Feldern innerhalb des Konstruktors experimentiert, das Feld bleibt jedoch der Standardwert 0-Wert - daher wird der Konstruktor nicht aufgerufen.
    3. oder ... Der Compiler ist irgendwie den Konstruktor-Anruf, weil der öffentliche Int32 eingestellt wird, aber das ist eine Fuzzy-Vermutung am besten !!
    4. Best Practices usw. Vermutung, ich bin nur super von ihm fasziniert, da ich für mich selbst sehen kann, warum es nicht angerufen wird.

      edit: Ich habe auf meine eigene Frage eine Antwort hinzugefügt, nur ein Zitat dessen, was Jeffrey Richter darüber sagt.

      Wenn jemand irgendwelche Ideen hat, wäre das brillant. Vielen Dank, James

War es hilfreich?

Lösung

das Microsoft C # 4 Spec hat sich von früheren Versionen leicht geändert, und spiegelt nun das Verhalten, das wir hier sehen, genau geändert:

11.3.10 statische konstrukteure

statische Konstrukteure für Strukturen folgen die meisten der gleichen Regeln wie für Klassen. Die Ausführung eines statischen Konstruktors für einen Strukturtyp wird von der ausgelöst Erste der folgenden Ereignisse auftreten Innerhalb einer Anwendungsdomäne:

  • Ein statisches Mitglied des Strukturtyps ist referenziert.
  • Ein explizit deklarierter Konstruktor des Strukturtyps wird aufgerufen.

Die Erstellung von Standardwerten (& # 167; 11.3.4) von Strukturtypen nicht den statischen Konstruktor auslösen. (Ein Beispiel dafür ist der Anfangswert von Elementen in einem Array.)

das ECMA spec und die Microsoft C # 3 spec Beide haben ein zusätzliches Ereignis in dieser Liste: "Ein Instanzmitglied des Strukturtyps ist referenziert". So sieht es so aus, als ob C # 3 hier ein eigener Spezifikation verstoßen hat. Die C # 4-Spec wurde mit dem tatsächlichen Verhalten von C # 3 und 4 in eine nähere Ausrichtung gebracht.

bearbeiten ...

Nach weiterer Untersuchung erscheint es, dass ein ziemlich kleiner Instanz-Mitglieder-Zugriff außer direkter Feldzugriff den statischen Konstruktor auslöst (zumindest in den aktuellen Microsoft-Implementierungen von C # 3 und 4).

So sind die aktuellen Implementierungen enger mit den in den ECMA- und C # 3-Spezifikationen angegebenen Regeln als die in der C # 4-Spec-Spezifikation korreliert: Die C # 3-Regeln werden beim Zugriff auf alle Instanzmitglieder korrekt implementiert. / em> Felder; Die Regeln C # 4 sind nur richtig für den Feldzugriff.

(die verschiedenen Spezifikationen sind alle in Übereinstimmung - und scheinbar korrekt implementiert - in Bezug auf die Regeln, die sich auf den statischen Mitgliederzugang in Bezug auf den Zugriff statischer Mitglieder und explizit deklarierte Konstrukteure angeben.)

Andere Tipps

von §18.3.10 des Standards (siehe auch die C # -Programmiersprache Buch):

Die Ausführung eines statischen Konstruktors für eine Struktur wird durch die erste der folgenden Ereignisse ausgelöst, die in einem Anwendungsbereich auftreten kann:

  • ein Instanzmitglied der Struktur ist referenziert.
  • ein statisches Mitglied von Die Struktur wird referenziert.
  • ein explizit deklarierter Konstruktor des struct wird aufgerufen.

[ note : Die Erstellung von Standardwerten (& # 167; 18.3.4) der Struktur Typen löscht nicht die statische Konstrukteur. (Ein Beispiel dafür ist der Anfangswert von Elementen in einem Array.) ende note ]

Ich stimme Ihnen damit einverstanden, dass die letzten beiden Zeilen Ihres Programms jeweils die erste Regel auslösen sollten.

Nach dem Testen scheint der Konsens zu sein, dass es konsequent für Methoden, Eigenschaften, Ereignisse und Indexer löst. Das heißt, es ist korrekt für alle expliziten Instanzmitglieder außer -felder. Wenn also die C # 4-Regeln von Microsoft C # 4 für den Standard ausgewählt wurden, würde dies deren Umsetzung von hauptsächlich rechts auf Meistens falsch gehen.

das einfach als "Antwort" einfügen, damit ich teilen könnte, was Herr Richter selbst darüber schrieb (tut jemand einen Link für die neueste CLR-Spec übrigens, es ist leicht, die Ausgabe von 2006 zu erhalten, aber es ist Bit schwieriger, um den neuesten zu erhalten):

Für diese Art von Zeug ist es normalerweise besser, die CLR-Spedel anzusehen als die C # Spec. Die Clr-Spec sagt:

4. Wenn nicht gekennzeichnet ist, wird das Initialisierungsverfahren des Typs an (d. H. Auslösend durch) ausgeführt.

• Erster Zugriff auf jedes statische Feld dieses Typs oder

• Erster Aufruf einer statischen Methode dieses Typs oder

• Erster Aufruf einer einzelnen Instanz oder virtuellen Methode dieses Typs, wenn es ein Werttyp oder

ist

• Erster Aufruf eines Konstruktors für diesen Typ.

Da keiner dieser Bedingungen erfüllt ist, ist der statische Konstruktor nicht aufgerufen. Die einzigen kniffligen Teile, die aufmerksam sind, sind, dass "_x" ein Instanzfeld ist, das kein statisches Feld, und das Erstellen eines Arrays von Strukturen ist nicht nicht alle Instanzkonstruktoren an den Array-Elementen aufrufen.

Eine andere interessante Probe:

generasacodicetagpre.

update: Meine Beobachtung ist, dass der statische Konstruktor, sofern der statische Zustand nicht verwendet wird, niemals berührt wird - etwas, das die Laufzeit entscheiden scheint, und gilt nicht für Referenztypen. Dies bittet die Frage, wenn es ein Fehler ist, denn es hat wenig Auswirkungen, es ist mit dem Design, oder es ist ein anstehender Fehler.

update 2: persönlich, es sei denn, Sie machen etwas Funky im Konstruktor, um dieses Verhalten der Laufzeit niemals ein Problem zu verursachen. Sobald Sie auf den statischen Zustand zugreifen, verhält es sich richtig.

update3: weiter zu einem Kommentar von lueeh, und referenzieren von matthew flaschens Antwort, implementieren und rufen Sie Ihren eigenen Konstruktor in der Struktur auch aus, um den statischen Konstruktor aufzunehmen. Bedeutet, dass das Verhalten in einem von den drei Szenarien nicht das ist, was er auf der Dose sagt.

Ich habe gerade ein statisches Eigentum an den Typ hinzugefügt und auf das statische Anwesen zugegriffen - es heißt den statischen Konstruktor. Ohne den Zugriff auf die statische Eigenschaft erstellen Sie einfach eine neue Instanz des Typs, wurde der statische Konstruktor nicht angerufen.

generasacodicetagpre.

Eine Notiz in diesem Link gibt an, dass statische Konstruktoren nicht aufgerufen werden, wenn er einfach auf Instanzen zugreift:

http://www.jaggersoft.com/pubs/structsvsclasses.htm#default

Ich würde erraten, dass Sie ein Array Ihres Werttyps erstellen.Daher würde das neue Schlüsselwort verwendet, um den Speicher für das Array zu initialisieren.

es ist gültig zu sagen

generasacodicetagpre.

mit kein neuem Keyword überall, was im Wesentlichen das ist, was Sie hier tun.Waren SomevalType einen Referenztyp, Sie müssen jedes Element Ihres Arrays mit

initialisieren generasacodicetagpre.

Dies ist ein verrücktes Designverhalten von "Beforefieldinit" -attribut in MSIL. Es betrifft auch C ++ / CLI, ich habe einen Fehlerbericht eingereicht, in dem Microsoft sehr schön erklärt hat, warum das Verhalten so ist, warum das Verhalten so ist, und ich habe mehrere Abschnitte im Sprachstandard darauf hingewiesen, dass es nicht stimmte, um das tatsächliche Verhalten zu beschreiben . Aber es ist nicht öffentlich einsehbar. Wie auch immer, hier ist das letzte Wort von Microsoft (diskutiert eine ähnliche Situation in C ++ / CLI):

Da wir den Standard aufrufen Hier die Linie von Partition I, 8.9.5 sagt das:

wenn damals als forefieldinit markiert ist Die Initialisierungsmethode des Typs wird ausgeführt Oder irgendwann zuvor, erster Zugriff für jedes dafür definierte statische Feld Typ.

Der Abschnitt geht tatsächlich in das Detail darüber, wie eine Sprachimplementierung kann entscheiden, das Verhalten zu verhindern du beschreibst sich. C ++ / cli wählt nicht eher, dass sie dem Programmierer erlauben tun, wenn sie es wünschen.

Grundsätzlich, da der Code unten hat absolut keine statischen Felder, der Jit ist ganz einfach nicht richtig Rufen Sie statische Klassenkonstrukteure auf.

Das gleiche Verhalten ist das, was Sie sehen, obwohl in einer anderen Sprache.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top