For the last couple of months I’ve been using .NET 2 for the first time. There are a bunch of great new language features in there, generics being the most obvious (and implemented properly in .NET rather than the hack in Java), but another biggy is anonymous delegates.
One use of anonymous delegates is just to inline methods, e.g.:
public void MyFunkyExample() { Timer timer = new Timer(); timer.Elapsed += DoSomething; timer.Interval = 1000; timer.Start(); } private void DoSomething(object sender, ElapsedEventArgs e) { Console.WriteLine("Hello World! (at {0})", e.SignalTime); }
becomes:
public void MyFunkyExample() { Timer timer = new Timer(); timer.Elapsed += delegate (object sender, ElapsedEventArgs e) { Console.WriteLine("Hello World! (at {0})", e.SignalTime); }; timer.Interval = 1000; timer.Start(); }
This is handy occasionally when you have a 1 or 2 line method that only gets used as a delegate.
However, the real power of anonymous delegates comes when using them as closures. Take the following code as an example:
public void MyFunkyClosureExample() { string[] names = new string[] { "Fred", "Bob", "Sue" }; foreach (string name in names) { SetupTimer(name); } } private void SetupTimer(string name) { NamedWriter writer = new NamedWriter(name); Timer timer = new Timer(); timer.Elapsed += writer.Write; timer.Interval = 1000; timer.Start(); } private class NamedWriter { private readonly string name; public NamedWriter(string name) { this.name = name; } public void Write(object sender, ElapsedEventArgs e) { Console.WriteLine("Hello {0}! (at {1})", name, e.SignalTime); } }
Now we want to have several timers, but the event of each has different behaviour depending on some local value when the timer event is bound. Pre C# 2.0 you have to setup a custom class to handle this, but compare with the anonymous delegate version:
public void MyFunkyClosureExample() { string[] names = new string[] { "Fred", "Bob", "Sue" }; foreach (string name in names) { SetupTimer(name); } } private void SetupTimer(string name) { Timer timer = new Timer(); timer.Elapsed += delegate(object sender, ElapsedEventArgs e) { Console.WriteLine("Hello {0}! (at {1})", name, e.SignalTime); }; timer.Interval = 1000; timer.Start(); }
This is much cleaner since we don’t need to introduce that custom class.
Using closures can get a little hairy, especially when you’re trying to figure out which value of variables actually get bound – check out one of Jeremy Stell-Smith’s recent entries on the subject. But of course, you’ll have plenty of automated tests to check what you’re doing, right? š
PS – apologies for the lack of decent formatting – I’m still getting to grips with WordPress.