以下の場合、InvalidCastException がスローされるのはなぜですか? バグの範囲外である理由がわかりません (これは x86 にあります。x64 は clrjit.dll で 0xC0000005 でクラッシュします)。
class Program
{
static void Main(string[] args)
{
MyDouble? my = new MyDouble(1.0);
Boolean compare = my == 0.0;
}
struct MyDouble
{
Double? _value;
public MyDouble(Double value)
{
_value = value;
}
public static implicit operator Double(MyDouble value)
{
if (value._value.HasValue)
{
return value._value.Value;
}
throw new InvalidCastException("MyDouble value cannot convert to System.Double: no value present.");
}
}
}
に対して生成された CIL は次のMain()
とおりです。
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 3
.locals init (
[0] valuetype [mscorlib]System.Nullable`1<valuetype Program/MyDouble> my,
[1] bool compare,
[2] valuetype [mscorlib]System.Nullable`1<valuetype Program/MyDouble> CS$0$0000,
[3] valuetype [mscorlib]System.Nullable`1<float64> CS$0$0001)
L_0000: nop
L_0001: ldloca.s my
L_0003: ldc.r8 1
L_000c: newobj instance void Program/MyDouble::.ctor(float64)
L_0011: call instance void [mscorlib]System.Nullable`1<valuetype Program/MyDouble>::.ctor(!0)
L_0016: nop
L_0017: ldloc.0
L_0018: stloc.2
L_0019: ldloca.s CS$0$0000
L_001b: call instance bool [mscorlib]System.Nullable`1<valuetype Program/MyDouble>::get_HasValue()
L_0020: brtrue.s L_002d
L_0022: ldloca.s CS$0$0001
L_0024: initobj [mscorlib]System.Nullable`1<float64>
L_002a: ldloc.3
L_002b: br.s L_003e
L_002d: ldloca.s CS$0$0000
L_002f: call instance !0 [mscorlib]System.Nullable`1<valuetype Program/MyDouble>::GetValueOrDefault()
L_0034: call float64 Program/MyDouble::op_Implicit(valuetype Program/MyDouble)
L_0039: newobj instance void [mscorlib]System.Nullable`1<float64>::.ctor(!0)
L_003e: stloc.3
L_003f: ldloca.s CS$0$0001
L_0041: call instance !0 [mscorlib]System.Nullable`1<float64>::GetValueOrDefault()
L_0046: call float64 Program/MyDouble::op_Implicit(valuetype Program/MyDouble)
L_004b: conv.r8
L_004c: ldc.r8 0
L_0055: bne.un.s L_0060
L_0057: ldloca.s CS$0$0001
L_0059: call instance bool [mscorlib]System.Nullable`1<float64>::get_HasValue()
L_005e: br.s L_0061
L_0060: ldc.i4.0
L_0061: stloc.1
L_0062: ret
}
IL の 0x2D ~ 0x3E 行に注意してください。MyDouble?
インスタンスを取得し、GetValueOrDefault
それを呼び出し、その上で暗黙的な演算子を呼び出し、結果を a にラップしてDouble?
、コンパイラが生成したCS$0$0001
ローカルに格納します。行 0x3F から 0x55 でCS$0$0001
値を取得し、'unwrap' 経由GetValueOrDefault
で 0 と比較します...しかし、ちょっと待ってください! MyDouble::op_Implicit
行 0x46 で実行する余分な呼び出しは何ですか?
C# プログラムをデバッグすると、確かに への 2 つの呼び出しが表示されます。 が初期化されていないimplicit operator Double(MyDouble value)
ため、失敗したのは 2 番目の呼び出しです。value
ここで何が起こっているのですか?