During my discussion of SQL Server Compact Edition, I mentioned Delegates. I thought I’d take a moment to cover what a delegate is, and how you can effectively use them in your application.
Let’s say you send an employee to the mall, and tell him “OK, when you get to the mall I will tell you which store to go in, because right now I haven’t decided yet.” A delegate is somewhat like that. You can tell your application that you are going to call a method with a certain signature, but you will tell it the name of the method at run time instead of compile time. (The signature, in case you haven’t heard the term, is the name and return type of the method plus the list of the data types of the parameters you pass.)
Let’s create a simple example. Create a new windows form app. Put on a label, a text box, and two buttons. When done, it should look something like this:
Now add a class, and name it “TheDoSomethingClass”. Once it’s created, we’ll need to put a declaration at the class level:
public delegate void DoDelegate(string msg);
We are creating a new variable type called DoDelegate. It’s descended from a Delegate, and has one parameter. It has to be pubic, so we can later create a variable of the DoDelegate type.
Next, we’ll add one method to the class, and pass in our delegate type.
public void DoSomething(DoDelegate doit)
{
for(int i=0; i < 3000;i++)
if (doit != null)
{
doit(“Count=” + i.ToString());
}
}
This method has one parameter, “doit”. Notice that doit is of type DoDelegate. I created a little loop, just so we can see some action. Next, I check to see if the doit variable is null. This is very important, traditionally a delegate is never required but optional for use in your class. Thus you should always check to see if it’s null before attempting to use it. In the next line we actually call the doit method, and pass in it’s parameter, in this case a single string.
Now let’s look at how to use our delegate. Let’s return to our form, and add a new method. This method will be called ShowInLabel, accept a single string which it will display in the label control. I also added a DoEvents, just to get the label to update immediately.
private void ShowInLabel(string theMessage)
{
label1.Text = theMessage;
Application.DoEvents();
}
Now for the final step which ties everything together. In the click event for the button next to the label, we need to add two lines of code. The first line will instantiate a new object from our TheDoSomethingClass class. The second line will call the DoSomething method.
private void btnLabel_Click(object sender, EventArgs e)
{
TheDoSomethingClass dsc = new TheDoSomethingClass();
dsc.DoSomething(
new TheDoSomethingClass.DoDelegate(ShowInLabel));
}
Notice something important: in the second line we create a new variable of type DoDelegate. Perhaps if I do it in 3 lines it will make it slightly clearer.
TheDoSomethingClass dsc = new TheDoSomethingClass();
TheDoSomethingClass.DoDelegate myNewDoDelegate
= new TheDoSomethingClass.DoDelegate(ShowInLabel);
dsc.DoSomething(myNewDoDelegate);
As part of the constructor, we pass it the name of a method that has the same signature as the delegate. In this case, ShowInLabel has the same signature (one parameter, a string) as the delegate was declared with. The Delegate’s signature and the signature of the method you want to assign to it must match or you’ll get an error.
Now let’s flex our power a little. Create another method with a different name, but the same signature. This one we’ll call ShowInTextBox, and like the other we have to have one string as a parameter. In this method we will update the text box instead of the label with the passed in message.
private void ShowInTextBox(string theMessage)
{
textBox1.Text = theMessage;
Application.DoEvents();
}
Now in the click event for the button associated with the text box, we’ll repeat the code from the other button with one exception. In the constructor, we’ll pass in the name of the new method.
private void btnTextBox_Click(object sender, EventArgs e)
{
TheDoSomethingClass dsc = new TheDoSomethingClass();
dsc.DoSomething(
new TheDoSomethingClass.DoDelegate(ShowInTextBox));
}
DoDelegate method what so ever, yet it was able to call a completely different method.
You can also store the delegate, in case you want to use it for several methods in your class, or manipulate it a bit easier. Put this code in your class (note I squished down the get/set to save a bit of space, I don’t normally code that ugly.) I added a private variable to hold our delegate, a property get / setter, and a new method that will take advantage of it.
private DoDelegate _TheDelegate;
public DoDelegate TheDelegate
{
get
{ return _TheDelegate; }
set
{ _TheDelegate = value; }
}
public void DoSomethingElse()
{
for (int i = 0; i < 3000; i++)
if (_TheDelegate != null)
{
_TheDelegate(“Count=” + i.ToString());
}
}
Now to call it, all we have to do is go back to our form and add this code to a button click event:
TheDoSomethingClass dsc = new TheDoSomethingClass();
dsc.TheDelegate
= new TheDoSomethingClass.DoDelegate(ShowInLabel);
dsc.DoSomethingElse();
dsc.TheDelegate
= new TheDoSomethingClass.DoDelegate(ShowInTextBox);
dsc.DoSomethingElse();
Note here I changed the delegate between calls, I could have also coded more methods that used the same call. Also note if I had tried calling DoSomethingElse before assigning a delegate, the program would have run just fine I just wouldn’t have been shown any messages, thanks to the if ( _TheDelegate != null) statement.
Now that I’ve shown you how a delegate works, let’s take a moment to discuss some times when you might want to use it. The first example I can think of is to support an add in architecture. You can dynamically load DLLs at run time, and when you do you can query it to see if it supports a certain delegate type, perhaps one for communicating a message like our example. If so, you can assign that delegate to the message handler for your particular app. Not only does this mean you can use multiple add-ins with the same app, it also means you could support multiple apps with one add-in.
Here’s another example from my personal experiences. I have a winforms app that can connect to multiple database. (Each of our sites has it’s own database.) Most users only need to connect to one, so I save the database they were last connected to in the settings file. When the user reloads the app, I reconnect to the same database.
When my app loads, there are a lot of lists of values I retrieve to populate drop down combos. During load, however the only form visible is my splash screen. Using delegates in my load routine I have all progress messages from my data layer displayed on the splash screen.
During the course of using my program, the user can choose to hook to a different site, and hence a different database, which means I have to reload all those lists of values again. This time though, I don’t have the splash screen up. True, I could show it again, but it would look really goofy.
Instead, in my load routine I instead pass a delegate to the data layer that instead will display progress messages on the status bar control at the bottom of the form.
The beauty of this is that the data layer has no clue where or if it is displaying messages, nor should it have to care. I can also reuse this data layer DLL in other apps down the road, should the need arise, and take advantage of the status messages it provides.
In my example I have kept it simple and used a single parameter for my delegate. Know that you are not restricted; you can use multiple parameters if you wish. The important thing to remember is your signatures must match. The return type and number of parameters for your delegate (DoDelegate) must match the signature of the methods you assign to it (ShowInLabel, ShowInTextBox).
When designing your classes, especially those destined for DLL libraries that could get multiple use, consider adding some delegates as a way to inform your consumer of the progress of your methods.
There you go, a short step by step for delegates in C#. If you think of some new uses for delegates, drop a comment and let us know.
You should do a search-and-replace, changing all occurrences of “pubic” to “public”, which I believe is the intended word.
Kurt
No kurt, the intended word really was pubic, as the author likes pubic hair soo much that he CODES pubic hair too. dum ass kurt dont u have any sence?
Annony – why the malicious response? Why do you call Kurt a dum (sic) ass? That’s the problem with this cyberworld – gutless geek bastards like you can be as obnoxious as you want with no fear of having your ass kicked. You’re a smart ass punk. Oh, and by the way genius – learn how to spell.
Kurt, Ignore such a** h****… This is a great article and keep writing…