8

Wenn Sie beim nächsten Beispiel aussehen:Warum C# lokale Variable sollte direkt zugewiesen werden, auch wenn es Standardwert ist?

public void TestLocalValuesAssignment() 
{ 
    int valueVariable; // = default(int) suits fine 
    string refType; // null suits fine as well 

    try 
    { 
     valueVariable = 5; 
     refType = "test"; 
    } 
    catch (Exception){} 

    Console.WriteLine("int value is {0}", valueVariable); 
    Console.WriteLine("String is {0}", refType); 
} 

Sie leicht erkennen können, dass Variablen valueVariable und refType vor ihrer Verwendung in Console.WriteLine() nicht zugeordnet werden können. Compiler sagt uns darüber mit Fehlern:

Error 1 Use of unassigned local variable 'valueVariable' 
Error 2 Use of unassigned local variable 'refType' 

Dies ist ein weit verbreiteter Fall und es gibt loads of answers auf, wie die (mögliche Korrekturen kommentiert) zu beheben.

Was kann ich nicht verstehen, warum ein solches Verhalten existiert? Wie unterscheiden sich hier lokale Variablen von Klassenfeldern, wobei die letzten Standardwerte erhalten, wenn sie nicht zugewiesen sind (Null für Referenztypen und korrespondierender Standardwert für Werttypen)? Vielleicht gibt es ein Beispiel oder einen Eckfall, der erklärt, warum ein solches Compiler-Verhalten gewählt wird?

+1

möglich Duplikat [Initialisierung der Instanzfelder gegen lokale Variablen] (http://stackoverflow.com/questions/1542824/initialization-of-instance-fields-vs-local-variables) –

+1

Es ist nicht „Verhalten“ Es ist * Regel *. Die eindeutige Zuordnungsregel besagt, dass eine Variable * vor der Verwendung zugewiesen werden muss. Natürlich wird es nicht in Ihrem Code-Snippet sein, wenn eine Ausnahme ausgelöst wird. Ja, kann passieren. –

+0

@TimSchmelter Stimme absolut zu, es ist ein Duplikat. [John Skeet lieferte] (http://stackoverflow.com/a/1542851/472020) ziemlich vernünftige Erklärung, die als eine Antwort auf meine Frage betrachtet werden könnte. – Antonio

Antwort

11

im Grunde - das ist, was MS entschieden hat.

Wenn Sie mehr wollen, können Sie here lesen und prüfen Eric Lippert’s Blog

Der Grund, dies in C# illegal ist, weil unter Verwendung eines nicht zugewiesenen lokalen hohe Wahrscheinlichkeit hat ein Bug zu sein.

+1

Dieser Link geht auf eine große Eric Lippert Antwort. –

+0

Einverstanden, Eric Lipperts Antwort erklärt viel. Grundsätzlich scheint es eine Regel zu sein, Programmierer davon abzuhalten, Fehler zu machen. – Antonio

+2

@Antonio: Richtig. Grundsätzlich ist die Idee, dass (1) nicht initialisierte Variablen Fehler sein können, und (2) es sehr einfach zu erkennen ist, wenn ein Local nicht definitiv zugewiesen ist, aber es ist ein bisschen schwieriger zu erkennen, wenn ein Feld nicht eindeutig zugewiesen ist . Die Regel lautet also: Einheimische müssen eindeutig zugewiesen werden. Wenn es billig und einfach wäre, Felder zu finden, die nicht zugewiesen wurden, würde die Regel auch auf Felder ausgedehnt werden, aber es ist nicht billig und einfach. –

4

Es ist in C# spec beschrieben:

5.1.7 Lokale Variablen

Eine lokale Variable durch eine lokale Variablen-Deklaration eingeführt ist nicht automatisch initialisiert und hat somit keine Standard Wert. Für den Zweck der definitiven Zuweisungsprüfung wird eine lokale Variable, die von einer lokalen Variablendeklaration eingeführt wurde, zunächst als nicht zugewiesen betrachtet. A local-variable-Deklaration kann einen lokale Variablen-Initialisierer, in welchem ​​Fall die Variable wird auf jeden Fall nur nach dem Initialisieren Expression abgetreten (§5.3.3.4).

Im Rahmen eines von einer lokal lokalen Variablen-Deklaration eingeführt variable, ist es ein Fehler Übersetzungszeit zu dass lokaler Variable in einer Textposition Bezug zu nehmen, der seinen local-variabel voran Deklarator. Wenn die lokale Variablendeklaration implizit ist (§8.5.1), ist es auch ein Fehler, auf die Variable local-variable-declarator zu verweisen.

+0

Ja, gute refference. Es erklärt das Verhalten (oder die Regel) des Compilers deutlich. Obwohl es nicht erklärt, warum eine solche Entscheidung getroffen wurde. Ich hatte gehofft, ein Beispiel zu bekommen, wo es offensichtlich wäre, warum diese Regel existiert. – Antonio

0

In Wirklichkeit sollte Ihr Code in Ordnung sein, aber durch strenge Interpretation gibt es einen Code-Pfad, der Ihre Variablen vor der Verwendung nicht zugewiesen lassen kann.Der versuchen Block das Potenzial für Code innerhalb des Blocks führt nicht ausgeführt werden (wenn eine Ausnahme ausgelöst wird), aber immer noch den Code über den fangen ausführen (denn es gibt nichts in der fangen wie Rückkehr ist Oder throw zu verhindern, dass der Rest der Methode ausgeführt wird, wenn eine Ausnahme in der versucht wird, versuchen).

Wenn Sie zwischen Initialisierung „struct“ Felder der Differenz beziehen und Initialisieren Klassenfelder, zB:

public class A 
    { 
    } 

     MyMethod() 
     { 
      int myInt; // Initialized to zero, yes, but not yet assigned. 
         // An error to use this before assigning it. 

      A myA; // defaults to null, which may be a valid initial state, but still unassigned. 
        // Also an error to use this before assigning it. 

      A oneMoreA = null; // Same value as default, but at least intention is clear. 
      A anotherA = new A(); // What is or is not happening in the constructor is a separate issue. 
           // At least anotherA refers to an actual instance of the class. 
2

Wenn Sie etwas tun, das dumm erscheint, wie aus einer Variablen lesen Sie nie haben zugewiesen, gibt es im Wesentlichen zwei Dinge, die der Compiler tun kann:

  1. Geben Sie eine Diagnose, die Ihre Aufmerksamkeit darauf richtet, was wahrscheinlich ein Fehler ist.
  2. Tun Sie etwas Willkürliches.

Seit Option # 1 Sie Fehler finden hilft, ist es bevorzugt, vor allem, wenn die Abhilfe der Compiler zu sagen „Nein, ich meine den ursprünglichen Standardwert verwenden“ ist so einfach wie das Hinzufügen = 0, = null oder = default(T).

Warum Klassenmitglieder nicht auf die gleiche Weise arbeiten, liegt daran, dass dies nicht zur Kompilierzeit überprüft werden kann (wegen der unzähligen verschiedenen Ordnungen, die die verschiedenen Methoden aufgerufen werden könnten). Es würde Laufzeitkosten für Flags geben, ob jedes Mitglied zugewiesen wurde, und Testen dieser Flags.

Beachten Sie, dass der Compiler die Einschränkung für Strukturelemente in einer Weise erzwingt, die bei der Kompilierung einfach überprüft werden kann. Jeder Konstruktor muss nämlich jedes Mitglied zuweisen.