Note: il semble que cela ait été corrigé dans Roslyn
Cette question a été soulevée lors de la rédaction de ma réponse à ce un seul, qui parle de l'associativité de l' null-coalescence de l'opérateur.
Juste pour rappel, l'idée de la valeur null est-coalescence de l'opérateur est qu'une expression de la forme
x ?? y
la première évalue x
, alors:
- Si la valeur de
x
est null,y
est évaluée et qui est le résultat de l'expression - Si la valeur de
x
est non-nulle,y
est pas évalué, et la valeur dex
est le résultat final de l'expression, après une conversion vers le type de compilation d'y
si nécessaire
Maintenant, généralement il n'y a pas besoin d'une conversion, ou c'est juste à partir d'un type nullable à un non nullable un - généralement les types sont les mêmes, ou tout simplement de (dis) int?
de int
. Toutefois, vous pouvez créer votre propre conversion implicite des opérateurs, et ceux-ci sont utilisées, le cas échéant.
Pour le cas simple d' x ?? y
, je n'ai pas vu tout comportement étrange. Cependant, avec (x ?? y) ?? z
je vois certains comportement déroutant.
Voici une courte mais complète du programme de test, les résultats sont dans les commentaires:
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;
}
}
Nous avons donc trois personnalisés types de valeur, A
, B
et C
, avec les conversions de A à B, A, C et B to C.
Je peux comprendre les deux cas le deuxième et le troisième cas... mais pourquoi est-il un supplément de A à B de conversion dans le premier cas? En particulier, j'aimerais vraiment avoir attendu le premier cas deuxième cas être la même chose - c'est juste de l'extraction d'une expression dans une variable locale, après tout.
Les élèves de ce qui se passe? Je suis extrêmement hesistant à pleurer "bug" quand il s'agit pour le compilateur C#, mais je suis perplexe quant à ce qui se passe...
EDIT: Ok, c'est du plus mauvais exemple de ce qui se passe, grâce au configurateur de réponse, ce qui me donne une raison de plus de penser que c'est un bug. EDIT: L'échantillon n'a pas même besoin de deux null-coalescence des opérateurs maintenant...
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;
}
}
La sortie de ce est:
Foo() called
Foo() called
A to int
Le fait qu' Foo()
est appelée deux fois ici, est très surprenant pour moi - je ne vois aucune raison pour que l'expression doit être évaluée à deux reprises.