2009-03-18 12 views
8

Dieser Code hat das gut definiertes Verhalten in C# nicht arbeiten:Warum in C# bestellen Sie für die statische Initialisierung?

class Foo 
{ 
    static List<int> to = new List<int>(from); // from is still null 
    static IEnumerable<int> from = Something(); 
} 

Hinweis: Ich frage nicht, wie dieser Code als I already known how to do that zu beheben

Was ist die Begründung dafür? C# führt bereits Zeitüberprüfungen durch, um den ersten Zugriff auf statische Member zu erkennen. Warum erweitern Sie das nicht auf ein Pro-Element-Objekt und lassen es bei Bedarf laufen, oder besser gesagt, der Compiler ermittelt den Auftrag zur Kompilierzeit?

BTW: Ich denke, die gleiche Frage (oder fast das gleiche) gilt auch für nicht statische Mitglieder.

+1

Ich glaube, du antwortest dir selbst, indem du sagst, das sei "wohldefiniertes Verhalten". – mayu

Antwort

6

ich einen Programmierer aufgrund von Nebenwirkungen bei der Initialisierung, um mit anderen statischen je vorstellen kann Klassen. Sie und ich wissen beide, dass abhängig von Nebenwirkungen schlechte Praxis ist, aber es ist nicht unbedingt illegal.

Betrachten wir etwas wie folgt aus:

class Foo 
{ 
    static string header = Bar.GetHeader(); 
    static string version = Bar.GetVersion(); 
} 

Und Bar.GetVersion geht davon aus, dass Bar.GetHeader aufgerufen wurde. Wenn der Compiler frei wäre, die Initialisierungsreihenfolge zu ändern, wäre der Programmierer nicht in der Lage, die Initialisierungsreihenfolge zu garantieren.

Hässlich, gewährt, aber vollkommen legal. Wenn Sie sich Effekte zweiter Ordnung vorstellen (d. H.statische Methoden genannt, die selbst von Klassen abhängen, die Nebeneffekte haben), sehen Sie, dass der Compiler nichts wirklich neu anordnen kann, so wie es im Allgemeinen unmöglich ist, dass der Compiler die Reihenfolge der Funktionsaufrufe in Ihrem statischen Konstruktor neu anordnet.

+0

Ein guter Punkt und es könnte der Grund sein. Das heißt, ich denke, dass die "in der richtigen Reihenfolge" Weg ist falsch, den Weg, um das zu lösen. Ich denke, der richtige Takt ist zu sagen: "Wenn die Reihenfolge zählt, initialisiere in einem Konstruktor." und "Code, der von der Reihenfolge der Inline-Initialisierung abhängt, ist illegal, selbst wenn er ausgeführt wird". – BCS

1

Ich denke, was Sie brauchen, ist ein statischer Konstruktor.

Wie so

class Foo 
{ 
    static List<int> to; 
    static IEnumerable<int> from; 

    static Foo() 
    { 
     from = Something(); 
     to = new List<int>(from); 
    } 
} 

Wie, warum C# es beim ersten Zugriff nicht tut, ich sehe einfach nicht die Notwendigkeit für diese Art von Komplexität, wenn es andere Alternativen, die deutlich machen, was los ist .

+0

Ich glaube, du hast die Frage nicht gelesen. – Samuel

+0

Ich habe die Frage gelesen. Zu fragen, warum C# auf eine bestimmte Art und Weise funktioniert, wird Ihnen nie eine nützliche Antwort geben. Meine Antwort lautete: Warum sollte es funktionieren, wenn Sie das tun können? – Ray

+0

Fragen, warum etwas in C funktioniert, hat schon viele Male funktioniert; Sehen Sie sich nur an, wie viel Jon Skeet über die Mechanik von C# weiß. – Samuel

1

C# überprüft die Laufzeit, um den ersten Zugriff auf eine Klasse zu ermitteln, ordnet jedoch die statische Initialisierung in einer Klasse nicht neu an.

Die statischen Felder werden von oben nach unten initialisiert, gefolgt von den statischen Konstruktoren von oben nach unten. Ändern Sie entweder die Reihenfolge Ihrer Felder oder erstellen Sie einen statischen Konstruktor und initialisieren Sie die Felder von tehre.

Siehe Variable initializers in der C# -Spezifikation oder this article auf Initialisierer .. Auch die Frage Order of static constructors/initializers in C# ist verwandt.

+0

Ich habe diese Frage gestellt: b Siehe auch meinen Kommentar zu Ray. Ich frage mich/nicht/wie ich diesen Code reparieren soll. – BCS

+0

Ja, hast du. :-) Ich denke, ich sollte mehr Aufmerksamkeit schenken! –

+0

"'Irgendwas stimmt nicht, bitte kontaktiere den sys admin', Crud! Ich wäre aber ich/bin/der sys admin!" BCS

12

Initialisierer sind nur ein syntaktischer Zucker. Der Compiler fügt diesen Code in die .cctor-Datei ein, wenn er Ihre Klasse kompiliert und sie in den Befehlen pausiert, die sie im Code enthalten.

Es führt keine Überprüfungen durch, weil es keinen Sinn ergeben würde. Sie könnten immer noch Initialisierungszyklen haben, also würde es sowieso nicht funktionieren.

ich gebloggt es vor einiger Zeit, wenn Sie interessiert sind:

+0

Das ist der Hauptgrund: Initialisierungszyklen, die der Compiler nicht auflösen kann. –

+0

Zyklen sind immer ein Fehler: Ich würde lieber Compilerfehler bekommen, als Sie derzeit bekommen. Abgesehen von Zyklen sehe ich keine Probleme. +1 – BCS

+0

> "Compiler legt diesen Code in die .cctor." Sicherlich kann das nicht stimmen. Initialisierer werden in anderer Reihenfolge als Konstruktoren aufgerufen, richtig? – mayu

Verwandte Themen