Was verursacht dieses Problem?
Sieht für mich wie ein Compiler-Bug aus. Zumindest war es so. Obwohl die Ausdrücke decimal.TryParse(v, out a)
und decimal.TryParse(v, out b)
dynamisch ausgewertet werden, habe ich erwartet , dass der Compiler immer noch versteht, dass a <= b
beide a
und b
definitiv zugewiesen sind, wenn sie erreicht sind. Selbst mit den Verrücktheiten, die beim dynamischen Tippen auftreten können, würde ich erwarten, dass die a <= b
Bewertung erst nach der Bewertung beider TryParse
Anrufe erfolgt.
Es stellt sich jedoch heraus, dass es durch Operator und Konvertierung schwierig ist, einen Ausdruck zu haben, A && B && C
der ausgewertet wird A
und C
aber nicht B
- wenn Sie schlau genug sind. Das geniale Beispiel von Neal Gafter finden Sie im Roslyn-Fehlerbericht .
Es dynamic
ist noch schwieriger , diese Arbeit zu erledigen - die Semantik bei dynamischen Operanden ist schwieriger zu beschreiben, da Sie zur Durchführung der Überlastungsauflösung Operanden auswerten müssen, um herauszufinden, um welche Typen es sich handelt, was möglicherweise nicht intuitiv ist. Aber auch hier ist Neal hat mit einem Beispiel , das zeigt , dass die Compiler - Fehler kam erforderlich ... dies ist kein Fehler, es ist ein Bug - Fix . Riesige Anerkennung an Neal für den Beweis.
Ist es möglich, es durch Compiler-Einstellungen zu beheben?
Nein, aber es gibt Alternativen, die den Fehler vermeiden.
Erstens könnten Sie verhindern, dass es dynamisch ist. Wenn Sie wissen, dass Sie immer nur Zeichenfolgen verwenden, können Sie der Bereichsvariablen den Typ (dh ) verwenden IEnumerable<string>
oder geben . Das wäre meine bevorzugte Option.v
string
from string v in array
Wenn Sie es wirklich dynamisch halten müssen, geben Sie zunächst b
einen Wert an:
decimal a, b = 0m;
Dies wird nicht schaden - wir wissen , dass tatsächlich Ihre dynamische Auswertung etwas verrückt nicht tun, so dass Sie immer noch einen Wert zuweisen am Ende dann , b
bevor Sie es verwenden, so dass der Ausgangswert irrelevant.
Darüber hinaus scheint das Hinzufügen von Klammern auch zu funktionieren:
where decimal.TryParse(v, out a) && (decimal.TryParse("15", out b) && a <= b)
Dies ändert den Punkt, an dem verschiedene Teile der Überlastungsauflösung ausgelöst werden, und macht den Compiler glücklich.
Es bleibt noch ein Problem offen: Die Regeln der Spezifikation für die definitive Zuordnung zum &&
Operator müssen präzisiert werden, um festzustellen, dass sie nur gelten, wenn der &&
Operator in seiner "regulären" Implementierung mit zwei bool
Operanden verwendet wird. Ich werde versuchen sicherzustellen, dass dies für den nächsten ECMA-Standard behoben ist.
b
nachdem es über einenout
Parameter zugewiesen wurde.