|
Like many .NET platform developers who originally migrated
from other tools and languages such as classic Visual Basic, much of
what I've learned has been self-taught. And the interesting thing about
being self-taught, of course, is that often our learning process can
be very "selective".
That is to say, we learn what we want to learn, not necessarily what
we should learn, and very often we "learn it to ourselves" in the wrong
order. Sound familiar? I thought it would!
One of the last things I learned was the delegate and event
infrastructure that's built into the .NET languages. I avoided getting
them under my belt for mostly the above reasons. However, now that I've
journeyed through the Valley of Delegate Darkness and emerged at the
other side unscathed, I have seen that "it is good". For reasons
of clarity, I'm focusing here on C# specifically (also because it's my
favorite .NET Platform language, by a long shot).
So, what's a delegate? You'll find a number of definitions,
but they all seem to converge around "it's a type-safe, object oriented
way to point to a method". In .NET, you can make a call on any
method, either synchronously or asynchronously, by simply
defining a delegate for the method and invoking the delegate.
First, let's take a look at a delegate "under the hood".
Once you understand what the Common Language Runtime is doing with your
delegates, you will have a lot more insight into what they can do. I've
created a simple class, "DaddysCar" that looks like so:
using System;
namespace Daddy
{
public class DaddysCar
{
public DaddysCar()
{
}
private decimal _damageAmount;
public decimal DamageAmount
{
get{ return _damageAmount;}
set{_damageAmount=value;}
}
private string _whichCar;
public string WhichCar
{
get{return _whichCar;}
set{_whichCar=value;}
}
public delegate string NotifyDaddy(DaddysCar car, decimal DamageAmount);
}
} |
Note the delegate "NotifyDaddy" defined at the bottom of
the class above (I hope you are never the recipient of this method call).
Now when we run this through our trusty ILDASM and look inside, see what
the Compiler has done for us:
First, we can see that NotifyDaddy, our delegate, is
actually a class, and that the compiler has created it as
a nested class, since we defined it inside our DaddyCar class
(we could have defined it in a separate class too). Note also
that the compiler has generously supplied us with both synchronous
"Invoke" and asynchronous "BeginInvoke / EndInvoke" methods!
Note also that the compiler has derived this class from System.MulticastDelegate.
Some of the inherited members we get from this trick are Method (name
of the method it points to), Target (name of the
class if the method it points to is a member of a class), Combine (a
static method to allow our delegate to point to more than one
method), and GetInvocationList, which returns an
array of each of the Delegate types in the list of methods pointed
to. We also get, of course, Clone, the += and -= operator overloads,
DynamicInvoke, MethodInfo, and other methods.
So here we've defined a Delegate called NotifyDaddy,
and we have indicated that each instance of it can hold details of
a method that takes a DaddysCar instance and a decimal damageAmount,
and will return a string. I've now added a new method to my DaddysCar
class that can act as a sample target of a delegate:
public string ComputePunishment( DaddysCar car, decimal
damageAmount)
{
if((int)damageAmount >1000.00 && car.WhichCar =="TBird")
{
return "Confiscate Car Keys Immediately; Call Insurance Company!";
}
else
{
return "Look Mad and Issue Stern Warning";
}
Invoking Delegates
We invoke a delegate by supplying the name of a delegate
instance, followed by parentheses containing a list of acceptable parameters.
This has the same effect as calling the method pointed to by the delegate.
So now let's put together a "Tester" class to flesh this all out:
using System;
using Daddy;
namespace DaddyTester
{
class TestMeOutDelegate
{
delegate string NotifyDaddy(DaddysCar car, decimal damageAmount);
[STAThread]
static void Main(string[] args)
{
Daddy.DaddysCar d=new DaddysCar();
d.WhichCar="TBird";
NotifyDaddy BadNews = new NotifyDaddy(d.ComputePunishment);
Console.WriteLine("Method: " + BadNews.Method);
Console.WriteLine("Target: " + BadNews.Target);
Console.WriteLine(BadNews(d,1500));
Console.ReadLine();
}
}
} |
And here is the output from our delegate call:
The above comprises the very basic, "get to First
Base"
understanding of delegates. Hopefully it will encourage you to move forward
on your own and study more on the use of delegates. Delegates can be used
in ASP.NET, with SMTP, Web Services, even in FTP and on applications
written for hand held devices such as the PocketPC.
Finally, delegates can be used to call methods asynchronously.
For a complete example of how to implement this technique, please visit
my previous articles "How
to send emails asynchronously".
Now that we have a "basics" example of what a
delegate is and how they are used, we can move on to be a "Delegate
to the Event!", which covers events, in my next installment here.
Download the Delegate Example solution
|