Hinweis: Dieses Problem scheint in der folgenden Version behoben worden zu sein Roslyn
Diese Frage stellte sich beim Verfassen meiner Antwort auf celui-ci die über die Assoziativität der Nullkoalitionsoperator .
Zur Erinnerung: Die Idee des Null-Koalitionsoperators ist, dass ein Ausdruck der Form
x ?? y
wertet zunächst aus x
, dann:
- Wenn der Wert von
x
null ist,y
ausgewertet wird und das ist das Endergebnis des Ausdrucks - Wenn der Wert von
x
nicht null ist,y
es pas bewertet, und der Wert vonx
ist das Endergebnis des Ausdrucks nach einer Umwandlung in den Kompilierzeittyp vony
falls erforderlich
Jetzt in der Regel keine Konvertierung erforderlich ist oder es sich nur um eine Konvertierung von einem nullbaren Typ in einen nicht-nullbaren Typ handelt - in der Regel sind die Typen gleich, oder nur von (sagen wir) int?
a int
. Aber Sie kann Ihre eigenen impliziten Konvertierungsoperatoren erstellen, die dann bei Bedarf verwendet werden.
Für den einfachen Fall von x ?? y
Ich habe kein merkwürdiges Verhalten festgestellt. Allerdings, mit (x ?? y) ?? z
Ich sehe ein verwirrendes Verhalten.
Hier ist ein kurzes, aber vollständiges Testprogramm - die Ergebnisse finden Sie in den Kommentaren:
using System;
public struct A
{
public static implicit operator B(A input)
{
Console.WriteLine("A to B");
return new B();
}
public static implicit operator C(A input)
{
Console.WriteLine("A to C");
return new C();
}
}
public struct B
{
public static implicit operator C(B input)
{
Console.WriteLine("B to C");
return new C();
}
}
public struct C {}
class Test
{
static void Main()
{
A? x = new A();
B? y = new B();
C? z = new C();
C zNotNull = new C();
Console.WriteLine("First case");
// This prints
// A to B
// A to B
// B to C
C? first = (x ?? y) ?? z;
Console.WriteLine("Second case");
// This prints
// A to B
// B to C
var tmp = x ?? y;
C? second = tmp ?? z;
Console.WriteLine("Third case");
// This prints
// A to B
// B to C
C? third = (x ?? y) ?? zNotNull;
}
}
Wir haben also drei benutzerdefinierte Wertetypen, A
, B
y C
mit Umwandlungen von A nach B, A nach C und B nach C.
Ich kann sowohl den zweiten als auch den dritten Fall verstehen... aber warum Gibt es im ersten Fall eine zusätzliche Umwandlung von A nach B? Insbesondere würde ich realmente Ich habe erwartet, dass der erste Fall und der zweite Fall dasselbe sind - es geht ja nur darum, einen Ausdruck in eine lokale Variable zu extrahieren.
Weiß jemand, was hier los ist? Ich bin extrem zögerlich zu schreien "Bug", wenn es um den C#-Compiler kommt, aber ich bin ratlos, was los ist...
EDIT: Okay, hier ist ein böseres Beispiel für das, was vor sich geht, dank der Antwort des Konfigurators, was mir einen weiteren Grund gibt, zu glauben, dass es ein Fehler ist. EDIT: Das Beispiel braucht jetzt nicht einmal mehr zwei Null-Koalitionsoperatoren...
using System;
public struct A
{
public static implicit operator int(A input)
{
Console.WriteLine("A to int");
return 10;
}
}
class Test
{
static A? Foo()
{
Console.WriteLine("Foo() called");
return new A();
}
static void Main()
{
int? y = 10;
int? result = Foo() ?? y;
}
}
Das Ergebnis ist:
Foo() called
Foo() called
A to int
Die Tatsache, dass Foo()
hier zweimal genannt wird, ist für mich sehr überraschend - ich kann keinen Grund erkennen, warum der Ausdruck bewertet zweimal.