Warum brauchen wir statische Konstruktoren?

8

Zuerst habe ich eine Antwort in Was ist der Einsatz von statischen? Konstruktoren? , aber ich möchte eine Antwort in diesem Zusammenhang.

Hier ist meine C # statische Klasse:

%Vor%

Darin habe ich eine statische Variable i , die beim ersten Aufruf auf 10 initialisiert wird. Im Grunde kann es der Zweck eines statischen Konstruktors sein, aber dasselbe kann erreicht werden, ohne einen statischen Konstruktor zu deklarieren, indem static int i = 10 initialisiert wird. Das dient demselben Zweck, der nur einmal initialisiert wird.

Warum brauchen wir einen statischen Konstruktor? Oder bin ich völlig falsch darin, das Konzept oder die Verwendung von statischen Konstruktoren zu verstehen?

    
iJade 06.03.2013, 14:33
quelle

8 Antworten

22

Wenn Sie diese Klasse in eine Assembly kompilieren und dann ILSpy o.ä. verwenden, um das Ergebnis zu disassemblieren, werden Sie feststellen, dass die Initialisierung aller statischen Elemente im statischen Konstruktor ausgeführt wird.

Zum Beispiel der folgende C # -Code:

%Vor%

Produziert IL entsprechend:

%Vor%

Mit anderen Worten, direkte Initialisierung ist nur syntaktischer Zucker, der vom C # -Compiler bereitgestellt wird. Unter der Haube ist noch ein statischer Konstruktor implementiert.

    
Frédéric Hamidi 06.03.2013, 14:38
quelle
6

Nun, in Ihrem Beispiel wird es zwar nicht benötigt, aber stellen Sie sich vor, wenn i value aus einer Datenbank, Textdatei oder einer anderen Ressource gelesen werden muss? Möglicherweise benötigen Sie etwas wie:

%Vor%

Jetzt ist es nicht möglich, Ihr statisches Feld zu deklarieren und zu initialisieren, Sie werden besser mit einem statischen Konstruktor bedient

    
RMalke 06.03.2013 14:38
quelle
1

Sie benötigen in diesem Szenario keinen statischen Konstruktor.

%Vor%

und

%Vor%

sind funktional identisch.

    
Roy Dictus 06.03.2013 14:38
quelle
1

Die Antwort ist auch in Ihrer verknüpften Frage:

  

[...] insbesondere nützlich zum Lesen erforderlicher Konfigurationsdaten in schreibgeschützte Felder usw.

     

Es wird beim ersten Mal automatisch von der Laufzeitumgebung ausgeführt (die genauen Regeln dort & gt; sind kompliziert (siehe "beforefieldinit") und werden subtil zwischen CLR2 und CLR4 geändert). & gt; Wenn Sie die Reflektion nicht missbrauchen, läuft sie garantiert höchstens einmal (auch wenn zwei Threads gleichzeitig ankommen).

Sie könnten viel kompliziertere Dinge in einem statischen Konstruktor initialisieren, wie das Einrichten einer Datenbankverbindung und so weiter. Wenn es Sinn machen würde, ist eine andere Sache ...

    
Jobo 06.03.2013 14:39
quelle
1

Ein statischer Contructor ist sinnvoll, wenn Sie einige Aktionen innerhalb des Konstruktors ausführen müssen und Sie eine eindeutige Instanz in der Anwendung wünschen. Zum Beispiel:

%Vor%

In dem von Ihnen erläuterten Szenario benötigen Sie keinen statischen Konstruktor explizit.

Sie können auch das Singleton-Muster anwenden, um diesen Zweck zu erreichen.

    
Daniel Peñalba 06.03.2013 14:39
quelle
0

Ein statischer Konstruktor dient nicht nur zum Initialisieren von Variablen, sondern auch zum Erstellen von Objekten, die für Ihre (statische) Klasse (oder Umgebung) notwendig sind, um Methoden für diese Objekte oder Ihre Klasse selbst zu verwenden und aufzurufen.

    
bash.d 06.03.2013 14:39
quelle
0

Sie können Felder an Ort und Stelle nur mit Kompilierzeitkonstanten (Ihrem Fall) initialisieren. Aber im statischen Konstruktor können Sie etwas Code ausführen (z. B. Konfigurationsdatei lesen).

    
Sergey Berezovskiy 06.03.2013 14:37
quelle
0

Ein noch nicht erwähnter Faktor ist, dass es einen semantischen Unterschied zwischen einem statischen Konstruktor (geschrieben mit Konstruktorsyntax) und dem Aufruf von foo() gegenüber einem statischen Feldinitialisierer gibt. Insbesondere wenn ein Typ einen statischen Konstruktor hat, der mit der Konstruktorsyntax geschrieben wurde, wird garantiert, dass dieser Konstruktor den ersten Zeitcode aufgerufen wird, der diesen Typ "verwenden" würde; Es wird vorher nicht aufgerufen und auch nicht aufgerufen, wenn der Typ nicht verwendet wird. Im Gegensatz dazu garantiert .NET zwar, dass die statischen Feldinitialisierer eines Typs vor dem Zugriff auf seine statischen Felder ausgeführt werden und nicht mehr als einmal ausgeführt werden. .NET kann jedoch solche statischen Initialisierer beim ersten Auftreten eines Typs könnte verwendet werden. Betrachten Sie zum Beispiel:

%Vor%

Wenn der Just-In-Time-Compiler den obigen Code findet, someClass noch nie verwendet wurde und ein Konstruktor mit der statischen Konstruktorsyntax deklariert wurde, lautet der resultierende Maschinencode etwa:

%Vor%

Ausführen des if-check innerhalb der Schleife. Wenn dagegen Feldinitialisierungen, aber keine Deklaration im Konstruktorstil stattgefunden hätten, würde der JIT wahrscheinlich die statische Konstruktion von someClass ausführen, bevor er den Code ausführt, wodurch die if -Kontrolle nicht mehr darin enthalten sein muss.

    
supercat 28.10.2013 22:53
quelle

Tags und Links