Delegates, Events and Async callbacks

A delegate is nothing more than some syntax around the idea of pointers to functions, such that the compiler can perform robust type-safety checking on them. That is, if you say that you want delegate 'D' to hold a pointer to a function returning void and taking an int parameter, the ompiler will complain if you then try to assign to D a delegate representing a function returning int and taking an int parameter (or any other conceivable mismatch, for that matter).

Delegates are enormously handy on their own for situations where you might want to use one of a number of methods to perform some task, but you won't know until run-time which method to use. For instance, let's say you're writing an application that allows users to compare two images by showing the per-pixel difference between the two images. Of course, there are many
ways you might compute the difference between pixels:

RGB color difference: (R', G', B') = (|R2-R1|, |G2-G1|, |B2-B1|)
brightness difference:
Bright1 = (R1+G1+B1)/3;
Bright2 = (R2+G2+B2)/3;
diff = |Bright2-Bright1|;
(R1',G1',B1') = (diff,diff,diff);

Those are just two; you can no doubt think of many more (show where image 2 is brighter than image 1, redder, whatever, etc.). Without delegates, to handle this situation you'd have to do something like this:




This is fine, but has the penalty that for every pixel in the images, you have to evaluate the switch statement. Basically, you're being forced to decide which method to use every time you want to compare two pixels, rather than being allowed to decide up-front. With delegates, you can decide up-front (that is, outside of your loop over all pixels in the images). In this example, I would make a hash table that stored the delegates so I could access them by my "mode" variable:



etc...

then later:



Much cleaner code, and faster, too. You can effectively do this same trick in C and/or C++ with function pointers, but not in a type-safe way.

Events are just a wrapper around the concept of invoking every item in a list of delegates when some condition happens, with the exception that you use the "event" keyword when you declare one. The "event" keyword tells the compiler that, even though under the covers an event is a lot like any other public method, only the class that declares the event is allowed to call (or "raise") it. Events, as you're probably aware, are tightly linked to user interface programming because they're just the thing for responding to user events. Events are what you want any time you say to yourself "I need X to happen whenever Y happens, but I have no way of knowing when, exactly, Y is going to happen." Windows Forms use Events to signal, to anybody who cares,
that various things have happened.

Events make use of delegates because events are allowed to pass data to the various other pieces of code that have subscribed to the event. If you're creating a new event, obviously you don't want anybody subscribing to your event unless they're going to handle the event with a function that's capable of accepting whatever sort of data you want to pass to them. Because delegates are type-safe, using them to implement events allows the compiler to enforce this sort of restriction.

Events are also a total life-saver when you get into multi-threaded programming (which is pretty much impossible to avoid if you're writing any sort of interesting WinForms app). There are lots of great resources out on the web for explaining why you need to use separate threads to perform long-running operations in WinForms apps. I won't cover that ground again
here; suffice it to say that you'll constantly find yourself in the situation where you want to run something in its own thread, and then you need a method of letting the UI know when the thread is done, and thus has some sort of result, so that the UI can show the results to the user. What you do in this case is make an event so that the thread can say "Ok, I'm done", and have the UI subscribe to that event so it can update itself at the appropriate time. If your operation is _really_ long running, you can create another event to signal progress, so that the UI can update a ProgressBar control or something like that. Basically, Events are exactly what you want to use for communicating safely between threads.

Asynchronous callbacks are very similar to events in terms of what they do. They both provide a mechanism for one piece of code to say to another "go do this, and let me know when you're done". The difference is that with an event, many pieces of code can be notified when the event occurs, whereas with an async callback, only the caller can be notified. Why? Because
essentially an event, recall, is a wrapper around a list of callbacks. To subscribe to an event, you use the += operator to subscribe your callback (that is, your event handler) onto the event object. The event class handles the grunt-work of invoking all the subscribed callbacks when the
event is raised. Conversely, functions that take an explicit callback parameter (such as BeginInvoke), don't support any mechanism for handling a list of callbacks. They just remember the one callback that was passed to them as a parameter, and then invoke that when they're finished.

So in short:

use Async callbacks if you're sure that you'll only need to notify the code
that called you of completion.
use Events for multi-threading situations, or if you want to enable more
than one piece of code to be notified of the things your code is doing.
use Delegates any time you want simple run-time determination of what method
to use to accomplish some task.

Got this in one of the forums and I think it's a very good explanation of Delegates, Events and Async callbacks! Thanks!

コメント

人気の投稿