-
-
Save rogeralsing/965c3ba740f0c43bd90e to your computer and use it in GitHub Desktop.
| public class Foo<T> where T: IDoStuff | |
| { | |
| private T _stuffer; | |
| public Foo(T stuffer) | |
| { | |
| _stuffer = stuffer; | |
| } | |
| public void Bar() | |
| { | |
| //will this be a direct call or resolved through interface lookup? | |
| _stuffer.StuffTheStuff(); | |
| } | |
| } |
It will be via the interface, but as a "constrained call". This has the advantage that it works without boxing if T is a value type that implements the interface. If you just type the parameter / field / whatever as the interface it will force value-types to be boxed. Likewise, assigning a T to an IDoStuff will force value-type to be boxed; keeping it as a T throughout: does not.
Constrained calls result in virtual call if T is a reference-type, and static call if T is a value-type that implements or overrides the method. If you call .ToString / .Equals etc and the value-type doesn't override them, it will have to box/virtual-call. It makes this decision at the JIT stage per distinct final T: the IL is identical for all T. A good reason for custom structs to always override all the object virtual methods! Yet another reason why the JIT output can be shared for all ref - types, but needs to be per value-type: it isn't just the size - individual method calls can be very different depending on what methods the value-type overrides.
Awesome answer!
Too bad I couldn't hack my way past virtual lookup though.
Well you can: use structs :)
But really, I don't think that is going to be an important part of any performance issue.
since
_stufferis of a concrete type when used, will the calls to it's methods be direct?or will they be resolved through the interface
IDoStuffdue to the constraint?in short, is this faster, than if the
_stufferfield would have been declared asIDoStuff