CoreCLR源码探索(六) NullReferenceException是如何发生的

本文详细探讨了在CoreCLR中NullReferenceException的产生过程,包括源码、IL、汇编代码层面的分析,以及在Linux和Windows上的异常处理机制。文章还讨论了特殊情况的null检查,并进行了性能测试,揭示了CoreCLR实现null检查的原因和优势。
摘要由CSDN通过智能技术生成

NullReferenceException可能是.Net程序员遇到最多的例外了, 这个例外发生的如此频繁,以至于人们付出了巨大的努力来使用各种特性和约束试图防止它发生, 但时至今日它仍然让很多程序员头痛, 今天我将讲解这个令人头痛的例外是如何发生的.

可以导致NullReferenceException发生的源代码

我们先来看看什么样的代码可以导致NullReferenceException发生:

第一份代码, 调用函数时this等于null导致例外发生

using System;
namespace ConsoleApp1{    
class Program    {      
 public class MyClass        {        
     public int MyMember;    

       public void MyMethod() { }        }                static void Main(string[] args)        {            MyClass obj = null;            obj.MyMethod();        }    } }

第二份代码, 访问成员时this等于null导致例外发生

using System;

namespace ConsoleApp1{  

 class Program    {      
 public class MyClass        {        
    public int MyMember;    
       public void MyMethod() { }        }                static void Main(string[] args)        {            MyClass obj = null;            Console.WriteLine(obj.MyMember);        }    } }

观察生成的IL代码

再来看看生成的IL:

第一份代码的IL

.method private hidebysig static 
    void Main (
        string[] args
    ) cil managed 
{
    // Method begins at RVA 0x2050
    // Code size 11 (0xb)
    .maxstack 1
    .entrypoint
    .locals init (
        [0] class ConsoleApp1.Program/MyClass
    )

    IL_0000: nop
    IL_0001: ldnull
    IL_0002: stloc.0
    IL_0003: ldloc.0
    IL_0004: callvirt instance void ConsoleApp1.Program/MyClass::MyMethod()
    IL_0009: nop
    IL_000a: ret
} // end of method Program::Main

第二份代码的IL

.method private hidebysig static 
    void Main (
        string[] args
    ) cil managed 
{
    // Method begins at RVA 0x2050
    // Code size 16 (0x10)
    .maxstack 1
    .entrypoint
    .locals init (
        [0] class ConsoleApp1.Program/MyClass
    )

    IL_0000: nop
    IL_0001: ldnull
    IL_0002: stloc.0
    IL_0003: ldloc.0
    IL_0004: ldfld int32 ConsoleApp1.Program/MyClass::MyMember
    IL_0009: call void [System.Console]System.Console::WriteLine(int32)
    IL_000e: nop
    IL_000f: ret
} // end of method Program::Main

看出什么了吗? 看不出吧, 我也看不出, 这代表了null检查不是在IL层面实现的, 我们需要继续往下看.

观察生成的汇编代码

看生成的汇编代码:

第一份代码生成的汇编 (架构不同生成的代码也不同, 以下代码是windows x64生成的)

    10:         static void Main(string[] args) {
  00007FF9F5C30482 56                   push        rsi  00007FF9F5C30483 48 83 EC 30          sub         rsp,30h  00007FF9F5C30487 48 8B EC             mov         rbp,rsp  00007FF9F5C3048A 33 C0                xor         eax,eax  00007FF9F5C3048C 48 89 45 20          mov         qword ptr [rbp+20h],rax  00007FF9F5C30490 48 89 45 28          mov         qword ptr [rbp+28h],rax  00007FF9F5C30494 48 89 4D 50          mov         qword ptr [rbp+50h],rcx  00007FF9F5C30498 83 3D 49 48 EA FF 00 cmp         dword 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值