I’m not sure why, but I get the feeling that anonymous delegates in C# 2.0 haven’t really had much of a press and people aren’t really that aware of them.
Essentially, it lets you declare the delegate inline a la:
public delegate void MyDelegate(); ... private void DoIt(MyDelegate codeBlock) { codeBlock(); } public void AddInstrumentToPrice(string message) { DoIt(delegate { Console.WriteLine(message); }); }
Closures!
On my current project we’ve found some great use for them, in particular, once we’d started refactoring some GUI code into the Model-View-Presenter pattern as described in Michael Feathers’ Humble Dialog paper (pdf). This tidied a lot of the code up nicely, keeping the GUI code focused, allowing us to then focus a little more on improving the behaviour of the UI.
The Windows Forms UI needed to show a progress bar indicating how far it was through pricing all of the selected trades. But, with our pricing occurring within the same thread our UI was locking. So, you push the processing out into a worker thread and then you can update both, right? Wrong, because .NET will throw an exception should you attempt do this - because Windows itself doesn’t like it when you do.
The Control
class includes an Invoke
method that executes a Delegate
on the UI thread. So, to ensure our UI updates execute on the UI thread we can write the following
public void calculateButton_click (object m, mouseeventargs e) { this.Invoke(delegate { resultsList.Items.Add("a result!") });}
Testing With NUnitForms
Once we had that written, we had an additional problem - we now had code executing on different threads making it difficult to test through the GUI. Sure, we had a lot of tests that drove out the implementation of the Presenter, but, it’s always nice to know that the GUI is behaving, and you’re driving something end to end.
Our solution — use the Strategy pattern to extract out the behaviour around how code is executed in the GUI, we use an anonymous method/delegate to pass a code block to a class that either executes it on the same thread (for our tests), or, uses ThreadPool.QueueUserWorkItem
.
So our end-to-end NUnitForms test might look something like
[SetUp]public void Initialisation() { form = new SampleForm(new SameThreadWorker());}class SameThreadWorker : IWorker { public void Do(WaitCallback block) { block(null); }} [Test]public void ShouldShowResultInListAfterCalculating() { ClickButton("calculateResults"); Assert.IsTrue(ListContains("resultsList", "My Result"))}
Which is handled inside the form by
public void calculateButton_click (object m, mouseeventargs e) { worker.Do(delegate { resultsList.Items.Add("a result!") });}
And our default worker for the GUI? Something a little like
class UserWorkItemWorker : IWorker { public void Do(WaitCallback block) { ThreadPool.QueueUserWorkItem(block); }}
Probably not the best way of doing it, but certainly better than most I could think of, and all thanks to anonymous delegates.