为什么CLRexception发生FatalExecutionEngineError?

我们正在使用封装数值的结构,我发现当在表达式中使用此结构的可空版本时,会发生FatalExecutionEngineError

附加信息:运行时遇到致命错误。 错误的地址位于0x729c1e04,位于线程0x52d8上。 错误代码是0xc0000005。 此错误可能是CLR中的错误,也可能是用户代码的不安全或不可validation部分中的错误。 此错误的常见来源包括COM-interop或PInvoke的用户封送错误,这可能会破坏堆栈。

我正在使用Visual Studio Premium 2013 Update 3这是源代码(C#,目标.NET Framework 4.5):

 using System; using System.Globalization; namespace ConsoleApplication4 { public struct Number { ValueType _val; private Number(double val) { this._val = val; } public static implicit operator double(Number val) { return Convert.ToDouble(val._val, CultureInfo.InvariantCulture); } public static implicit operator Number(double val) { return new Number(val); } } class Program { static void Main(string[] args) { Number? b = 1.2; var c = b - 1.2; Number b1 = 1.2; var c1 = b1 - 1.2; } } } 

注意,添加这个解决了这个问题,所以它并不紧急,但我很感兴趣为什么这个问题实际发生。

 public static implicit operator double(Number? val) { return Convert.ToDouble(val.GetValueOrDefault()._val, CultureInfo.InvariantCulture); } 

这看起来像编译器错误。 问题发生在Main的第二行。

  Number? b = 1.2; var c = b - 1.2; // The problem lies here 

注意由VS2013生成的IL,问题在于IL_005C和包含的代码,这是不必要的生成:

 .method private hidebysig static void Main(string[] args) cil managed { .entrypoint // Code size 116 (0x74) .maxstack 2 .locals init (valuetype [mscorlib]System.Nullable`1 V_0, valuetype [mscorlib]System.Nullable`1 V_1, valuetype [mscorlib]System.Nullable`1 V_2, valuetype [mscorlib]System.Nullable`1 V_3, valuetype [mscorlib]System.Nullable`1 V_4) // Number? b = 1.2; IL_0000: nop IL_0001: ldloca.s V_0 //b IL_0003: ldc.r8 1.2 IL_000c: call valuetype Test.Number Test.Number::op_Implicit(float64) IL_0011: call instance void valuetype [mscorlib]System.Nullable`1::.ctor(!0) IL_0016: nop IL_0017: ldloc.0 IL_0018: stloc.2 // b // var c = b - 1.2; IL_0019: ldloca.s V_2 // b IL_001b: call instance bool valuetype [mscorlib]System.Nullable`1::get_HasValue() IL_0020: brtrue.s IL_002d IL_0022: ldloca.s V_3 IL_0024: initobj valuetype [mscorlib]System.Nullable`1 IL_002a: ldloc.3 IL_002b: br.s IL_003e IL_002d: ldloca.s V_2 IL_002f: call instance !0 valuetype [mscorlib]System.Nullable`1::GetValueOrDefault() IL_0034: call float64 Test.Number::op_Implicit(valuetype Test.Number) // Um, what? First part of compiler bug is that it's needlessly creating a nullable float IL_0039: newobj instance void valuetype [mscorlib]System.Nullable`1::.ctor(!0) IL_003e: nop IL_003f: stloc.3 IL_0040: ldloca.s V_3 IL_0042: call instance bool valuetype [mscorlib]System.Nullable`1::get_HasValue() IL_0047: brtrue.s IL_0055 IL_0049: ldloca.s V_4 IL_004b: initobj valuetype [mscorlib]System.Nullable`1 IL_0051: ldloc.s V_4 IL_0053: br.s IL_0071 IL_0055: ldloca.s V_3 // Here's the real bug, though. It's passing float64 to a the op_Implicit that is expecting a Number struct IL_0057: call instance !0 valuetype [mscorlib]System.Nullable`1::GetValueOrDefault() IL_005c: call float64 Test.Number::op_Implicit(valuetype Test.Number) IL_0061: conv.r8 IL_0062: ldc.r8 1.2 IL_006b: sub IL_006c: newobj instance void valuetype [mscorlib]System.Nullable`1::.ctor(!0) IL_0071: nop IL_0072: stloc.1 IL_0073: ret } // end of method Program::Main 

Roslyn(也使用它的VS14 CTP)产生不同的IL,没有这个问题。 代码几乎完全相同,只是它省略了IL_0039IL_0061之间的IL。