c# - 为什么 C# 编译器会产生方法调用以在 IL 中调用 BaseClass 方法

标签 c# .net il

假设我们在 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();
    }
  }

当我输入以下代码时:

.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 instance void EnumReflection.BaseClass::HelloWorld()。这是为什么?我没有在 Main 方法中的任何地方提到 BaseClass。

而且如果它正在调用 BaseClass::HelloWorld() 那么我希望 call 而不是 callvirt 因为它看起来直接调用BaseClass::HelloWorld() 方法。

最佳答案

调用转到 BaseClass::HelloWorld,因为 BaseClass 是定义该方法的类。虚拟分派(dispatch)在 C# 中的工作方式是在基类上调用方法,虚拟分派(dispatch)系统负责确保调用最派生的方法覆盖。

Eric Lippert 的回答非常有用:https://stackoverflow.com/a/5308369/385844

正如他关于该主题的博客系列:http://blogs.msdn.com/b/ericlippert/archive/tags/virtual+dispatch/

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

以这种方式实现是因为编译器不跟踪对象的运行时类型,只跟踪它们引用的编译时类型。使用您发布的代码,很容易看出调用将转到该方法的 DerivedClass 实现。但是假设 derived 变量是这样初始化的:

Derived derived = GetDerived();

GetDerived() 有可能返回 StillMoreDerived 的实例。如果 StillMoreDerived(或继承链中 DerivedStillMoreDerived 之间的任何类)覆盖该方法,则调用 派生方法的实现。

通过静态分析找到一个变量可能持有的所有可能值就是解决停机问题。对于 .NET 程序集,问题更严重,因为程序集可能不是完整的程序。因此,编译器可以合理地证明 derived 不包含对更多派生对象(或空引用)的引用的情况很少。

添加此逻辑以发出 call 而不是 callvirt 指令需要多少成本?毫无疑问,成本将远远高于所获得的微薄 yield 。

关于c# - 为什么 C# 编译器会产生方法调用以在 IL 中调用 BaseClass 方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10219188/

相关文章:

c# - 转到 C# WPF 中的第一页

methods - 不需要 ret 的 MSIL 方法

c# - IL 优化尝试导致执行速度变慢

c# - 条件属性如何工作?

c# - 使用 WCF 更改规范化算法

c# - 简化嵌套的 IF 语句

c# - LINQ - 完全外部连接

c# - ASP.NET Web 窗体和标识 : Move IdentityModels. cs 到另一个项目

c# - 使用 C# 中的 2D 字符串数组填充 JavaScript 数组

.net - 在 .net 中使用 start.process 运行 R 脚本