gpt4 book ai didi

c# - 为什么 callvirt IL 指令会导致虚方法中的递归调用?

转载 作者:太空狗 更新时间:2023-10-29 20:49:25 25 4
gpt4 key购买 nike

在这种情况下,IL 并不总是对 virtual 方法使用 callvirt 指令:

class MakeMeASandwich{
public override string ToString(){
return base.ToString();
}
}

在这种情况下,据说 IL 将产生 call 而不是 callvirt 其中产生 callvirt 是为了检查 variable 是否为 null,否则抛出 NullReferenceException

  1. 如果使用 callvirt 而不是 call,为什么递归调用会发生直到堆栈溢出?
  2. 如果使用call,那么它什么时候检查它用来调用方法的实例变量是否为空?

最佳答案

Why does a recursive invocation happen till stack overflow if callvirt is used instead of call?

因为这样你的代码就完全一样了:

override string ToString()
{
return this.ToString();
}

这显然是无限递归,前提是给定的方法是 ToString 的最重要版本。

If call is used, then how come it checks whether the instance variable it uses to call the methods is null or not?

这个问题是不可回答的,因为这个问题假定了一个谎言。调用指令检查接收者的引用是否为空,所以问为什么调用指令检查空值没有任何意义。

让我为您改写成一些更好的问题:

Under what circumstances does the C# compiler generate a call vs a callvirt?

如果 C# 代码对虚方法 执行非虚调用,则编译器必须生成调用,而不是 callvirt。唯一一次真正发生这种情况是在使用 base 调用虚拟方法时。

如果 C# 代码正在执行一个虚拟调用,那么编译器必须生成一个 callvirt。

如果 C# 代码正在非虚拟方法 上执行非虚拟调用,则编译器可以选择生成 call 或 callvirt。两者都会起作用。 C# 编译器通常选择生成 callvirt。

The call instruction does not automatically do a null check, but callvirt does. If the C# compiler chooses to generate a call instead of a callvirt, is it also obligated to generate a null check?

没有。如果已知接收者不为空,则 C# 编译器可以跳过空检查。例如,如果您为非虚方法 M 说 (new C()).M(),那么编译器生成 call 指令是合法的没有空检查。我们知道 (1) 该方法不是虚拟的,因此它不必是 callvirt;我们可以选择是否使用callvirt。我们知道 (2) new C() 永远不会为空,因此我们不必生成空检查。

如果 C# 编译器不知道接收者不为空,那么它将生成一个 callvirt,或者生成一个空检查然后调用。

关于c# - 为什么 callvirt IL 指令会导致虚方法中的递归调用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10213413/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com