Interfaces allow us to design better code, but complicates the matter when the code needs to be optimized. The jitter (sometimes the compiler can do this too) has an arsenal of techniques that are used at runtime to try to see through our code and perform better. As of .NET Framework 5, these optimizations are done while the application is working (and they can be reapplied if the jitter detects poor performances). For a glimpse of what it can do, have a look at RyuJIT Tutorial.
Calls at interface methods are dispatched through a V-Table when speaking at high level. However, at low level, the call can go through or even being inlined when the jitter is able to infer that the call site satisfies certain constraints. This technique is called devirtualization.
Generally if the jit can determine the type of the this object at an interface call, it can devirtualize and then potentially inline. There are two main mechanisms for determining types:
deduce the type from flow analysis within a method
enable PGO, have that observe the possible types for this, and then test for the most likely type when rejitting or in a future run of the process.
Last I looked flow analysis can enable devirualization and inlining in a relatively small fraction of interface call cases (say no more than 10%). Success here requires that there be some "organic" evidence of type identity (constructor call or type test) upstream from the interface site. Inlining can help bring together the needed information but currently the inlining heuristics do not include increased devirtualization potential as part of their evaluation. That may change soon (see eg #53670).
PGO is quite effective at devirtualizing interface calls; most studies I have done show upwards of 80% of interface call sites have one dominant implementing class for this.
Inlining
The inlining heuristics are complicated and difficult to summarize concisely. Roughly speaking a method will be inlined if:
there is a direct call to the method, OR the jit can devirtualize an interface or virtual call, AND
the method being invoked is small (16 bytes of IL or fewer), OR
the method being invoked is marked with AggressiveInlining, OR
the method is medium sized (17 to ~100 bytes of IL) and the inline heuristics determine the inline is worthwhile
The above definition comes from Andy Ayers in a longstanding issue aimed to improve performances in a case like this (#7291).
As the runtime and the jitter improve over time, code that previously wasn't optimized, now can benefit certain optimizations. Indeed, it happened a month ago, with additional improvements in the upcoming framework.
Side note
Micro benchmarking requires certain technical and statistical skills as many things can go wrong (e.g. noise, dynamic frequency of the processor, optimizations, code warmup...). There are frameworks that allows you to perform such measurements in more statically-friendly and repeatable environment. The .NET framework uses Benchmark .NET, it may help you in having a better understanding of your code.