当前位置:  开发笔记 > 编程语言 > 正文

在新的c#6"的情况下调用而不是callvirt?" 空检查

如何解决《在新的c#6"的情况下调用而不是callvirt?"空检查》经验,为你挑选了2个好方法。

鉴于这两种方法:

    static void M1(Person p)
    {
        if (p != null)
        {
            var p1 = p.Name;
        }
    }

    static void M2(Person p)
    {
        var p1 = p?.Name;
    }

为什么M1 IL代码使用callvirt:

IL_0007:  brfalse.s  IL_0012
IL_0009:  nop
IL_000a:  ldarg.0
IL_000b:  callvirt   instance string ConsoleApplication4.Person::get_Name()

和M2 IL使用call:

brtrue.s   IL_0007
IL_0004:  ldnull
IL_0005:  br.s       IL_000d
IL_0007:  ldarg.0
IL_0008:  call       instance string ConsoleApplication4.Person::get_Name()

我只能猜到它,因为在M2我们知道它p不是空的,它就像它

new MyClass().MyMethod();

这是真的吗?

如果是,如果p在其他线程中将为null?



1> Hans Passant..:

callvirtM1中是标准的C#代码生成.它提供了语言保证,即永远不能使用空引用调用实例方法.换句话说,p != null如果它为null ,它确保并生成NullReferenceException.您的显式测试不会改变这一点.

这种保证非常好,调试NRE如果它this是null 则变得非常多毛.反而更容易诊断呼叫站点的事故,调试器可以快速向您显示它是p麻烦制造者.

但当然callvirt不是免费的,虽然成本非常低,在运行时一个额外的处理器指令.因此,如果它可以代替call那么代码将更快半个纳秒,给予或采取.它实际上可以与elvis运算符一起使用,因为它已经确保引用不为null,因此C#6编译器利用了它并生成调用而不是callvirt.



2> Dudi Keleti..:

我认为现在很明显

在触发事件之前,这是一种检查null的简单且线程安全的方法.它是线程安全的原因是该功能仅评估左侧一次,并将其保存在临时变量中.MSDN

所以call在这里使用指令是安全的.

我写了一篇关于C#生成之间call和之间差异的博客文章callvirtcallvirt

感谢Dan Lyons的MSDN链接.

推荐阅读
mobiledu2402851203
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有