Never declare another C♯ delegate again

I recently did some refactoring of our .NET Compact Framework codebase. The goal was to tighten up our use of delegates a bit. In case you didn’t know, there’s never a need to declare custom delegates in C♯ code.

By way of a quick review, delegates are C♯’s strongly-typed function pointers. Closures, callbacks, and events are all implemented using delegates. The delegate statement declares the signature of a function pointer and gives that signature a name. You can then assign a variable of that delegate type to a method or an anonymous function whose signature matches the delegate.

Thelonious Monk, Howard McGhee, Roy Eldridge, and Teddy Hill, ca. 1947 This example, obtained via 1940s corporate espionage, illustrates how the club software running the legendary Minton’s Playhouse kept out unwanted patrons and novice musicians who couldn’t hack the hot new bebop tunes.

The body of the Nightclub#Bouncer function is defined outside the Nightclub class, possibly in another program altogether. (That part of the source code was lost when an intrepid corporate spy died trying to smuggle it out of Minton’s. It has been painstakingly reconstructed here.)

An annoying thing about the delegate statement is that it’s hard to know where to put it. Do we nest it inside a class, as shown above? Do we put it in a separate .cs file? Do we group multiple delegate statements in a file, or put each one in its own file?

Another misfortune of custom delegates is that each one is yet another thing that we have to come up with a name for. Naming is often cited as one of the harder things programmers must do. I myself have uttered Hungarian obscenities such as delegate void VoidFormDoubleDelegate(Form form, double @double); when a good name escaped me or when I wanted to reuse the declaration for multiple purposes.

Wouldn’t it be nice to do away with the delegate statement altogether in our applications? We can.

All delegates of a particular arity are alike and can be unified through generics. So all we need is a generic delegate declaration for each possible arity.

Microsoft has provided those declarations in the form of the System.Action and System.Func generic delegates, introduced as long ago as .NET 2.0. These generic delegates accommodate nullary procedures, unary procedures, binary procedures, ternary procedures, and so forth through 10-ary procedures. (‘Nullary’ means zero parameters; it’s represented by either the System.Action delegate or the System.Func<TResult> delegate. A 10-ary procedure can use System.Action<T1 … T10> or System.Func<T1 … T10, TResult>.)

Clear as mud, right?

Here’s how the Minton’s code can be refactored to eliminate the unnecessary delegate declaration. The client code using Nightclub remains the same.

Admittedly, the refactoring amounts to a minuscule improvement in this example. Projects that make heavy use of custom delegates will benefit more dramatically.

Perhaps you need a delegate for a function that has 11 parameters and a return value. In that case you need to declare your own 11-parameter generic delegate because the .NET Framework Class Library only declares generic delegates up to an arity of 10.

If you need to declare an 11-parameter delegate, you’ve got bigger problems to solve than the question of where to put a delegate statement. end of article

Blog comments powered by Disqus
Follow Me on GitHub