简体   繁体   中英

Why is a C# EventHandler Equal to an Event in MSN example?

The following is an example from MSN website. This is a good example, I just do not understand what this line:

EventHandler<CustomEventArgs> handler = RaiseCustomEvent;

is doing?

  1. Is not RaiseCustomEvent an event based on the definition at the top of the program?

  2. Why is an Event is equated to an EventHandler? These are two different types.

  3. Where is RaiseCustomEvent being initialized? If it is not initialized how can we copy it or why do we want to copy something uninitialized to something else?

  4. What is the handler variable there for? Is that an event or an event handler?

I'm very confused and am trying hard to get this event/event handler/delegate issue understood.

Here is the sample code from MSN

namespace DotNetEvents
{
using System;
using System.Collections.Generic;

// Define a class to hold custom event info 
public class CustomEventArgs : EventArgs
{
    public CustomEventArgs(string s)
    {
        message = s;
    }
    private string message;

    public string Message
    {
        get { return message; }
        set { message = value; }
    }
}

// Class that publishes an event 
class Publisher
{

    // Declare the event using EventHandler<T> 
    public event EventHandler<CustomEventArgs> RaiseCustomEvent;

    public void DoSomething()
    {
        // Write some code that does something useful here 
        // then raise the event. You can also raise an event 
        // before you execute a block of code.
        OnRaiseCustomEvent(new CustomEventArgs("Did something"));

    }

    // Wrap event invocations inside a protected virtual method 
    // to allow derived classes to override the event invocation behavior 
    protected virtual void OnRaiseCustomEvent(CustomEventArgs e)
    {
        // Make a temporary copy of the event to avoid possibility of 
        // a race condition if the last subscriber unsubscribes 
        // immediately after the null check and before the event is raised.
        EventHandler<CustomEventArgs> handler = RaiseCustomEvent;

        // Event will be null if there are no subscribers 
        if (handler != null)
        {
            // Format the string to send inside the CustomEventArgs parameter
            e.Message += String.Format(" at {0}", DateTime.Now.ToString());

            // Use the () operator to raise the event.
            handler(this, e);
        }
    }
}

//Class that subscribes to an event 
class Subscriber
{
    private string id;
    public Subscriber(string ID, Publisher pub)
    {
        id = ID;
        // Subscribe to the event using C# 2.0 syntax
        pub.RaiseCustomEvent += HandleCustomEvent;
    }

    // Define what actions to take when the event is raised. 
    void HandleCustomEvent(object sender, CustomEventArgs e)
    {
        Console.WriteLine(id + " received this message: {0}", e.Message);
    }
}

class Program
{
    static void Main(string[] args)
    {
        Publisher pub = new Publisher();
        Subscriber sub1 = new Subscriber("sub1", pub);
        Subscriber sub2 = new Subscriber("sub2", pub);

        // Call the method that raises the event.
        pub.DoSomething();

        // Keep the console window open
        Console.WriteLine("Press Enter to close this window.");
        Console.ReadLine();

    }
}
}

An event is to a delegate type what a property is to any other type.

If you have a property such as this:

public string Name {get;set;}

Obviously you can do something like this:

string name = Name;

The property has an underlying string value that is accessed/modified by the property.

Similarly, an event has a delegate under the hood, and that delegate is of the type defined in the event declaration. That it's an event simply defines how handlers of that event are added/removed from that underlying delegate.

From within the declaring type (that's a key point; you can't do this externally) you can access that underlying delegate in order to invoke it. That's the reason for doing the code that you see; they're accessing the underlying delegate so that they can verify that it has some handlers within it, and if so, it invokes them.

So, to answer the questions explicitly:

Is not RaiseCustomEvent an event based on the definition at the top of the program?

RaiseCustomEvent is the type of the underlying delegate that the event wraps.

Why is an Event is equated to an EventHandler? These are two different types.

It's not strictly equality. It's pulling out the underlying delegate from within the event.

Where is RaiseCustomEvent being initialized? If it is not initialized how can we copy it or why do we want to copy something uninitialized to something else?

In this case it's using the automatic add/remove implementations that the framework will provide, rather than manually defining them. The automatically defined add handler will initialize the underlying delegate if it is currently null. If the event declaration would define a custom add handler, it would need to handle that case.

What is the handler variable there for? Is that an event or an event handler?

It is a single delegate that represents the combination of all of the event handlers. Within it's definition will be an invocation list of all of the individual methods that make up that delegate. So it's not a single event handler, it's the collection of all of them. Since it's pulled out of the event it no longer strictly represents that event; it's a copy of what was in the event at some point in the past. You cannot change the event (ie add a new handler) using the delegate that you've pulled out of it.

I'll try the four questions you pose:

1) Is not RaiseCustomEvent an event based on the definition at the top of the program ?

The CustomEventArgs class holds some data (arguments) for the event we want to declare. It is used as type parameter in the type EventHandler<CustomEventArgs> . This last type is a delegate type, which means it represents one or more methods of the same signature and return type. (Zero methods will be a null reference as the value of the delegate.)

The type of the event RaiseCustomEvent is that delegate type, EventHandler<CustomEventArgs> .

2) Why an Event is equated to an EventHandler? These are two diffeent types

An event consists on a pair of special methods, accessors, one add accessor and one remove accessor. Both have one parameter of the same type which is called the type of the event. That type must be a delegate type. In this case that type is EventHandler<CustomEventArgs> .

In this example the event is a so-called field-like event. It generates a backing field of the same type, EventHandler<CustomEventArgs> , the delegate type. That field has the same name as the event itself!

When they do:

// Make a temporary copy of the event to avoid possibility of 
// a race condition if the last subscriber unsubscribes 
// immediately after the null check and before the event is raised.
EventHandler<CustomEventArgs> handler = RaiseCustomEvent;

they copy the current value of that backing field into the local variable handler . The comment describes why. They want to check for null before they invoke the delegate.

3) Where is RaiseCustomEvent have been initialized? If not initialized how can we copy or why do we want to copy something uninitialized to soemthig else.

It usually gets initialized when people use the add accessor of the event. This takes place through the special C# syntax += . This is called subscribing to the event. See the Subscriber class.

Actually pub.RaiseCustomEvent += HandleCustomEvent; translates to pub.add_RaiseCustomEvent(HandleCustomEvent); , so it is a call to the add accessor. The add accessor is generated by the compiler (in a field-like event), and it initializes the backing field.

4)I do not know what is handler variable? is that an event or an event handler ?

It is a delegate. It is not an event. It is a copy of the backing field of the field-like event at one moment in time.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM