在IL中的空引用上调用实例方法

时间:2010-08-10 10:26:08

标签: c# null cil

在IL中的空引用上调用实例方法是否正确? 有没有任何例子可以证明这一点..?

3 个答案:

答案 0 :(得分:10)

是的,这是可能的,只要该方法不使用this,因为CLR不对call指令进行空检查。

您必须手动修改IL,因为C#编译器几乎总是生成callvirt指令 1

有关详细信息和示例,请参阅此博客文章:

  

<强> Instance Methods Called on null References

<强>示例

.method private hidebysig static void  Main(string[] args) cil managed
{
    .entrypoint
    // Code size       18 (0x12)
    .maxstack  1
    .locals init ([0] class SomeClass o, [1] string hello)
    IL_0000:  nop
    IL_0001:  ldnull
    IL_0002:  stloc.0
    IL_0003:  ldloc.0
    IL_0004:  call       instance string SomeClass::GetHello()
    IL_0009:  stloc.1
    IL_000a:  ldloc.1
    IL_000b:  call       void [mscorlib]System.Console::WriteLine(string)
    IL_0010:  nop
    IL_0011:  ret
} 

1 实际上,即使在简单的callvirt指令足够的情况下,C#编译器发出call的原因是为了防止在空引用上调用实例方法。使用编译器的这种行为,用户将获得NullReferenceException,因此避免了在空指针上调用方法的奇怪情况。 Eric Gunnerson在一段时间的博客文章中对此进行了解释: Why does C# always use callvirt? Gishurelated question中也有一个很好的解释。< / p>

答案 1 :(得分:5)

请参阅我的blog entry了解相关信息。

IL代码示例:

.class Program
{
  .method static void  Main(string[] args)
  {
    .entrypoint
    .locals init ([0] class Program p)
    ldloc.0 // but wait, it's still null!
    call   instance void Program::Awesome()
    ret
  } 

  .method instance void Awesome()
  {
    ldstr      "Awesome!"
    call       void [mscorlib]System.Console::WriteLine(string)
    ret
  } 

  .method public specialname rtspecialname instance void  .ctor()
  {
    ldarg.0
    call       instance void [mscorlib]System.Object::.ctor()
    ret
  }
}

答案 2 :(得分:3)

CLR不需要它,它是该语言的实现细节。 C#和VB.NET执行测试。 C ++ / CLI是一种值得注意的托管语言。只要实例方法不引用任何类成员,那么什么都不会出错。如果是,NullReferenceException将正常引发,只是让你很难找到原因。

#include "stdafx.h"

using namespace System;

ref class Test {
public:
    void Run() {
        Console::WriteLine("no problem");
    }
};

int main(array<System::String ^> ^args)
{
    Test^ obj = nullptr;
    obj->Run();
    return 0;
}