Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.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
为什么.NET IL null检查不能按预期工作?_.net_Cil - Fatal编程技术网

为什么.NET IL null检查不能按预期工作?

为什么.NET IL null检查不能按预期工作?,.net,cil,.net,Cil,我正在编写一些自定义IL,需要与returnsomestaticfield!=无效。这是我自然得出的结论: volatile.ldsfld ...SomeStaticField //volatile is needed here for unrelated reasons ldnull ceq not ret 然而,这似乎不起作用。我确认SomeStaticField为null,但该函数最终将返回true。我知道C#使用分支来实现这样的构造,我也可以使用它,但这让我很困惑,为什么这不会产生预期

我正在编写一些自定义IL,需要与
returnsomestaticfield!=无效。这是我自然得出的结论:

volatile.ldsfld ...SomeStaticField //volatile is needed here for unrelated reasons
ldnull
ceq
not
ret
然而,这似乎不起作用。我确认SomeStaticField为null,但该函数最终将返回true。我知道C#使用分支来实现这样的构造,我也可以使用它,但这让我很困惑,为什么这不会产生预期的行为

完整且可验证的示例(作为库):


not
计算其操作数的位补码:
~1
-2
,非零为真。否定布尔值的标准方法是
ldc.i4.0;ceq

正如@HansPassant所指出的,做
!=null
直接比较是
cgt.un
——当解释为无符号值时,所有有效引用都“大于零”。第I.12.1.5节中明确记录了此类比较的安全性:

具体而言,对象引用可以是:

  • 创建为空引用(
    ldnull
  • 托管指针还有几个附加的基本操作

  • 基于两个托管指针的无符号比较和条件分支(
    bge.un
    bge.un.s
    bgt.un
    bgt.un.s
    ble.un
    ble.un.s
    blt.un
    blt.un.s
    cgt.un
    clt.un

  • 它应该会起作用。请提供一个。
    不是
    不是吗。始终最好让C#编译器先生成msil,然后使用ildasm.exe查看它。几乎没有人想到使用
    cgt.un
    @Heinzi I updated添加了一个完整的示例(为了简单起见,将ldsfld替换为ldnull)@HansPassant对null和引用类型使用cgt安全吗?我认为这只对数字有效你想针对C#编译器提交错误报告吗?呵呵。它是安全的。我一直使用
    brtrue
    brfalse
    进行空值检查,因为我不必进行
    ldnull
    比较。在这种情况下,比较版本更可取吗?@Kyle:不。如果出于任何原因(可能是为了组合表达式并稍后保存到分支上),需要将比较结果作为布尔值,那么您就可以这样做。如果您想立即分支,
    brtrue
    brfalse
    确实是实现这一点的常用方法(事实上,
    brinst
    brnull
    都是别名)。当然,您也可以分支并加载一个常量布尔值;什么更好取决于您正在做什么以及JIT编译器最终生成什么。
    .assembly extern /*23000001*/ mscorlib
    {
      .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..
      .ver 4:0:0:0
    }
    .assembly 'BareMetal'
    {
      .custom instance void class [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::'.ctor'() =  (
                    01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78   // ....T..WrapNonEx
                    63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01       ) // ceptionThrows.
    
      .hash algorithm 0x00008004
      .ver  1:0:0:0
    }
    .module BareMetal.dll 
    
    
    .namespace Earlz.BareMetal
    {
      .class public auto ansi abstract sealed beforefieldinit BareMetal
            extends [mscorlib]System.Object
      {
        .method public static hidebysig
               default bool FooTest ()  cil managed
        {
            .maxstack 2
            ldnull
            ldnull
            ceq
            not
            ret
        }
    
      }
    }