在 IL 中对空引用调用实例方法

发布于 2024-09-14 01:16:47 字数 46 浏览 1 评论 0原文

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

Is it correct that a instance method can be called on a null reference in IL..?
Is there any example to show this..?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

不打扰别人 2024-09-21 01:16:47

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

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

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

在空引用上调用实例方法

示例

.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实际上是 C# 编译器发出 的原因callvirt 即使在简单的 call 指令就足以防止在空引用上调用实例方法的情况下。通过编译器的这种行为,用户将得到 NullReferenceException ,因此可以避免在空指针上调用方法的奇怪情况。 Eric Gunnerson 在不久前的一篇博客文章中解释了这一点:为什么 C# 总是使用 callvirt? < a href="https://stackoverflow.com/users/1695/gishu">Gishu 在 相关问题

Yes, this is possible, as long as the method doesn't use this because the CLR does not do a null check for call instructions.

You would have to modify the IL by hand as the C# compiler would almost always generate a callvirt instruction1.

See this blog post for details and an example:

Instance Methods Called on null References

Sample

.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
} 

1In fact the reason that the C# compiler emits callvirt even in cases where a simple call instruction would be sufficient is to prevent calling instance methods on null references. With this behavior of the compiler users will get a NullReferenceException so the weird situation of calling a method on a null pointer is avoided. Eric Gunnerson explained this in a blog post some time ago: Why does C# always use callvirt? Gishu also has a nice explanation in a related question.

撞了怀 2024-09-21 01:16:47

请参阅我的 博客条目以获取信息。

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
  }
}

See my blog entry for info.

IL code sample:

.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
  }
}
智商已欠费 2024-09-21 01:16:47

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;
}

The CLR doesn't require it, it is an implementation detail of the language. C# and VB.NET perform the test. C++/CLI is a notable managed language that permits it. As long as the instance method doesn't reference any class members then nothing goes wrong. If is does, NullReferenceException will be raised as normal, merely giving you a hard time finding out why.

#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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文