此基准测试似乎表明直接在对象引用上调用虚方法比在对象实现的接口的引用上调用它更快.
换一种说法:
interface IFoo {
void Bar();
}
class Foo : IFoo {
public virtual void Bar() {}
}
void Benchmark() {
Foo f = new Foo();
IFoo f2 = f;
f.Bar(); // This is faster.
f2.Bar();
}
Run Code Online (Sandbox Code Playgroud)
来自C++世界,我原本预计这两个调用都将以相同的方式实现(作为简单的虚拟表查找)并具有相同的性能.C#如何实现虚拟调用以及通过接口调用时显然可以完成的"额外"工作是什么?
好的,答案/评论我到目前为止暗示了通过接口进行虚拟呼叫的双指针解除引用,而不是通过对象进行虚拟呼叫的一个取消引用.
那么请有人解释为什么这是必要的?C#中虚拟表的结构是什么?是否"平坦"(对于C++来说是典型的)或不是?在C#语言设计中做出的设计权衡导致了什么?我不是说这是一个"糟糕"的设计,我只是好奇为什么它是必要的.
简而言之,我想了解我的工具在引擎盖下做了什么,这样我就可以更有效地使用它.如果我不再获得"你不应该知道"或"使用其他语言"类型的答案,我将不胜感激.
为了说清楚,我们没有在这里处理一些JIT优化的编译器,它删除了动态调度:我修改了原始问题中提到的基准,以在运行时随机实例化一个类或另一个类.由于实例化在编译之后和程序集加载/ JITing之后发生,因此在这两种情况下都无法避免动态调度:
interface IFoo {
void Bar();
}
class Foo : IFoo {
public virtual void Bar() {
}
}
class Foo2 : Foo {
public override void Bar() { …Run Code Online (Sandbox Code Playgroud)