Having different options can be great if one of the options is really more suited for a specific task, but having more options can also make decisions harder when different options have different advantages and disadvantages.
I often need to stop and carefully think if an interface will or will not do a better job than a delegate and sometimes I even go back to my old code, that I initially implemented using delegates, to replace the delegates by interfaces. So, I decided it was time to write an article and show the advantages and disadvantages of both approaches.
Note: I know that interfaces have a different purpose than delegates, yet we can always use an interface where a delegate is expected and, in some cases, it is useful to do it.
I often see people asking if interfaces are faster than delegates or if delegates are faster than interfaces and then I see answers like:
- Interfaces are faster. Delegates are too damn slow;
- Delegates are faster because they are only a pointer to a method. Interfaces need to use a v-table to then find a delegate;
- They are equal, but delegates are easier to use.
Well, those are not true. Maybe in .NET 1 delegates were really slower but, actually, the truth is:
- Delegates are faster... to execute.
- Interfaces are faster... to get.
For example, in this code:
Action action = SomeMethod;
We are getting an
Action (a type of delegate) to call
SomeMethod. The problem is: delegates are reference types that contain both the instance and the pointer to a method. They are not a single pointer to a method and, by being reference types, they need to allocate memory. So, each time you transform a method to a delegate you are allocating a new object.
If delegates were value-types that could be different, but they are not and we need to live with them this way.
On the other hand, if we do this:
IRunnable runnable = this;
If the actual object implements
IRunnable we simple get the same reference with a different cast. There is no allocation involved. So, when I saw a speed comparison like this:
- For Delegates:
Stopwatch stopwatch = new Stopwatch();
for(int i=0; i<COUNT; i++)
Action action = SomeMethod;
- For Interfaces:
Stopwatch stopwatch = new Stopwatch();
for(int i=0; i<COUNT; i++)
IRunnable runnable = this;
I know that the interfaces are going to win. Not because they execute faster, but because at each iteration a new
Action delegate is allocated. But put the delegate getter and the interface getter outside of the loop and the delegate will be a little faster.
When creating events, for example, we put the delegate only once on the event and then the event can be invoked thousands of times. That is, a single allocation is done.
So, is there a winner?
Well, for events (aside from the fact that the
event keyword requires a delegate), delegates are really better.
But before saying that delegates are better or faster, let's see different cases.
In my opinion anonymous methods are the worst use of delegates but, at the same time, are becoming the most common ones.
When you do a call like this:
for(int i=0; i<count; i++)
MethodThatReceivesADelegate(() => SomeCall(i));
The compiler is, in fact, creating an instance to hold the value of
i. Then, it is creating another instance (the delegate) with a reference to that instance.
If an interface was used instead, it will need to allocate a single object, which will implement the interface.
Someone could complain that a single object is allocated to hold the value of
i then, at each iteration, the value inside that instance is changed. And it is even possible to argue that the compiler could optimize the delegate allocation, allocating it only once.
Well, for the delegate allocation I don't know, but about a single instance to hold the
i value that's true, and that's also a bug. If
MethodThatReceivesADelegate is giving the delegate to another thread, such other thread may receive the wrong value of
i. In C# 5 such behavior was corrected. That is, at each iteration a new object is created. This guarantees the good result if the delegate is given to another thread, but that also means that a new delegate instance should be allocated each time.
MethodThatReceivesADelegate is going to use the delegate only once, using an interface would do a better job. Unfortunately, we don't have the option to implement anonymous interfaces.
So, if it is for the convenience, the delegate will still be better. But if it is for performance, in this situation, an interface will be better because it will avoid one unnecessary allocation.
In fact I created the
IRunnable interface to force the users of my remoting framework to implement a new type instead of using anonymous delegates to solve the problem of the mutable
i value used in
fors (or any value used in
foreachs, as both kinds of for share the same problem) but that also gave me a little performance benefit.
Invoke and DynamicInvoke
At this moment we know that there are anonymous delegates but there are no anonymous interfaces and that for single use-cases interfaces will have a better performance than delegates because they will require a single object instead of two.
This already makes me think if I should use a delegate or an interface when I have a performance critical method that's going to receive a method to be executed but is going to execute it only once.
But there are more situations we can use such objects that are also performance related.
Do you ever need to call
DynamicInvoke instead of the direct delegate invoke? Maybe because you don't know the delegate's parameter types at compile time?
Well, having an interface you have the option to use a base interface to do the untyped call. I don't know why, but reflection invokes and delegates'
DynamicInvokes are extremely slow, much slower than simple doing the casts, the array-length validation and putting a try/catch to generate the
So, if you have something like:
public interface IDynamicInvokable
object DynamicInvoke(params object parameters);
And then you create any of your delegate like interfaces as sub-interfaces of
IDynamicInvokable, like this:
public interface IAction<T>:
void Invoke(T parameter);
You will be giving your users the possibility to call your interface with the typed
Invoke method or, if they don't know the exactly interface type at compile-time, they could use the more generic one, the
Note: I hate the name generics. To me, the
IDynamicInvokable is the most generic way to do the calls, and the
IAction<T> is the typed interface. So, when I said generic I was refering to the common and untyped way of doing the call, and not to generics, which are typed.
So, if I am going to do thousands of calls to a delegate, but using
DynamicInvoke instead of
Invoke, an interface will do a better job.
Again, I will question myself: Is the easy of use of anonymous delegates worth? Should I make it harder for the callers of my method only to have the best performance? Is this really going to impact the overall application performance?
I just said that I hate the name generics, as the code that uses generics is the typed code and we may want to have an untyped code, which I consider more generic.
But let's really talk about .NET generics. Imagine that you know the number of parameters a delegate has but you don't know their exact types. This is not the same as
DynamicInvoke, as such method simple receives the parameters as an array.
The generic covariance and contravariance can help a little on that situation. Only a little.
For example, we can get a
Func<string> as a
Func<object>. Or an
Action<object> as an
The reason is simple. When returning a value (the
Func case), a
string is an
object. It will not do any kind of conversion, it will simple return a
string that the caller will see as an untyped
object, but that's ok. And for the
Action case, it expects an
object and, again, a
string will be a valid
object, that's OK too.
But, what happens if I want to get a
Func<int> as a
Func<object>? Or the more common case, I want to pass all parameters cast as
object. Will it work?
The answer is no. Even if an
int is an
object in the .NET concept, all value types need boxing, which is an extra action. Simple trying to get an
int as an
object, without the boxing process, will create serious problems, and that's why it is not supported.
But interfaces have an advantage here, if well designed. I have a personal rule: Everytime I have a generic type (be it a class or even an interface) I also create a more generic interface... well, an untyped interface, with all the same methods and properties, but using
object instead of the generic argument types, and that's a base interface for the generic type.
That is, if I have an
IAction<T>, I will have an
IAction interface. If I have an
IAction<T1, T2> I will have an
The truth is: I will love to have the option of getting an
Action<int> as an
Action<> and let the .NET know I want to use a generic delegate untyped. But the .NET does not support untyped-uses of generic types, so I add an extra interface with the untyped methods and properties to my generic classes and interfaces and I achieve that. But that's simple impossible to do for delegates. So the interfaces are winning this point.
We already have the
Invoke and the
DynamicInvoke. What about a
My last two articles talked about conversions and I will return to that kind of situation.
If I use the
Converter<TInput, TOutput> delegate, the conversion should work or should throw an exception. But exceptions are the wrong way to say that a conversion failed if the code is prepared to deal with invalid values.
I considered creating another delegate (
TryConverter) that, well, will return a boolean value to tell if the conversion worked and use an out parameter for the result.
That will be great for the cases where we have an exception-free conversion, like
int.TryParse, but if we don't have one (like when the conversion is done by a
TypeConverter) we will need to catch the exception to return
That's not a real problem. The problem is that I still want to give the version that generates exception. In such case, the exception will be caugh to return false, to then generate another exception. Terrible.
But an interface solves such problem. With an interface we can have both methods, the
Convert and the
Convert can use a conversion that throws an exception and the
TryConvert can use a conversion that does not throws an exception.
If there is only a conversion that throws a exception, then the
TryConvert will be forced to catch the exception. If there is only a conversion that does not generates an exception and can fail, then the
Convert will need to check for that and generate the exception, but we will avoid the case where an exception is caugh to return false to then generate another exception.
In this case such versatility makes the interface the best solution, without a comparable delegate solution and surely giving better performance than a
TryConvert only delegate.
For those who read my other articles, you can expect an update of the Converters article to use the interface solution, which will support both
TryConvert and the
CastedGet will be eliminated as an untyped interface will do the job.
I still question myself if I should use an interface or a delegate when a method is going to receive such to use it only once as interfaces are faster for those cases and delegates have the compiler support to be anonymous.
For normal events I don't question that delegates are better, but for the most part (in general when I register delegates and allow users to find them) I am replacing delegates by interfaces, because the latter allows better typed to untyped support, which is easier to use and also performs better.
But let's finish by a small list of points:
- Are reference-types, so they allocate an entire object only to reference a method;
- Are the fastest to call when you know all parameter types at compile-time;
- Allow the use of anonymous delegates which really simplify creating single-line or very small delegates;
- Can reference a private method without requiring to create a new type.
- Don't allocate new objects, so they are faster to get;
- Are faster for single-use cases, as only one object will be created instead of two;
- If well designed allow for generic (untyped) uses that are faster than
DynamicInvoke of delegates;
- If well designed, generic interfaces can be accessed by an untyped interface that has the same signature methods and parameters, only changing the generic type parameters by
- Allow different calling possibilities (like the
- Are a little slower to call with the rightly typed parameters;
- Don't have anonymous compile-time support;
- Require full types to be created even if a single method is needed.
The sample application will only execute speed comparisons for the different situations.
Initially all the tests were executing 100 million of iterations, but the
DynamicInvoke was so slow that I decided to reduce the test to 10 millions of iterations.
The output of this application on my work computer is:
This application tests the speed of interfaces and delegates in
different situations. Compile it in release and execute it outside
Visual Studio to get the right results.
The following tests do 100 millions of iterations:
Testing delegate speed, the wrong way: 00:00:01.6483403
Testing interface speed, the wrong way: 00:00:00.5369746
Testing delegate speed, the right way: 00:00:00.3757670
Testing interface speed, the right way: 00:00:00.4831114
Testing anonymous delegate speed: 00:00:01.7475340
Testing an interface that does the same: 00:00:01.1950063
The following tests do only 10 millions of iterations:
Testing delegate's DynamicInvoke speed: 00:00:37.0368337
Testing interface's DynamicInvoke speed: 00:00:00.3218726
All the tests are finished. Press ENTER to exit.