I have interface I , an abstract class A , concrete classes for both of them, and a concrete class C for 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 tested the 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(); } }
Test results consistently show that calling A.Do() will 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 several variations of this structure, such as having one Impl class Impl from both A and I , or linearizing the hierarchy using A implementation I and reproducing the same effect every time.
The difference, of course, is not very important - what is 700 picoseconds between friends? - but I would like to understand what happens in the .NET runtime. I understand why C.Do() is the fastest to date - there is no indirectness associated with finding a method implementation - but why did calling through an abstract class beat the call through the interface? I am using .NET Core 1.1 on OSX with x64 RyuJit.
source share