2017-01-19 2 views
6

Ich habe zwei Methoden, von denen beide kompiliert richtig:Nicht zugewiesene lokale Variable und Kurzschluss Auswertung

public int A() 
{ 
    int i; 
    if(!int.TryParse("0", out i)) 
    { 
     return -1; 
    } 
    // do sth 
    return i; 
} 

public int B() 
{ 
    int i; 
    if(true) 
    { 
     return -1; 
    } 
    return i; 
} 

Im zweiten Fall (Methode B) Compiler intelligent genug, um die Variable zu detektieren i wird nie so verwendet, es beschwert sich nicht, es nicht zuzuweisen.

Allerdings habe ich ein anderes Beispiel (eine Kombination aus beiden), die B äquivalent Methode zu sein scheint:

public int C() 
{ 
    int i; 
    if (true || !int.TryParse("0", out i)) 
    { 
     return -1; 
    } 
    return i; 
} 

Wenn unter Windows unter Visual Studio 2012 (.NET Framework kompilieren 4.6.01055) es wirft einen Fehler auf: Use of unassigned local variable 'i'. Die Lösung ist:

  • i mit einem beliebigen Wert initialisiert werden, oder
  • Verwendung | Operator anstelle von ||.

Warum ist das so? Es sieht so aus, als hätte ein Compiler alle notwendigen Daten, um nicht erreichbaren Code zu erkennen.

Exkurs: Beispiel C kompiliert auf Linux unter Mono 4.6.2 mit Warnungen über nicht erreichbaren Code wie erwartet.

+3

Kennen Sie das Halteproblem (https://en.wikipedia.org/wiki/Halting_problem)? Das ist hauptsächlich der Grund, warum Compiler nicht immer erwartet werden können, um zu wissen, ob Ihr Code nicht erreichbar ist ... – Idos

+0

Es gab einen alten Bug ganz ähnlich, aber es ging um [dynamic] (http://stackoverflow.com/a/36062697/15498) –

+0

Im ersten Beispiel in Methode B - wenn Sie nach der schließenden Klammer der _ "if (true)" _ Anweisung ungültigen Code geschrieben haben, würde dies einen Compilerfehler erzeugen, obwohl er nicht erreichbar ist - also die Verwendung eines nicht zugewiesenen Locals meldet Variable scheint ein konsistenter Ansatz. – PaulF

Antwort

1

Dies kann nicht als ein Fehler betrachtet werden, aber es ist eine verbesserungsfähige Funktion. Sie haben Recht, wenn Sie sagen, dass der Compiler über genügend Informationen verfügt, um zu wissen, dass das nicht zugewiesene i nie verwendet wird und daher den Compilerfehler auslassen sollte.

Es ist verbesserungsfähig, weil es in der Tat verbessert wurde; In VS 2015 ist das Verhalten des Compilers das erwartete: kein Kompilierzeitfehler. Ich kann nicht dasselbe für frühere Versionen des Compilers sagen, weil ich sie im Moment nicht testen kann.

Komischerweise gibt es weder VS 2015 noch VS 2017 RC eine unerreichbare Code-Warnung bei return i, die ein bisschen seltsam erscheint. if (true) gibt diese Warnung und if (true || ....) ergibt sich richtig, dass i nicht verwendet wird, aber die Warnung wurde aus Gründen, die ich nicht verstehe, weggelassen.

Weitere Informationen darüber, warum das Verhalten geändert wurde, finden Sie unter answer. Ich wusste, dass diese Frage eine Glocke läutete ... Ich habe vor ein paar Jahren selbst eine ähnliche Frage gestellt;).

+0

@Damien_The_Unbeliever oops, behoben, danke. – InBetween

0

When compiling on Windows under Visual Studio 2012 (.NET Framework 4.6.01055) it throws an error: Use of unassigned local variable 'i'

Wie es sollte. Die Variable ist nicht zugewiesen. Sie dürfen es nicht im Code referenzieren. Manchmal, je nach Compiler, weiß es vielleicht vorher, dass die Zeile nie ausgeführt wird und entfernt sie vollständig, bevor sie die Variablenverwendung überprüft. Andere Versionen können die Schritte wechseln, die zu unterschiedlichen Ergebnissen führen können. Persönlich würde ich sagen, dass Sie sich nicht darauf verlassen sollten: code safe.

Nur zu Ihrer Information. Roslyn (der neueste .NET-Compiler) gibt keinen Fehler beim Kompilieren. Es scheint, dass die Validierung alle || Bedingungen einfach verwirft.

if (true || !int.TryParse("0", out i)) // // does not give an error, first return always used, other discarded 

if (true && !int.TryParse("0", out i)) // does not give an error, i is known to always be assigned 

if (false && !int.TryParse("0", out i)) // gives an error, if never results in true, and parse is known not to be called 
+1

* Wie es sein sollte *. Nein, es ist nicht so wie es sein sollte. Ihre eigene Antwort disqualifiziert diese Argumentation; neuere Compiler-Versionen verursachen keinen Kompilierzeitfehler. – InBetween

+0

Dass sie den Compiler optimiert haben, um das richtig zu handhaben, ist egal, dass Sie solchen Code herumstehen haben sollten. Wenn jemand das 'true' in' false' ändert, öffnet sich eine ganze Reihe von Problemen. Ich denke, du solltest sie früher beheben. –

+1

10 @InBetween: Da dieser Codeabschnitt nicht erreichbar ist - sollte der gesamte ungültige Code ignoriert werden? – PaulF