Action & Func: Never write another delegate
With lambda expressions in C#, the FuncFirst let's look at the evolution of delegates from 1.1 to now. Delegates, simply are the method equivalent of function pointers. They let you pass a method call as an argument for later execution. The cool thing (and a garbage collection pitfall) is that a delegate creates a lexical closure, i.e. the delegate carries with it the object that the method gets called on. For garbage collection this means that a delegate prevents an object from being collection. That's why it's important to unsubscribe from those events you subscribed to.
But I digress. Let's define a delegate that returns an Integer and a method that matches that delegate:
delegate int IntProducerDelegate(); public int x = 0; public int IntProducer() { return x++; }
With the original .NET 1.0 syntax we'd create the delegate like this:
IntProducerDelegate p1 = new IntProducerDelegate(IntProducer);
Now we can call p1() and get an integer back, and since it's closure, each time we call p1() the originating objects x increases as does our return value.
Then, in .Net 2.0 we got anonymous delegates.
IntProducerDelegate p2 = delegate { return IntProducer(); }; // or with IntProducer's action inlined... IntProducerDelegate p3 = delegate { return x++; };
This got rid of the need to create a method just to pass along a closure that manipulated our object at a later time. The other thing that anonymous delegates re-inforce is that delegates just care about signature. IntProducerDelegate can get assigned any delegate that takes no argument and returns an int. That sounds like a perfect scenario for a delegate and in .NET 3.5, we got just that, a set of generic delegates called Func. Using Func, we quickly get to our lambda expression replacing the original delegate syntax like this:
// create a new Func delegate just like the IntProducerDelegate IntProducerDelegate p3 = new Func<int>(IntProducer); // which means that we don't need IntProducerDelegate at all anymore Func<int> p4 = delegate { return x++; }; // and the anonymous delegate can also be shorthanded with a lambda expression Func<int> p5 = () => { return x++; }; // which says, given that we take no argument "()", execute and return the following "return x++;"
However, before there ever was Func Now following the same evolution of syntax we get this:
So lambda syntax can be used to create either a Func
delegate void IntConsumerDelegate(int i);
public void IntConsumer(int i)
{
Console.WriteLine("The number is {0}", i);
}
IntConsumerDelegate c1 = new IntConsumerDelegate(IntConsumer);
IntConsumerDelegate c2 = new Action<int>(IntConsumer);
Action<int> c3 = delegate(int i) { Console.WriteLine("The number is {0}", i); };
Action<int> c4 = (i) => { Console.WriteLine("The number is {0}", i); };

2 Comments:
Fun<> takes maximum 4 input parameters. What if you need just 5 input paramters?
Ok, so "never write another delegate is hyperbolic". But in the end, Func is just a delegate, so you could define another n versions of Func with n parameters and keep those definitions in some core lib.
Post a Comment
<< Home