Click here to Skip to main content
Click here to Skip to main content

Events and Delegates Simplified

By , 28 Nov 2012
 

Contents

Introduction

When I was trying to learn events and delegates, I read a lot of articles to completely understand what they are and how to use them, and now I want to present them all here, everything I learned, most of the things you need to learn.

What are delegates?

Delegate and Event concepts are completely tied together. Delegates are just function pointers, That is, they hold references to functions.

A Delegate is a class. When you create an instance of it, you pass in the function name (as a parameter for the delegate's constructor) to which this delegate will refer.

Every delegate has a signature. For example:

Delegate int SomeDelegate(string s, bool b);

is a delegate declaration. When I say this delegate has a signature, I mean that it returns an int type and takes two parameters of type string and bool.

I said, when you instantiate delegates, you pass in the function name to which this delegate will refer as its constructor parameter. The important thing to notice is that only functions that have the same signature as the delegate, can be passed as a parameter.

Consider the following function:

private int SomeFunction(string str, bool bln){...}

You can pass this function to SomeDelegate's constructor, because of their similar signatures.

SomeDelegate sd = new SomeDelegate(SomeFunction);

Now, sd refers to SomeFunction, in other words, SomeFunction is registered to sd. If you call sd, SomeFunction will be invoked. Keep in mind what I mean by registered functions. Later, we will refer to registered functions.

sd("somestring", true);

Now that you know how to use delegates, let's understand events...

Understanding Events

  • A Button is a class, when you click on it, the click event fires.
  • A Timer is a class, every millisecond a tick event fires.

Want to understand what's happening? Let's learn through an example:

This is the scenario: we have a class named Counter. This class has a method named CountTo(int countTo, int reachableNum) which starts counting from 0 to countTo, and raises an event named NumberReached whenever it reaches the reachableNum.

Our class has an event: NumberReached. Events are variables of type delegates. I mean, if you want to declare an event, you just declare a variable of type some delegate and put event keyword before your declaration, like this:

public event NumberReachedEventHandler NumberReached;

In the above declaration, NumberReachedEventHandler is just a delegate. Maybe it was better to say: NumberReachedDelegate, but notice that Microsoft doesn't say MouseDelegate or PaintDelegate, instead it offers: MouseEventHandler and PaintEventHandler. It's a convention to say NumberReachedEventHandler instead of NumberReachedDelegate. OK? Good!

You see, before we declare our event, we need to define our delegate (our event handler). It could be something like this:

public delegate void NumberReachedEventHandler(object sender, 
    NumberReachedEventArgs e);

As you see, our delegate's name is: NumberReachedEventHandler, and its signature contains a void return value and two parameters of type object and NumberReachedEventArgs. If you somewhere want to instantiate this delegate, the function passed in as constructor parameter should have the same signature as this delegate.

Have you ever used PaintEventArgs or MouseEventArgs in your code to determine the position of the mouse, where it was moving, or the Graphics property of the object which raised the Paint event? Actually, we provide our data for the user in a class which is derived from EventArgs class. For example, in our example, we want to provide the number which was reached. And here is the class definition:

public class NumberReachedEventArgs : EventArgs
{
    private int _reached;
    public NumberReachedEventArgs(int num)
    {
        this._reached = num;
    }
    public int ReachedNumber
    {
        get
        {
            return _reached;
        }
    }
}

If it wouldn't be necessary to provide the user with any information, we just use the EventArgs class.

Now, every thing is prepared to take a look inside our Counter class:

namespace Events
{
    public delegate void NumberReachedEventHandler(object sender, 
        NumberReachedEventArgs e);

    /// <summary>
    /// Summary description for Counter.
    /// </summary>
    public class Counter
    {
        public event NumberReachedEventHandler NumberReached;
        
        public Counter()
        {
            //
            // TODO: Add constructor logic here
            //
        }
        public void CountTo(int countTo, int reachableNum)
        {
            if(countTo < reachableNum)
                throw new ArgumentException(
                    "reachableNum should be less than countTo");
            for(int ctr=0;ctr<=countTo;ctr++)
            {
                if(ctr == reachableNum)
                {
                    NumberReachedEventArgs e = new NumberReachedEventArgs(
                        reachableNum);
                    OnNumberReached(e);
                    return;//don't count any more
                }
            }
        }

        protected virtual void OnNumberReached(NumberReachedEventArgs e)
        {
            if(NumberReached != null)
            {
                NumberReached(this, e);//Raise the event
            }
        }
    }

In the above code, we raise an event if we reach the desired number. There are a lot of things to consider here:

  • Raising an event is accomplished through calling our event (an instance of some delegate named NumberReachedEventHandler):
    NumberReached(this, e);

    This way, all registered functions will be invoked.

  • We prepare data for registered functions through this:
    NumberReachedEventArgs e = new NumberReachedEventArgs(reachableNum);
  • One question: why do we indirectly call NumberReached(this, e) through OnNumberReached(NumberReachedEventArgs e) method? Why didn't we use the following code?
    if(ctr == reachableNum)
    {
        NumberReachedEventArgs e = new NumberReachedEventArgs(reachableNum);
        //OnNumberReached(e);
        if(NumberReached != null)
        {
            NumberReached(this, e);//Raise the event
        }
        return;//don't count any more
    }

    Good question! If you want to know why we called indirectly, take another look at OnNumberReached's signature:

    protected virtual void OnNumberReached(NumberReachedEventArgs e)
    • You see, this method is protected, it means it's available for classes which are derived from this class (inheriting classes).
    • This method is also virtual, this means that it could be overridden in a derived class.

    And this is very useful. Suppose you are designing a class which inherits from Counter class. By overriding OnNumberReached method, you can do some additional work in your class before the event gets raised. An example:

    protected override void OnNumberReached(NumberReachedEventArgs e)
    {
        //Do additional work
        base.OnNumberReached(e);
    }

    Note that if you don't call base.OnNumberReached(e), the event will never be raised! This might be useful when you are inheriting from some class and want to eliminate some of its events! An interesting trick, huh?

    As a real world example, you can just create a new ASP.NET Web Application and take a look inside the code behind generated. As you see, your page inherits from System.Web.UI.Page class. This class has a virtual and protected method name OnInit. You see that InitializeComponent() method is called inside the overridden method as an extra work, and then OnInit(e) is called in the base class:

    #region Web Form Designer generated code
    protected override void OnInit(EventArgs e)
    {
        //CODEGEN: This call is required by the ASP.NET Web Form Designer.
        InitializeComponent();
        base.OnInit(e);
    }
    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    private void InitializeComponent()
    {
          this.Load += new System.EventHandler(this.Page_Load);
    }
    #endregion
  • Notice that NumberReachedEventHandler delegate is defined outside our class, inside the namespace, visible to all classes.

OK. Now, it's time to practically use our Counter class:

In our sample application, we have two textboxes named txtCountTo and txtReachable as follows:

sample application

And here is the event handler for btnRun click event:

private void cmdRun_Click(object sender, System.EventArgs e)
{
    if(txtCountTo.Text == "" || txtReachable.Text=="")
        return;
    oCounter = new Counter();
    oCounter.NumberReached += new NumberReachedEventHandler(
        oCounter_NumberReached);
    oCounter.CountTo(Convert.ToInt32(txtCountTo.Text), 
        Convert.ToInt32(txtReachable.Text));
}

private void oCounter_NumberReached(object sender, NumberReachedEventArgs e)
{
    MessageBox.Show("Reached: " + e.ReachedNumber.ToString());
}

This is the syntax for initiating an event handler for some event:

oCounter.NumberReached += new NumberReachedEventHandler(
    oCounter_NumberReached);

Now, you understand what you are doing here! You are just instantiating an object of type NumberReachedEventHandler delegate (as you do for any other object). Care about the oCounter_NumberReached method signature similarity as I mentioned before.

And notice that we used += instead of simply =.

It's because delegates are special objects that can hold references to more than one object (here, reference to more than one function). For example, if you had another function named oCounter_NumberReached2 with the same signature as oCounter_NumberReached, both of the functions could be referenced this way:

oCounter.NumberReached += new NumberReachedEventHandler(
    oCounter_NumberReached);
oCounter.NumberReached += new NumberReachedEventHandler(
    oCounter_NumberReached2);

Now, after raising an event, both functions will be invoked one after another.

If somewhere in your code, based on conditions, you decided oCounter_NumberReached2 not be invoked anymore on NumberReached event occurrences, you could simply do this:

oCounter.NumberReached -= new NumberReachedEventHandler(
    oCounter_NumberReached2);

event Keyword

A lot of folks keep asking this question: "what happens if we don't use event keyword?"

In essence, declaring the event keyword prevents any of the delegate’s users from setting it to null. Why is this important? Imagine that as a client I would add to the delegates invocation list a callback to one of my class’ functions. So would other clients. All is well and good. Now imagine that someone, instead of using the “+=”, is simply setting the delegate to a new callback by using “=”. This basically just throws the old delegate and its invocation list down the drain and creates a whole new delegate with a single item in its invocation list. All the other clients will not receive their callbacks when the time comes. It is this kind of situation that having the event keyword is aiming to solve. If I keep the event keyword in the Counter class and try to compile the following code in my application, it will cause a compilation error. By removing the event keyword, however, this error will not happen.

In conclusion: an event declaration adds a layer of protection on the delegate instance. This protection prevents clients of the delegate from resetting the delegate and its invocation list, and only allows adding or removing targets from the invocation list [reference].

Finally

Don't forget to define these lines in your application's main constructor, instead of cmdRun_Click event handler. I defined them in my button click event handler just for the sake of simplicity! ;-)

public Form1()
{
    //
    // Required for Windows Form Designer support
    //
    InitializeComponent();

    //
    // TODO: Add any constructor code after InitializeComponent call
    //
    oCounter = new Counter();
    oCounter.NumberReached += new NumberReachedEventHandler(
        oCounter_NumberReached);
    oCounter.NumberReached += new NumberReachedEventHandler(
        oCounter_NumberReached2);

The source code provided by this article is as above.

If your vote is less than 5, let me know the reason ;-). I hope you are satisfied after reading this article!

History

  • Thursday, August 21, 2003
    • The article has a better decorated coding.
    • Some image of demo application added.
  • Wednesday, August 11, 2004
    • Added an example of inheritance.
  • Saturday, March 12, 2005
    • More about the usage of event keyword.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Meysam Mahfouzi
Software Developer (Senior)
Iran (Islamic Republic Of) Iran (Islamic Republic Of)
Member
My main focus is currently on C++, but I have enjoyed developing with C# too Smile | :)

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5memberMember 949867210 May '13 - 4:39 
Well explained the concept..Good one
GeneralMy vote of 5memberYang Li23 Apr '13 - 5:37 
It might be the best post on this topic I have seen
GeneralMy vote of 5groupthangnvc14 Apr '13 - 20:39 
very clear
QuestionThanksmemberRanjith Gonugunta9 Apr '13 - 16:00 
Good Article
QuestionGrt explanation, helps a newbe like memembersaumen_halder1 Apr '13 - 6:28 
Smile | :)
GeneralMy vote of 4membernummer3129 Mar '13 - 9:03 
I vote 4 because as a noob I really didn't understand the significance of delegate and its relation with event here.
GeneralMy vote of 5groupsinhasourabh15 Mar '13 - 10:18 
I was trying to figure out the different between Events & Delegates, but i was getting all the syntax level difference. This article acutally explains what is the use of delegates with respect to events. Great job done. Simply Awesome
GeneralMy vote of 5memberimoralesm13 Mar '13 - 17:38 
Really clear and neat explanation!
GeneralMy vote of 5memberDr Bob8 Dec '12 - 7:15 
Nice and simple work!
GeneralMy vote of 5memberSalmanSamian7 Dec '12 - 7:28 
Great but i need to learn more about Events in C#...
thanks
GeneralMy vote of 5memberJanak Desai7 Dec '12 - 5:51 
Clear and concise.
AnswerMy vote of 5memberluschmi15 Dec '12 - 2:19 
A very good short article explains what Delegate and Events understandable.
GeneralMy vote of 5memberDegryse Kris3 Dec '12 - 22:19 
This is an excellent article: to the point and clear explanation
GeneralSimple, Excellent!memberBigWorld3 Dec '12 - 21:42 
Great introduction!
GeneralMy vote of 5memberOmar20033 Dec '12 - 18:08 
Thank You
GeneralMy vote of 5memberSakshi Smriti3 Dec '12 - 17:02 
Very well knit article on delegates and events and moreover explaining why we need them. Read many articles in this topic, yours is crisp, neat, precise and explains well. Good for beginners who want to understand this concept
Question5+memberSaumitra Kumar Paul3 Dec '12 - 16:46 
no reason to vote less than 5. it deserves 5+
GeneralMy vote of 5memberdeatharthas3 Dec '12 - 14:43 
Very nice article, thanks.
But could you please explain a little about the difference between 'delegate' Key word and 'Delegate' class? Since they are not exactly the same, thanks in advance.
GeneralMy vote of 5memberBrian_Lowe3 Dec '12 - 12:02 
Clear and to the point. Well done!
GeneralMy vote of 4membersavur1 Dec '12 - 10:48 
This article is very good, but i vote for 4 bucause of i also worry how can i bind two or more delagete to one event,
I mean how implemented this code: oCounter.NumberReached = new NumberReachedEventHandler(oCounter_NumberReached);
oCounter.NumberReached = new NumberReachedEventHandler(oCounter_NumberReached2);
GeneralRe: My vote of 4memberMeysam Mahfouzi1 Dec '12 - 17:10 
I have already said that in the article. You can do it using the += operator.
oCounter.NumberReached += new NumberReachedEventHandler(
    oCounter_NumberReached);
oCounter.NumberReached += new NumberReachedEventHandler(
    oCounter_NumberReached2);

GeneralMy vote of 5memberbinog29 Nov '12 - 15:54 
Simple yet precise..
Thank you..
GeneralMy vote of 5memberIFFI29 Nov '12 - 4:13 
Nicely explained. Got my 5.
GeneralMy vote of 5memberAbang Jam1 Oct '12 - 15:36 
good and precise explanation
QuestionGood articlememberamit_1410 Sep '12 - 0:50 
Good article
GeneralMy vote of 3memberzahidbashir19 Jul '12 - 11:28 
Are you sure that the NumberReached event is an instance of NumberReachedEventHandler delegate? Since I read in book C# in Depth where the author clearly states that "events aren't delegate instances."
GeneralRe: My vote of 3memberMeysam Mahfouzi25 Jul '12 - 21:38 
I have seen in many MSDN documents that events have been referred to as delegate instances. For example take a look at this article[^]:
 
The following steps must be taken in order to create and use C# events:
 
1- Create or identify a delegate. If you are [. . .]
2- Create a class that contains:
a. An event created from the delegate.
b. (optional) A method that verifies that an instance of the delegate declared with the event keyword exists. Otherwise, this logic must be placed in the code that fires the event.
 
As you can see the official documents are referring to events as "instance of the delegate".
GeneralRe: My vote of 3memberrchenna29 Nov '12 - 11:03 
I think its the reference variable to the instance of the delegate, the key word event helps the compiler generate the code in IL to Add and Remove instances of the delegate.
QuestionGreat articlememberPuneet Khurana16 Jul '12 - 20:58 
Simple yet effective. Thanks Smile | :)
GeneralMy vote of 5memberPuneet Khurana16 Jul '12 - 20:56 
Great article simple yet effective. Thanks
GeneralMy vote of 5memberDr. noob19 May '12 - 2:56 
Excellent explanation, thank you!
QuestionGreat!groupShandesh Poudel10 May '12 - 8:44 
Great Article...on Delegates..Thumbs Up | :thumbsup: ...Could you please post an article on Events and Asynchronous Call ?.
GeneralMy vote of 5memberAchintya Jha6 May '12 - 17:07 
Best short explanation...
GeneralMy vote of 5memberArkham0010 Feb '12 - 6:20 
Simple, clear, complete.
QuestionMy 5 PointsmemberAtif Aslam9 Feb '12 - 0:50 
Very Nice Article
GeneralMy vote of 5memberVinod Satapara29 Dec '11 - 22:48 
Nice Article
GeneralMy vote of 5memberloshuyan@gmail.com15 Dec '11 - 21:47 
simple,clear,and logical
GeneralMy vote of 5memberskrjabin373 Jul '11 - 4:10 
this article was very usefull for me
QuestionDelegates in .Net 4memberAnubalaji3 Jun '11 - 5:14 
A very good article on Delegates and Events.. It gives a great idea about those objects.
 
I have a question in your code of Delegates.
 
I tried your code in .net 4 the Method call
 
private int SomeFunction(string str, bool bln){...}
 
that has same signature and parameters of the delegate. I had to change the method to a static method or need to create an Instance of the class to create an instance of the delegate.. only then it worked. The following is the error that I got when the method call is not a static method.
 
"A field initializer cannot reference the non-static field, method, or property 'DelegatesExample.TestDelegateClass.SomeFunction(string, bool)'"
 
The following is my code where I got the error :
 
//Declare a delegate
delegate int SomeDelegate(string s, bool b);
 
public class TestDelegateClass
{
//Method call with same signature and parameter of the delegate
 
private int SomeFunction(string str, bool bln)
{
return 1;
}
 

//Instantiate the Delegate
SomeDelegate sd = new SomeDelegate(SomeFunction);
}
 
I got the error mentioned earlier for the above code. I am not sure whether this is a new feature in .Net 4. Can anyone explain?
 
Thanks
AnswerRe: Delegates in .Net 4memberMeysam Mahfouzi3 Jun '11 - 7:15 
Well, turns out referencing a class member function from inside the class itself is not feasible unless the function is static. And I don't think it's ever needed to do such thing as you are doing in your code. Smile | :)
QuestionRe: Delegates in .Net 4memberAnubalaji6 Jun '11 - 2:26 
Thanks for your response. In my code I am calling the delegates from another class.. I mentioned that as an example becoz in your example it was mentioned in the same.. Sorry if i where wrong..In your code you haven't mentioned the static modifier for the Delegate function
 
private int SomeFunction(string str, bool bln){...} - Is this right? If so how should I use the delegate function?
 
Thanks in advance
GeneralSimple and CrispmemberWCFguru20 Apr '11 - 21:03 
One of the better articles on Delegates and Events.Lot of books could learn a lesson with regards to the easy language of the article,example and overall value of delivery.
Keep it up.Gr8 work Dude!!!!
GeneralRe: Simple and CrispmemberMeysam Mahfouzi20 Apr '11 - 23:02 
Thank you Smile | :)
GeneralGreat Job Dude ! Keep it Upmemberpakauman17 Apr '11 - 5:12 
This is evergreen article well done...Cool | :cool: Rose | [Rose] Smile | :)
GeneralRe: Great Job Dude ! Keep it UpmemberMeysam Mahfouzi17 Apr '11 - 6:49 
Thank you Smile | :)
Generalvery well explainedmemberron nec16 Apr '11 - 21:41 
thank you so much
GeneralMy vote of 5memberngocson2vn15 Feb '11 - 22:45 
You have given a insight to me about Delegate and Event
 
Thank you very much!
Gmail: ngocson2vn@gmail.com
GeneralMy vote of 5memberFrank884814 Feb '11 - 7:45 
The best explanation on the wide web.
GeneralNice Articlememberarpitgold5 Feb '11 - 5:01 
Nice Article, Very well explainedThumbs Up | :thumbsup:
GeneralMy vote of 5memberHitechdinesh19 Jan '11 - 23:28 
very clearly explained about delegates and events, and gives a very clear idea how and why and where to use it.
 
Thanks very much mate for the wonderful article
Dinesh

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130516.1 | Last Updated 29 Nov 2012
Article Copyright 2003 by Meysam Mahfouzi
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid