c# - 非虚实例方法继承是如何解决的?

标签 c# inheritance compiler-construction clr il

通过 C# 引用 CLR,它读起来就好像 call 会在运行时通过 CLR 搜索由基类型定义的方法。

Then call IL instruction is used to call an instance or virtual method, you must specify a variable that refers to an object. The type of the variable itself indicates which type defines the method that the CLR should call. If the variable's type doesn't define the method, base types are checked for a matching method.

When calling a non-virtual instance method, JIT locates the type object that corresponds to the type of the variable being used to make the call. If the type didn't defined the method being called, JIT walks down the class hierarchy toward Object looking for this method. It can do this because each type object has a field in it that refers to its base type. Then, JIT locates the entry in the type object's method table that refers to the method being called.

但是,根据以下示例,似乎在编译时检查方法继承:

class A
{
    public void Foo() {}
}
class B : A {}
void Main()
{
    new B().Foo();
}
IL_0000:  newobj      UserQuery+B..ctor
IL_0005:  call        UserQuery+A.Foo // Not B.Foo, resolved by C# complier.

我说得对吗?

即使我这样做:

void Main()
{
    B x = new B();
    x.Foo();
}
IL_0000:  newobj      UserQuery+B..ctor
IL_0005:  stloc.0     // x
IL_0006:  ldloc.0     // x
IL_0007:  callvirt    UserQuery+A.Foo // Not B.Foo, resolved by C# complier.

更新:

现在我明白分辨率是静态的。

而且我相信 JIT 需要的变量类型实际上是元数据标记指定的类。

重复警报

实际上它与 Is Richter mistaken when describing the internals of a non-virtual method call? 重复。

很高兴还有人和我有同样的问题。

最佳答案

引用涉及变量的类型,而不是变量引用的对象实例的类型。变量类型是静态已知的,因此所有决策都是静态的。

C# 编译器解析要调用的确切方法并将其编码到 IL 中。如果引用的程序集没有更改,则 JIT 本身不必执行任何方法解析。 C# 编译器这样做是因为它想要应用 C# 语义,而不是 CLR 语义。

要回答您编辑的问题:

  1. JIT 无法查看任何对象引用,因为它需要静态决定。它查看堆栈上元素的类型,无论该元素来自何处。在可验证的代码中,这是明确的。不过,变量类型不会影响方法绑定(bind)(IOW,你的问题 1 是无关紧要的)。
  2. 是的,方法是通过程序集+类型+方法名称和签名(包括)引用的。返回类型。非常精确。

关于c# - 非虚实例方法继承是如何解决的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17808622/

相关文章:

c# - 如何在指定时间执行指定任务

javascript - 使用 John Resig 的 "simple JavaScript inheritance"如何调用 super 方法以及方法中的额外代码?

javascript - 如何将 JavaScript 原型(prototype)对象扩展两次?

c++ - 从模板参数继承是不好的做法吗?

asp.net - 在asp.Net中,在控制标签中写代码会产生编译错误

compiler-construction - 编译器中的寄存器分配

c# - Blazor 服务器端支持的浏览器

c# - WinSCP .NET 程序集打开存储的 session

c# - 如何使用 mysql 删除附加行

compiler-construction - 使用逆波兰表示法 (RPN) 进行算术表达式评估