注:これはRoslynで修正されたようです
私の答えを書くときにこの質問は生まれたこの1の関連性について語る、nullで合体演算子。
念のため、null融合演算子の考え方は、フォームの式
x ?? y
最初にを評価しx
、次に:
- の値
x
がnullの場合、y
評価され、それが式の最終結果になります - 値があれば
x
非ヌルである、y
されていない評価され、値がx
のコンパイル時の型に変換した後、発現の最終的な結果であり、y
必要に応じて
今、通常、変換の必要はありません、またはそれは、非NULL可能1にNULL可能タイプからだけだ-通常のタイプが同じである、または単に(と言う)からint?
にint
。ただし、独自の暗黙の変換演算子を作成でき、それらは必要に応じて使用されます。
の単純なケースではx ?? y
、奇妙な動作は見たことがありません。しかし、(x ?? y) ?? z
私はいくつかの混乱した行動を見ています。
以下は短いが完全なテストプログラムです-結果はコメントにあります:
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;
}
}
3つのカスタム値型、持っている私たちは、そうA
、B
およびC
Cに、AからBへの変換で、CにA、およびBを
2番目のケースと3番目のケースの両方を理解できますが、なぜ最初のケースで余分なAからBへの変換があるのですか 特に、最初のケースと2番目のケースが同じであることを本当に期待していました。結局のところ、式をローカル変数に抽出するだけです。
何が起こっているのか?C#コンパイラに関しては、「バグ」を叫ぶのを非常にためらっていますが、何が起こっているのかについて困惑しています...
編集:わかりました、これは、コンフィギュレーターの回答のおかげで、何が起こっているのかという厄介な例です。編集:サンプルでは、2つのnull結合演算子も必要ありません...
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;
}
}
この出力は次のとおりです。
Foo() called
Foo() called
A to int
Foo()
ここで2回呼び出されるという事実は、私にとって非常に驚くべきことです。式が2回評価される理由は何もわかりません。
C? first = ((B?)(((B?)x) ?? ((B?)y))) ?? ((C?)z);
。あなたは得られます:Internal Compiler Error: likely culprit is 'CODEGEN'
(("working value" ?? "user default") ?? "system default")