With .NET 2.0 and with the new "anonymous delegates" feature in C#, doing multi threaded responsive GUIs is now easier. In fact, you get multiple choices on how to accomplish this task. But which choice is the best? and what does "best" really mean? more elegant? faster? more readable? all of the above?
Here's a little scenario for you. Assume there is a method that displays a string on the GUI, but may be called by a different thread than the GUI. The method has only a single string parameter. here are three versions of how you can implement this method and keep it thread safe. The last one is my favorite.
First, I'll declare two "generic" delegates. Each one is used in a different version of the method.
delegate void
Func<T>(T t)
;
private void
displayError(
string
message)
{
if
(InvokeRequired)
{
Func<
string
> del
=
displayError
;
Invoke(del, message)
;
return;
}
errorDisplay.Show(message)
;
}
This version uses a generic delegate which takes a string argument, then if Invoke is needed, it "Invokes" the delegate passing in the string argument. Note that passing in the string is not a strongly typed operation and may result in runtime errors if we make a mistake in the parameter order for example. That's why I don't like this version at all. But it's the most commonly used that I've seen, which is why I'm writing this.
delegate void
Func()
;
private void
displayError1(
string
message)
{
if
(InvokeRequired)
{
Func del
= delegate
{ displayError1(message)
;
}
;
Invoke(del)
;
return;
}
errorDisplay.Show(message)
;
}
This version uses a delegate with no parameters, and uses the "delegate" directive to create a delegate that calls the same method with the "message" parameter. Notice how lovely it is to be able to use a local scoped variable such as "message" in out delegate. It makes life much simpler because now all we ever need to do is just use
one delegate signature for all of our thread-safe GUI work. This version is much better than the previous one because it's type-safe. We can't make a mistake in parameter order or type, or we'll have a build error. But this version is
still not as elegant as I would like.
private void
displayError2(
string
message)
{
Func del
= delegate
{
errorDisplay.Show(message)
;
}
;
Invoke(del)
;
}
This version uses the delegate directive to actually create the full functionality of our method.
Notice that we *always* invoke the code in here using the "Invoke" method which is thread-safe, even if this is not required. Also note how much less code we have to write here, and that we always use the same delegate signature to accomplish this. Not only that, in contrast to the other two implementations, we only write the calling code
once inside the delegate, and not another time outside of it which can lead to maintenance problem due to duplication. This method, to me, is the most elegant and readable. I don't really care about one extra call to the "Invoke" method, since this method is GUI related, and obviously is called after a long operation which was async. 10 nano seconds more or less won't matter one bit. This is the method I'd encourage you to use, even though it seems a bit un-orthodox at first, it is clearly the simplest of the three, with less code, less duplication and more readability.
Colorized by: CarlosAg.CodeColorizer
Unfortunately, all three methods require you to use C#, since anonymous delegates are not present in VB.NET yet.
Thoughts?