2013-03-06 15 views
8

Zuerst bekam ich eine Antwort in What is the use of static constructors?, aber ich möchte eine Antwort in diesem Zusammenhang.Warum brauchen wir statische Konstruktoren?

Hier ist meine C# statische Klasse:

public static class BasicClass 
{ 
    static int i = 0; 
    static BasicClass() 
    { 
     i = 10; 
    } 

    public static void Temp() 
    { 
     //some code 
    } 


    public static void Temp1() 
    { 
     //some code 
    } 
} 

Innerhalb dieses Ich habe eine statische Variable i, die auf 10 initialisiert wird, wenn es zuerst genannt wird. Es kann also grundsätzlich der Zweck eines statischen Konstruktors sein, aber dasselbe kann erreicht werden, ohne einen statischen Konstruktor zu deklarieren, indem die static int i = 10 initialisiert wird, die denselben Zweck erfüllt, der nur einmal initialisiert wird.

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

+2

Was ist, wenn Ihr Programm eine Konfigurationsdatei verwendet? Sie möchten Ihre Konfiguration in statischen Variablen speichern, aber Sie müssen diese zuerst aus der Datei lesen, und wenn die Datei nicht existiert (oder Sie sie aus anderen Gründen nicht öffnen können), werden Sie das tun möchte diese Konfigurationen auf ihre Standardwerte setzen. Dafür kann ein statischer Konstruktor ** verwendet werden. – Nolonar

Antwort

22

Wenn Sie diese Klasse in eine Assembly kompilieren, dann verwenden Sie ILSpy oder ähnliches, um das Ergebnis zu disassemblieren. Sie werden feststellen, dass die statische Element-Initialisierung im statischen Konstruktor ausgeführt wird.

Zum Beispiel ist der folgende C# Code:

public static class BasicClass 
{ 
    static int i = 10; 
} 

Werden IL produzieren äquivalent zu:

public static class BasicClass 
{ 
    static int i; 

    static BasicClass() 
    { 
     i = 10; 
    } 
} 

Mit anderen Worten, ist die direkte Initialisierung nur syntaktischer Zucker durch die C# Compiler zur Verfügung gestellt. Unter der Haube ist noch ein statischer Konstruktor implementiert.

+0

Wäre es in diesem Fall nicht genug, wenn C# die statische Elementinitialisierung unterstützt (die tatsächlich in einen statischen Konstruktor kompiliert würde), aber nicht die tatsächlichen statischen Konstruktoren? – svick

+1

@svick, das wäre wohl kontraproduktiv. Manchmal müssen Sie für eine Klasse global weniger Operationen als die Elementinitialisierung (z. B. einfache Schleifen und Verzweigungen) ausführen. Warum sollte die Unterstützung für ein Feature entfernt werden, das in der CLR verfügbar ist und nur benötigt wird, dass ein statischer Konstruktor niemals auslöst? –

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).

1

Sie benötigen in diesem Szenario keinen statischen Konstruktor.

static BasicClass() 
{ 
    i = 10; 
} 

und

static int i = 10; 

sind funktional identisch.

6

Nun, in Ihre Beispiel ist es in der Tat nicht erforderlich, aber und stellen Sie sich vor, wenn i Wert aus einer Datenbank, Textdatei oder einer anderen Ressource gelesen werden muss? Unter Umständen müssen Sie so etwas wie:

static BasicClass() 
{ 
    using (SomeConnection con = Provider.OpenConnection()) 
    { 
     try 
     { 
      // Some code here 
     } 
     catch 
     { 
      // Handling expeptions, setting default value 
      i = 10; 
     } 
    } 
} 

Jetzt ist es nicht möglich ist, Ihre statischen Feld zu deklarieren und initialisieren, sind Sie besser bedient

0

Ein statischer Konstruktor einen statischen Konstruktor das dient nicht nur dem Zweck, Initialisieren von Variablen, aber auch Erstellen von Objekten, die notwendig sind, damit Ihre (statische) Klasse (oder Umgebung) funktioniert und Methoden für diese Objekte oder Ihre Klasse selbst aufruft.

1

Die Antwort ist auch in Ihrer verknüpften Frage:

[...] nützlich insbesondere für die erforderlichen Konfigurationsdaten in Nur-Lese-Felder zu lesen, usw.

Es wird automatisch von der Laufzeit beim ersten Mal ausgeführt (die genauen Regeln dort sind kompliziert (siehe "beforefieldinit") und subtil geändert zwischen CLR2 und CLR4). > Wenn Sie die Reflektion nicht missbrauchen, wird garantiert, dass sie höchstens einmal läuft (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 ...

1

Ein statischer Contructor hat Sinn, wenn Sie ausführen müssen einige Aktionen innerhalb des Konstruktors und Sie möchten eine eindeutige Instanz in der Anwendung. Beispiel:

In dem Szenario, das Sie erläuterten, benötigen Sie keinen statischen Konstruktor explizit.

Sie können auch die singleton pattern anwenden, um diesen Zweck zu erreichen.

+3

-1, statische Konstruktoren können keine Parameter haben. –

+5

Es ist gefährlich, so etwas in einem statischen Konstruktor zu tun. Wenn die Initialisierung eine nicht abgefangene Ausnahme auslöst, gibt es keine einfache Möglichkeit, sie abzufangen, und der Typ kann dann * nie * in diese App-Domäne geladen werden. –

0

Ein Faktor noch nicht erwähnt ist, dass es einen semantischen Unterschied zwischen einem statischen Konstruktor (geschrieben mit Konstruktorsyntax) foo() im Gegensatz zu 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. Obwohl .NET garantiert, dass die statischen Feldinitialisierer eines Typs ausgeführt werden, bevor auf statische Felder zugegriffen wird, und .NET nicht mehr als einmal ausgeführt wird, kann .NET solche statischen Initialisierer zum ersten Mal ausführen, wenn es einen Typ für möglich hält gewöhnen. Betrachten Sie zum Beispiel:

if (someCondition()) 
    for (i=0; i<100000000; i++) 
    someClass.someStaticField++; 

Wenn bei den Just-In-Time-Compiler den obigen Code treffen, hat someClass nie benutzt worden, und es hat erklärt, ein Konstruktor statische Konstruktor Syntax, der resultierende Code Maschine etwas sein wird, wie :

if (someCondition()) 
    for (i=0; i<100000000; i++) 
    { 
    if (someClass.hasBeenInitialized) 
     someClass.runConstructor(); 
    someClass.someStaticField++; 
    } 

Durchführung der if-check innerhalb der Schleife. Wenn dagegen Feldinitialisierungen, aber keine Deklaration im Konstruktortyp stattgefunden hätten, würde das JIT wahrscheinlich die statische Konstruktion von someClass ausführen, bevor der Code ausgeführt wird. Dadurch entfällt die Notwendigkeit, die if-Prüfung darin aufzunehmen.