Delegates vs. Events vs. AsyncCallback

  • Thread starter Thread starter LP
  • Start date Start date
L

LP

Hello!

I am still transitioning from VB.NET to C#. I undertand the basic concepts
of Delegates, more so of Events and somewhat understand AsyncCallback
methods. But I need some clarification on when to use one over another? If
anyone could provide any additional info, your comments, best practices, any
good articles, specific examples, etc.

Thank you
 
I am still transitioning from VB.NET to C#. I undertand the basic concepts
of Delegates, more so of Events and somewhat understand AsyncCallback
methods. But I need some clarification on when to use one over another? If
anyone could provide any additional info, your comments, best practices,
any
good articles, specific examples, etc.

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 compiler 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:

// compute pixel-difference:
for(int x = 0, x < image.Width; x++)
for(int y = 0; y < image.Height; y++)
{
Color c;
switch(mode)
{
case "rgbdifference"':
c = rgbdiff( Image1.GetPixel(x,y), Image2.GetPixel(x,y) );
case "brightnessdifference":
c = brightnessdiff( Image1.GetPixel(x,y), Image2.GetPixel(x,y) );
etc...
}
result.SetPixel(x,y,c);
}

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:

Hashtable h = new Hashtable();
h.Add("rgbdifference", new PixelDiffDelegate(rgbdiff));
h.Add("brightnessdifference", new PixelDiffDelegate(brightnessdiff));
etc...

then later:

PixelDiffDelegate d = h[mode]; // pick the pixel difference method the user
wants.
for(int x = 0, x < image.Width; x++)
for(int y = 0; y < image.Height; y++)
result.SetPixel(x,y, d(Image1.GetPixel(x,y), Image2.GetPixel(x,y)));

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.

Hope that helps! Sorry that was so long, but this is some tricky stuff. I
remember it took me a while to get my head around it when I was first
learning WinForms/C# programming.
 
Thanks, great overview!!!

One more question; As far as Events, is it accurate to say that events
internally are implemented as delegates?

Thanks again,

Jason Black said:
I am still transitioning from VB.NET to C#. I undertand the basic concepts
of Delegates, more so of Events and somewhat understand AsyncCallback
methods. But I need some clarification on when to use one over another? If
anyone could provide any additional info, your comments, best practices,
any
good articles, specific examples, etc.

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 compiler 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:

// compute pixel-difference:
for(int x = 0, x < image.Width; x++)
for(int y = 0; y < image.Height; y++)
{
Color c;
switch(mode)
{
case "rgbdifference"':
c = rgbdiff( Image1.GetPixel(x,y), Image2.GetPixel(x,y) );
case "brightnessdifference":
c = brightnessdiff( Image1.GetPixel(x,y), Image2.GetPixel(x,y) );
etc...
}
result.SetPixel(x,y,c);
}

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:

Hashtable h = new Hashtable();
h.Add("rgbdifference", new PixelDiffDelegate(rgbdiff));
h.Add("brightnessdifference", new PixelDiffDelegate(brightnessdiff));
etc...

then later:

PixelDiffDelegate d = h[mode]; // pick the pixel difference method the user
wants.
for(int x = 0, x < image.Width; x++)
for(int y = 0; y < image.Height; y++)
result.SetPixel(x,y, d(Image1.GetPixel(x,y), Image2.GetPixel(x,y)));

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
 
You're welcome! Happy to help.

And yes events are, fundamentally, just delegates; the "event" keyword is
literally just an access modifier that prevents code outside of the class
that declares the event from invoking the event. The functionality around
maintaining a list of subscribers and calling each of them when an event is
raised all comes from the functionality of delegates themselves.

Jessie Liberty provides a much more in-depth explanation of the relationship
between events and delegates in his "Programming C#" book.


LP said:
Thanks, great overview!!!

One more question; As far as Events, is it accurate to say that events
internally are implemented as delegates?

Thanks again,

Jason Black said:
I am still transitioning from VB.NET to C#. I undertand the basic concepts
of Delegates, more so of Events and somewhat understand AsyncCallback
methods. But I need some clarification on when to use one over another? If
anyone could provide any additional info, your comments, best
practices,
any
good articles, specific examples, etc.

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 compiler 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:

// compute pixel-difference:
for(int x = 0, x < image.Width; x++)
for(int y = 0; y < image.Height; y++)
{
Color c;
switch(mode)
{
case "rgbdifference"':
c = rgbdiff( Image1.GetPixel(x,y), Image2.GetPixel(x,y) );
case "brightnessdifference":
c = brightnessdiff( Image1.GetPixel(x,y), Image2.GetPixel(x,y) );
etc...
}
result.SetPixel(x,y,c);
}

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:

Hashtable h = new Hashtable();
h.Add("rgbdifference", new PixelDiffDelegate(rgbdiff));
h.Add("brightnessdifference", new PixelDiffDelegate(brightnessdiff));
etc...

then later:

PixelDiffDelegate d = h[mode]; // pick the pixel difference method the user
wants.
for(int x = 0, x < image.Width; x++)
for(int y = 0; y < image.Height; y++)
result.SetPixel(x,y, d(Image1.GetPixel(x,y), Image2.GetPixel(x,y)));

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.

Hope that helps! Sorry that was so long, but this is some tricky stuff. I
remember it took me a while to get my head around it when I was first
learning WinForms/C# programming.
 
Back
Top