2010-07-01 8 views
5

Welche statische Klasse initialisiert zuerst, wenn wir in unserem Projekt noch eine statische Klasse haben?Welche statische Klasse initialisiert zuerst?

Zum Beispiel: Unter dem Code gibt Null Ausnahme.

class Program 
    { 
     static void Main(string[] args) 
     { 
      First.Write(); 
      Second.Write(); 
     } 
    } 
    static class First 
    { 
     public static int[] firstArray = new int[20]; 
     public static int[] secondArray = Second.secondArray; 
     public static void Write() 
     { 
      Console.WriteLine(firstArray.ToString()); 
      Console.WriteLine(secondArray.ToString()); 
     } 
    } 
    static class Second 
    { 
     public static int[] firstArray = First.firstArray; 
     public static int[] secondArray = new int[30]; 
     public static void Write() 
     { 
      Console.WriteLine(firstArray.ToString()); 
      Console.WriteLine(secondArray.ToString()); 
     } 
    } 

Wenn Sie darauf achten, werden Sie feststellen, dass, wenn First Klasse selbst initialisieren wird so secondArray Bereich der Second null sein würde. Aber wenn Second Klasse würde zuerst initialisiert werden, so Second Klasse firstArray wäre null. Ich versuche zu sagen, dass das, was initialisiert, zuerst andere Ergebnisse bringt.

Ich denke, dass es abstrakte Frage zu meinem Projekt ist. Ich stoße darauf und versuche zu verstehen, warum ich unerwartete Ergebnisse erhalte.

Antwort

10

First beginnt, zu initialisieren firstArray zuweisen, dann merken, dass es Second um initialisiert werden muss den Anfangswert von secondArray zu erhalten.

Second beginnt mit der Initialisierung und merkt dann, dass First initialisiert werden muss. Die CLR wird dann jedoch feststellen, dass First bereits Initialisierung im aktuellen Thread ist, so wird es nicht blockieren. Second wird die Initialisierung abgeschlossen, und dann wird die Initialisierung von First abgeschlossen.

Glücklicherweise ist das Feld, das Second benötigt, bereits zugewiesen worden, so dass das "Richtige" passiert.

Das ist alles sehr gut, wenn Firsttatsächlich anfängt initialisieren zuerst. Da jedoch keine der Klassen einen statischen Konstruktor hat, ist es möglich, dass Second beginnt, zuerst zu initialisieren ... es würde dann anfangen, First zu initialisieren, was erkennen würde, dass Second bereits initialisiert ist und 's aktuellen Wert (null) für First.secondArray. Das wäre eine schlechte Sache. Beachten Sie, dass das Initialisierungstiming für Typen ohne statische Konstruktoren changed in .NET 4 hat - nicht in einer spe-breaking Weise, aber möglicherweise in einer Code-breaking-Weise.

Wenn beide First und Second statischen Konstruktoren hatte, dann würde First zunächst initialisiert werden, wie das ist die erste Klasse, die Main berührt.

Moral der Antwort: Tu dies nicht. Typinitialisierer, die sich aufeinander beziehen, sind sehr fehleranfällig. Ein weiteres Beispiel finden Sie in Eric Lippert und Neal Gafters NDC 2010 Talk, "C# Puzzlers", die auf der NDC video page angesehen werden können.

+0

Ist die Standard-Garantie diese Bestellung? Meine Vermutung war, dass sich jede Klasse vor dem ersten Zugriff auf ein undefiniertes initialisiert, was dies in einen Abhängigkeitszyklus umwandelt, der zufällig aufgelöst wird. –

+0

@Tim: Ich habe meine Antwort aktualisiert - ohne statische Konstruktoren ist die Reihenfolge in der Tat nicht definiert. –

+0

Mit dem an VS2005 angehängten Debugger passiert eine schlechte Sache - 'Second.firstArray' wird auf' null' gesetzt – AakashM

0

Ich glaube nicht, dass es eine Garantie gibt, welcher statische Typ zuerst initialisiert wird. Um sicherzustellen, dass Felder korrekt auf diese Weise initialisiert werden, dann würden Sie einen statischen Konstruktor hinzufügen müssen, zB:

static class Second 
{ 
    public static int[] firstArray = First.firstArray; 
    public static int[] secondArray = new int[30]; 

    static Second() { } 

    public static void Write() 
    { 
     Console.WriteLine(firstArray.ToString()); 
     Console.WriteLine(secondArray.ToString()); 
    } 
} 

Nun, wenn Sie die gleiche Sache wieder laufen, es funktioniert ...