Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/322.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 通过编译器生成的局部变量隐式转换为System.Double,并使用可为空的结构:为什么会失败?_C#_Nullable_Cil_Compiler Generated - Fatal编程技术网

C# 通过编译器生成的局部变量隐式转换为System.Double,并使用可为空的结构:为什么会失败?

C# 通过编译器生成的局部变量隐式转换为System.Double,并使用可为空的结构:为什么会失败?,c#,nullable,cil,compiler-generated,C#,Nullable,Cil,Compiler Generated,鉴于以下情况,为什么会抛出InvalidCastException?我不明白为什么它应该在bug之外(这是在x86中;x64在clrjit.dll中与0xc000005一起崩溃) 以下是为Main()生成的CIL: .method private隐藏静态void Main(字符串[]args)cil托管 { .入口点 .maxstack 3 .init( [0]valuetype[mscorlib]系统。可为null的'1我的, [1] 布尔比较, [2] valuetype[mscorlib]

鉴于以下情况,为什么会抛出InvalidCastException?我不明白为什么它应该在bug之外(这是在x86中;x64在clrjit.dll中与0xc000005一起崩溃)

以下是为
Main()
生成的CIL:

.method private隐藏静态void Main(字符串[]args)cil托管
{
.入口点
.maxstack 3
.init(
[0]valuetype[mscorlib]系统。可为null的'1我的,
[1] 布尔比较,
[2] valuetype[mscorlib]系统。可为空'1 CS$0$0000,
[3] valuetype[mscorlib]系统。可为空'1 CS$0$0001)
L_0000:没有
L_0001:ldloca.s我的
L_0003:ldc.r8 1
L_000c:newobj实例无效程序/MyDouble::.ctor(float64)
L_0011:调用实例void[mscorlib]System.Nullable`1::.ctor(!0)
L_0016:没有
L_0017:ldloc.0
L_0018:stloc.2
L_0019:ldloca.s CS$0$0000
L_001b:调用实例bool[mscorlib]System.Nullable`1::get_HasValue()
L_0020:brtrue.s L_002d
L_0022:ldloca.s CS$0$0001
L_0024:initobj[mscorlib]系统。可为null`1
L_002a:ldloc.3
L_002b:br.s L_003e
L_002d:ldloca.s CS$0$0000
L_002f:调用实例!0[mscorlib]System.Nullable`1::GetValueOrDefault()
L_0034:调用float64程序/MyDouble::op_隐式(valuetype程序/MyDouble)
L_0039:newobj实例无效[mscorlib]系统。可空`1::.ctor(!0)
L_003e:stloc.3
L_003f:ldloca.s CS$0$0001
L_0041:调用实例!0[mscorlib]System.Nullable`1::GetValueOrDefault()
L_0046:调用float64程序/MyDouble::op_隐式(valuetype程序/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:调用实例bool[mscorlib]System.Nullable`1::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
,对其调用隐式运算符,然后将结果包装为
Double?
并将其存储在编译器生成的
CS$0$0001
本地中。在第0x3F到0x55行中,我们通过
GetValueOrDefault
检索
CS$0$0001
值“unwrap”,然后与0进行比较请稍等!对第0x46行的
MyDouble::op_Implicit
的额外调用是什么

如果我们调试C#程序,我们确实会看到对
隐式运算符Double(MyDouble value)
的两个调用,并且是第二个调用失败,因为
value
没有初始化


这是怎么回事?

我觉得这确实像是一个编译器错误。IL提示编译器正在生成代码来转换MyDouble?使用转换运算符转换为double,然后转换为double?。但是当它再次在双精度上使用转换运算符时,它会急剧下降?。这是糟糕的,错误的参数类型。也没有必要

这和这个虫子很像。已经超过6年了,这一定是编译器中一个棘手的部分。我想是的。

这显然是一个C#编译器错误。谢谢你提醒我

顺便说一句,让用户定义的隐式转换运算符引发异常是一种不好的做法;文档说明隐式转换应该是那些从不抛出的转换。您确定不希望这是显式转换吗

不管怎样,回到错误上来

错误在C#3和C#4中重新出现,但在C#2中没有。这意味着这是我的错。当我重拨用户定义的隐式运算符代码以使其与表达式树lambda一起工作时,可能是我造成了这个错误。对不起!这段代码非常复杂,显然我没有对它进行充分的测试

代码应该做的是:

首先,重载解析尝试解析==的含义。两个参数都有效的best==运算符是比较两个可为空的双精度的提升运算符。因此,应将其分析为:

Boolean compare = (double?)my == (double?)0.0; 
(如果您这样编写代码,那么它在C#3和C#4中所做的事情是正确的。)

提升==运算符的含义是:

  • 评估两个参数
  • 如果两者都为空,则结果为真——显然,在这种情况下不会发生这种情况
  • 如果一个为空,另一个为非空,则结果为假
  • 如果两者都不为null,则将两者展开为double并作为double进行比较
现在的问题是“评估左手边的正确方法是什么?”

这里我们从MyDouble中提取了一个用户定义的转换运算符?加倍?。正确的行为是:

  • 如果“my”为null,则结果为null double
  • 如果“my”不为null,则结果是用户定义的my.Value到double的转换,然后是double到double?的转换
显然,在这个过程中出现了一些问题


我将在我们的数据库中输入一个bug,但任何修复都可能错过将其写入下一个service pack的更改的最后期限。如果我是你的话,我会考虑解决办法的。再次为这个错误道歉。

非常有趣-我真的无法理解这个错误。如果你从Reflector复制并粘贴反汇编,这不会发生。@Kragen-我确实从Reflector复制并粘贴了反汇编…听起来确实像个bug。可能是我的错。处理用户定义的转换操作的编译器代码极其复杂。我明天回办公室时会看一看。为错误道歉。@Eric-很好,谢谢。当你们在那个里的时候,我相信你们可以添加提升成员访问器操作符——听起来很正交,对我来说是未来的突破。(我开玩笑!我开玩笑!)同意了。对MyDouble::op_Implicit的第二次调用是错误的。感谢您挖掘连接问题;你说得对,看起来是这样
.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 
}
Boolean compare = (double?)my == (double?)0.0;