我们正在使用一个封装数值的结构,我发现当在表达式中使用此结构的可空版本时,会发生FatalExecutionEngineError
:
其他信息:运行时遇到致命错误。该 错误的地址是0x729c1e04,在线程0x52d8上。错误 代码是0xc0000005。此错误可能是CLR或中的错误 用户代码的不安全或不可验证部分。这个的常见来源 错误包括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);
}
答案 0 :(得分:10)
这看起来像编译器错误。问题发生在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<valuetype Test.Number> V_0,
valuetype [mscorlib]System.Nullable`1<float64> V_1,
valuetype [mscorlib]System.Nullable`1<valuetype Test.Number> V_2,
valuetype [mscorlib]System.Nullable`1<float64> V_3,
valuetype [mscorlib]System.Nullable`1<float64> 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<valuetype Test.Number>::.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<valuetype Test.Number>::get_HasValue()
IL_0020: brtrue.s IL_002d
IL_0022: ldloca.s V_3
IL_0024: initobj valuetype [mscorlib]System.Nullable`1<float64>
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<valuetype Test.Number>::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<float64>::.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<float64>::get_HasValue()
IL_0047: brtrue.s IL_0055
IL_0049: ldloca.s V_4
IL_004b: initobj valuetype [mscorlib]System.Nullable`1<float64>
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<float64>::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<float64>::.ctor(!0)
IL_0071: nop
IL_0072: stloc.1
IL_0073: ret
} // end of method Program::Main
Roslyn(也使用它的VS14 CTP)产生不同的IL,但没有这个问题。代码几乎完全相同,只是它忽略了IL_0039
和IL_0061
之间的IL。