Cameron Hotchkies

Categories

  • Coding

Tags

  • .net
  • C#
  • code
  • delegates
  • generics

I’ve been writing a lot of C# middleware lately and it’s not uncommon to have a need for throwaway delegates.

For example:

private delegate int rInt_StringInt(string arg1, int arg2);

private int Delegated(String Foo, int Bar) { 
    // Here be dragons 
} 

private void DoSomething() { 
    // BeginInvoke calls a delegate on the main thread 
    // but for the purpose of this example it's just 
    // something that takes a delegate 
    BeginInvoke(new rInt_StringInt(Delegated), new object[] {"Pizza", 1234}); 
} 

While this works fine, it leaves one with the “You’re doing it wrong” feeling. After working on a project where it became obvious I was going to require hundreds of these throwaway delegates I started to do some digging. In .Net 3.5, Microsoft introduced the Action and Func delegates. These utilize generics to generate these throwaway delegates in a clear manner.

The example above becomes:

private int Delegated(String Foo, int Bar) { 
    // Here be dragons 
} 

private void DoSomething() { 
    // BeginInvoke calls a delegate on the main thread 
    // but for the purpose of this example it's just 
    // something that takes a delegate 
    BeginInvoke(new Func<string, int, int>(Delegated), new object[] {"Pizza", 1234}); 
} 

This in itself isn’t too drastic of a change since it is such a trivial example. When you add in multiple developers, each with their own shorthand for creating throwaway delegates is where you’ll be happy you used them.

One thing to keep in mind is that in .Net 3.5, the Action and Func delegates were limited to 4 parameters. In .Net 4.0 this has been extended to 9. In the case that you are limited to 3.5 or are working against an insane API that requires 12 parameters to do anything, you can easily roll your own variations of these same delegates.

 
protected delegate TResult Func<T1, T2, T3, T4, T5, TResult> (T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5); 

If you want to get tricky and start accepting out or ref parameters, you can as well:

 
protected delegate TResult OutFuncR1<T1, OT1, TResult> (T1 arg1, out OT1 outArg1); 

But at this point you need to start coming up with your own name for the generic versions of the delegates which begins to create the multiple developer shorthand issue again. Another thing to keep in mind is that the out parameters will be changed in the array you pass to the Delegate invocation method but not whatever populated the array in the first place.