Delegates - real life example

acheo

Member
Joined
Aug 5, 2009
Messages
5
Programming Experience
Beginner
Hi,

While many books explains in detail how to use delegates, they fail to give meaningfull real life examples. Everything I have seen so far could have been programmed without delegates.

Could anyone give me a real scenario where the use of delegate would be option #1. Any code would be welcomed as well.

thanks
 
I'll give a few examples, some of which exist within the Framework and one that is of my own doing. Firstly, let's consider exactly what the purpose of delegates is. A delegate is an object that contains a reference to a method. If you create a delegate instance, you can pass it around like you can any other object, allowing you to then invoke it anywhere, any time, even if you don't have a reference to the object of which the method is a member. You will generally use delegates when you know that you want to execute a method that has a specific number and type of parameters and a specific return type without caring what the method does or, at the very least, how it does it.

The first example I'll use is events, which many people don't realise are based on delegates. An event is basically a collection of delegates and raising the event is basically looping through the delegates and invoking each one, thus executing each method. Let's take probably the most commonly used event: the Click of a Button. A lot of people talk about doing something "in a Button" but it's important to realise that the code that does something is in the form, not in the Button. You write a method in the form and it is registered as a handler for the Click event of the Button. That involves creating a delegate of type EventHandler that refers to your method and then adding that to the collection of delegates stored in the Button's Click event. When the user clicks the Button, the Button will loop through any and all delegates in its Click event. Note that the method is a member of the form but it's executed by the Button via the delegate.

With reference to what I said earlier, the Button knows that it wants to execute a method with one Object parameter and one EventArgs parameter and doesn't return anything, but it doesn't care what that method actually does or how it does it. You can have multiple methods handling that one event if you like, because the event can store multiple delegates, and they can be from different places if you like. The Button doesn't care. All it knows is that it has delegates that it needs to invoke when it gets clicked.

More to follow...
 
A real life example can be List(Of T).Sort method with a Comparison(Of T) delegate as parameter, where sorting is performed according to the delegated method (implementation compares two items of type T).
System.Linq.Enumerable class has lots of extension methods that takes delegates as parameters, these extend just about any list or array type. Linq expressions are often accompanied by lambda expressions, which are inline methods that appear as delegates.
Task Parallel Library that handles async invocation of tasks and callbacks rely heavily on the use of delegates, and traditionally multi-threading in .Net has always been done using delegates.
 
My next example is actually two examples that both relate to the Array class. The first one is the Array.ConvertAll class. It takes an array as input and returns a new array of the same size. It also takes a delegate and each element in the output array is the result of invoking that delegate and passing the element at the same index in the source array.

What's good about this is that this one method allows you to convert an array of any type to an array of any other type using any conversion routine you want. The ConvertAll method doesn't care what the method referred to by this delegate does, only that it has a single parameter of the correct type and it returns the correct type.

For instance, let's say that you have an array of Integers and you want to create three more arrays that contain the same numbers multiplied by 10, 100 and 1000. Without delegates, you would have to do something like this:
Dim numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
Dim upperBound = numbers.GetUpperBound(0)
Dim tens(upperBound) As Integer
Dim hundreds(upperBound) As Integer
Dim thousands(upperBound) As Integer

For i = 0 To upperBound
    tens(i) = numbers(i) * 10
    hundreds(i) = numbers(i) * 100
    thousands(i) = numbers(i) * 1000
Next
With ConvertAll you can do it like this:
Dim numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
Dim tens = Array.ConvertAll(numbers, Function(n) n * 10)
Dim hundreds = Array.ConvertAll(numbers, Function(n) n * 100)
Dim thousands = Array.ConvertAll(numbers, Function(n) n * 1000)
That's a fairly simple example but the same principle applies for as complex a conversion as you like. You can use a Lambda to generate the delegate as I've done there or you can write a conventional method and create a delegate referring to that.

The second example is the Array.Sort method, or at least the overload that takes a Comparison(Of T) delegate as an argument. Like ConvertAll, Sort takes an array and a delegate as arguments but this time, the delegate refers to a method that accepts two values and returns an Integer that indicates their relative order. The Array.Sort method follows a sorting algorithm and uses the delegate to compare pairs of elements to decide whether to swap them or not, which results in a sorted array. For example, let's say that you have an array of Strings where each one consists of a letter and a digit and you want to sort by the digit first and the letter second:
Dim values = {"B7", "B4", "A2", "C5", "C1", "A1"}

Array.Sort(values, Function(s1, s2)
                       Dim d1 = s1(1)
                       Dim d2 = s2(1)
                       Dim result = d1.CompareTo(d2)

                       If result = 0 Then
                           Dim l1 = s1(0)
                           Dim l2 = s2(0)

                           result = l1.CompareTo(l2)
                       End If

                       Return result
                   End Function)

Console.WriteLine(String.Join(", ", values))
Again, you can use a Lambda as I have or a delegate that refers to a named method.

More to follow...
 
Thanks to all of you. Much appreciated!

However, I still don't see the advantage of using delegates over a BackgroundWorkers in the case of asynchronous operations.
 
BackgroundWorker is just a wrapper class that makes it easy to add async processing to forms, internally it uses delegate.BeginInvoke to start the work, in other words a threadpool callback, and is otherwise filled with delegate usage.
 
Thanks to all of you. Much appreciated!

However, I still don't see the advantage of using delegates over a BackgroundWorkers in the case of asynchronous operations.

As JohnH says, the BackgroundWorker class itself uses delegates. It was only introduced in .NET 2.0. Prior to that, you would have have to use the ThreadPool directly to get the same functionality. You would have had to call ThreadPool.QueueUserWorkItem and pass it a delegate for the method that you wanted to execute on the background thread to get the equivalent of the DoWork event. You would also have had to call BeginInvoke and pass it a delegate for the method that you wanted to execute on the UI thread to get the equivalent of the ProgressChanged and RunWorkerCompleted events. The BackgroundWorker is simply a convenient wrapper for all that so that you don't have to work with delegates directly but they are still used in pretty much exactly the same way under the hood to get the same effect.
 
Back
Top