Der folgende Code führt zur Verwendung der nicht zugewiesenen lokalen Variablen "numberOfGroups" :
int numberOfGroups;
if(options.NumberOfGroups == null || !int.TryParse(options.NumberOfGroups, out numberOfGroups))
{
numberOfGroups = 10;
}
Allerdings funktioniert dieser Code in Ordnung (obwohl, ReSharper , sagt der = 10
überflüssig ist):
int numberOfGroups = 10;
if(options.NumberOfGroups == null || !int.TryParse(options.NumberOfGroups, out numberOfGroups))
{
numberOfGroups = 10;
}
Vermisse ich etwas oder mag der Compiler meine nicht ||
?
Ich habe dies eingegrenzt, dynamic
um die Probleme zu verursachen ( options
war eine dynamische Variable in meinem obigen Code). Es bleibt die Frage, warum ich das nicht tun kann .
Dieser Code wird nicht kompiliert:
internal class Program
{
#region Static Methods
private static void Main(string[] args)
{
dynamic myString = args[0];
int myInt;
if(myString == null || !int.TryParse(myString, out myInt))
{
myInt = 10;
}
Console.WriteLine(myInt);
}
#endregion
}
Dieser Code bewirkt jedoch :
internal class Program
{
#region Static Methods
private static void Main(string[] args)
{
var myString = args[0]; // var would be string
int myInt;
if(myString == null || !int.TryParse(myString, out myInt))
{
myInt = 10;
}
Console.WriteLine(myInt);
}
#endregion
}
Ich wusste nicht, dynamic
dass dies ein Faktor sein würde.
out
Parameter übergebenen Wert nicht als Eingabe verwendenout
Aufrufsite verfügt wahrscheinlich über einen Kontrollfluss, der keine Zuordnung zum Parameter garantiert . Es ist sicherlich interessant zu überlegen, welchen Hilfscode der Compiler erstellen sollte, um das Problem zu vermeiden, oder ob dies überhaupt möglich ist.Antworten:
Ich bin mir ziemlich sicher, dass dies ein Compiler-Fehler ist. Schöner Fund!
Bearbeiten: Es ist kein Fehler, wie Quartermeister demonstriert; dynamic implementiert möglicherweise einen seltsamen
true
Operator, der dazu führen kanny
, dass er niemals initialisiert wird.Hier ist ein minimaler Repro:
Ich sehe keinen Grund, warum das illegal sein sollte; Wenn Sie Dynamic durch Bool ersetzen, wird es problemlos kompiliert.
Ich treffe mich morgen mit dem C # -Team. Ich werde es ihnen gegenüber erwähnen. Entschuldigung für den Fehler!
quelle
d
von einem Typ mit einem überladenentrue
Operator sein kann. Ich habe eine Antwort mit einem Beispiel gepostet, in dem keiner der Zweige verwendet wird.Es ist möglich, dass die Variable nicht zugewiesen wird, wenn der Wert des dynamischen Ausdrucks von einem Typ mit einem überladenen
true
Operator ist .Der
||
Bediener ruft dentrue
Bediener auf, um zu entscheiden, ob die rechte Seite bewertet werden soll, und dannif
ruft die Anweisung dentrue
Bediener auf, um zu entscheiden, ob der Körper bewertet werden soll. Für einen Normalen gebenbool
diese immer das gleiche Ergebnis zurück und so wird genau eines ausgewertet, aber für einen benutzerdefinierten Operator gibt es keine solche Garantie!Aufbauend auf Eric Lipperts Repro ist hier ein kurzes und vollständiges Programm, das einen Fall demonstriert, in dem keiner der Pfade ausgeführt wird und die Variable ihren Anfangswert hat:
quelle
d
zweimal bewertet werden? (Ich bestreite nicht, dass dies eindeutig der Fall ist , wie Sie gezeigt haben.) Ich hätte erwartet, dass das ausgewertete Ergebnistrue
(vom ersten Operatoraufruf, verursacht durch||
) an dieif
Anweisung "weitergegeben" wird . Das würde sicherlich passieren, wenn Sie dort beispielsweise einen Funktionsaufruf einfügen.d
wird erwartungsgemäß nur einmal ausgewertet. Es ist dertrue
Operator, der zweimal aufgerufen wird, einmal nach||
und nachif
.var cond = d || M(out y); if (cond) { ... }
. Zuerst werten wir ausd
, um eineEvilBool
Objektreferenz zu erhalten . Um das zu bewerten||
, rufen wir zuerstEvilBool.true
mit dieser Referenz auf. Das gibt true zurück, also schließen wir kurz und rufen nicht aufM
und weisen dann die Referenz zucond
. Dann fahren wir mit derif
Aussage fort. Dieif
Anweisung wertet ihren Zustand durch Aufrufen ausEvilBool.true
.Von MSDN (Schwerpunkt Mine):
Da der Compiler keine Operationen prüft oder auflöst, die Ausdrücke vom Typ dynamisch enthalten, kann er nicht sicherstellen, dass die Variable mithilfe von zugewiesen wird
TryParse()
.quelle
numberGroups
wird zugewiesen (imif true
Block), wenn nicht, garantiert die zweite Bedingung die Zuweisung (viaout
).myString == null
(nur dasTryParse
).if
Ausdruck) einedynamic
Variable enthält und zur Kompilierungszeit nicht aufgelöst wird (der Compiler kann diese Annahmen daher nicht treffen).