为什么C#编译器产生的方法调用来调用IL BaseClass的方法方法、编译器、BaseClass、IL

2023-09-04 07:19:29 作者:无酒不欢

比方说,我们有以下示例code在C#:

Lets say we have following sample code in C#:

class BaseClass
  {
    public virtual void HelloWorld()
    {
      Console.WriteLine("Hello Tarik");
    }
  }

  class DerivedClass : BaseClass
  {
    public override void HelloWorld()
    {
      base.HelloWorld();
    }
  }

  class Program
  {
    static void Main(string[] args)
    {
      DerivedClass derived = new DerivedClass();
      derived.HelloWorld();
    }
  }

当我ildasmed以下code:

When I ildasmed the following code:

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       15 (0xf)
  .maxstack  1
  .locals init ([0] class EnumReflection.DerivedClass derived)
  IL_0000:  nop
  IL_0001:  newobj     instance void EnumReflection.DerivedClass::.ctor()
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  callvirt   instance void EnumReflection.BaseClass::HelloWorld()
  IL_000d:  nop
  IL_000e:  ret
} // end of method Program::Main

不过,csc.exe的转换 derived.HelloWorld(); - > callvirt实例无效EnumReflection.BaseClass ::的HelloWorld()。这是为什么?我没有提到的BaseClass在方法的任何地方。

However, csc.exe converted derived.HelloWorld(); --> callvirt instance void EnumReflection.BaseClass::HelloWorld(). Why is that? I didn't mention BaseClass anywhere in the Main method.

和同样如果调用的BaseClass ::的HelloWorld()那么我希望通话而不是 callvirt ,因为它看起来直接呼叫到的BaseClass ::的HelloWorld()方法。

And also if it is calling BaseClass::HelloWorld() then I would expect call instead of callvirt since it looks direct calling to BaseClass::HelloWorld() method.

推荐答案

将呼叫转到BaseClass的:: HelloWorld的,因为BaseClass的是定义方法的类。虚拟调度工作在C#中的方式是,该方法被称为上的基类,并且虚拟调度系统是负责确保该方法的最衍生倍率被调用

The call goes to BaseClass::HelloWorld because BaseClass is the class that defines the method. The way virtual dispatch works in C# is that the method is called on the base class, and the virtual dispatch system is responsible for ensuring that the most-derived override of the method gets called.

的埃里克利珀的这个答案是非常丰富: http://stackoverflow.com/a/5308369/385844

This answer of Eric Lippert's is very informative: http://stackoverflow.com/a/5308369/385844

这是他的博客系列的题目是:的http:// blogs.msdn.com/b/ericlippert/archive/tags/virtual+dispatch/

As is his blog series on the topic: http://blogs.msdn.com/b/ericlippert/archive/tags/virtual+dispatch/

你有这是为什么这种方式实现的任何想法?会发生什么,如果它是直接调用派生类的ToString方法?这样didnt太大的意义对我第一眼...

Do you have any idea why this is implemented this way? What would happen if it was calling derived class ToString method directly? This way didnt much sense this to me at first glance...

它是实现这种方式,因为编译器不跟踪的运行时类型的对象,其引用的只是编译时类型。随着您发布的code,可以很容易地看到,呼叫将进入DerivedClass的方法实现。但是,假设导出变量是这样初始化的:

It's implemented this way because the compiler does not track the runtime type of objects, just the compile-time type of their references. With the code you posted, it's easy to see that the call will go to the DerivedClass implementation of the method. But suppose the derived variable was initialized like this:

Derived derived = GetDerived();

这有可能是 GetDerived()返回 StillMoreDerived 的实例。如果 StillMoreDerived (或之间的任何类派生 StillMoreDerived 的继承链)覆盖的方法,那么这将是不正确调用派生的实施方法。

It's possible that GetDerived() returns an instance of StillMoreDerived. If StillMoreDerived (or any class between Derived and StillMoreDerived in the inheritance chain) overrides the method, then it would be incorrect to call the Derived implementation of the method.

要查找所有可能的值的变量可以容纳通过静态分析是解决停机问题。随着.NET程序集,问题更糟糕的是,因为组装可能不是一个完整的程序。因此,案件编译器在其中可以合理地证明导出数不成立的引用,更派生的对象(或空引用)就不大。

To find all possible values a variable could hold through static analysis is to solve the halting problem. With a .NET assembly, the problem is even worse, because an assembly might not be a complete program. So, the number of cases where the compiler could reasonably prove that derived doesn't hold a reference to a more-derived object (or a null reference) would be small.

需要多少费用增加这种逻辑,因此它可以发出通话,而不是 callvirt 指令?毫无疑问,成本将远远超过得到的小利高。

How much would it cost to add this logic so it can issue a call rather than callvirt instruction? No doubt, the cost would be far higher than the small benefit derived.