在这种情况下,IL并不总是将callvirt
指令用于virtual
方法:
class MakeMeASandwich{
public override string ToString(){
return base.ToString();
}
}
在这种情况下,据说IL将生成
call
而不是callvirt
,其中会生成callvirt
来检查variable
是否为null
,否则抛出NullReferenceException
。callvirt
而不是call
,为什么在堆栈溢出之前会进行递归调用? call
,则何时检查用于调用方法的实例变量是否为null? 最佳答案
因为这样,您的代码与以下代码完全相同:
override string ToString()
{
return this.ToString();
}
如果给定的方法是ToString的最主要版本,则这显然是无限递归。
该问题无法回答,因为该问题具有虚假性。调用指令不会检查接收方的引用是否为null,因此询问为什么调用指令检查null毫无意义。
让我为您改写一些更好的问题:
如果C#代码正在虚拟方法上进行非虚拟调用,则编译器必须生成一个调用,而不是callvirt。真正发生这种情况的唯一时间是使用
base
调用虚拟方法时。如果C#代码正在执行虚拟调用,则编译器必须生成一个callvirt。
如果C#代码正在非虚拟方法上进行非虚拟调用,则编译器可以选择生成call或callvirt。任何一个都可以。 C#编译器通常选择生成callvirt。
否。如果已知接收者不为空,则C#编译器可以跳过空检查。例如,如果您说的是非虚拟方法M的
(new C()).M()
,则编译器在不进行空检查的情况下生成call
指令是合法的。我们知道(1)该方法不是虚拟的,因此它不必是callvirt
;我们可以选择是否使用callvirt
。而且我们知道(2)new C()
永远不会为空,因此我们不必生成空检查。如果C#编译器不知道接收方不为null,则它将生成一个callvirt,或者将生成一个null检查,然后进行调用。
关于c# - 为什么callvirt IL指令会导致虚拟方法中的递归调用?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/10213413/