I have an interface I
, an abstract class A
, concrete classes for both of those, and a concrete class C
to use as a baseline.
interface I
{
void Do();
}
abstract class A
{
public abstract void Do();
}
class C
{
public void Do() {}
}
class IImpl : I
{
public void Do() {}
}
class AImpl : A
{
public override void Do() {}
}
I benchmarked calls to C.Do()
, I.Do()
and A.Do()
using BenchmarkDotNet
.
public class Bench
{
private C _c;
private I _i;
private A _a;
[Setup]
public void Setup()
{
_c = new C();
_i = new IImpl();
_a = new AImpl();
}
[Benchmark(Baseline = true)]
public void ConcreteCall()
{
_c.Do();
}
[Benchmark]
public void InterfaceCall()
{
_i.Do();
}
[Benchmark]
public void AbstractCall()
{
_a.Do();
}
}
The benchmark results consistently show the call to A.Do()
to be faster than I.Do()
.
Method | Mean | StdErr | StdDev | Scaled | Scaled-StdDev |
-------------- |---------- |---------- |---------- |------- |-------------- |
ConcreteCall | 0.0673 ns | 0.0114 ns | 0.0440 ns | 1.00 | 0.00 |
InterfaceCall | 1.4944 ns | 0.0084 ns | 0.0325 ns | 62.92 | 74.68 |
AbstractCall | 0.8178 ns | 0.0139 ns | 0.0539 ns | 34.43 | 40.99 |
I tried a few variations on this structure, such as having a single Impl
class derived from both A
and I
, or linearising the hierarchy by having A
implement I
, and reproduced the same effect every time.
The difference isn't much, of course - what's 700 picoseconds between friends? - but I'd like to understand what's going on in the .NET runtime. I understand why C.Do()
is the fastest by far - there's no indirection involved in looking up the method implementation - but why does the call via the abstract class beat the call via the interface? I'm using .NET Core 1.1 on OSX with x64 RyuJit.