Event

.C# Event Following .NET Standards


C# Event Following .NET Standards - Program Output

.Event

"A C# program which illustrates how to create events which conform to the .NET framework standards."

For compatibility with the .NET Framework, events should be published based on the EventHandler delegate. A popular, and recommended option, is to use the generic version called EventHandler<TEventArgs>. The advantage of using EventHandler<TEventArgs> is that you do not need to code your own custom delegate if your event generates event data. You simply provide the type of the event data object as the generic parameter.

If you are passing data with your event, you need to declare an class for passing the data. The class should be declared at a scope that is visible to both the Publisher and Subscribers. The class should be derived from System.EventArgs . If you are absolutely sure the event will never need to carry any data to the event handling method, you can use the EventArgs type directly.

If you need to create delegate for the event (i.e. you are NOT using EventHandler), then it should take exactly two parameters with a void return type:

  1. The first parameter is the "object source" parameter indicating the source of the event, is called "sender".
  2. The second parameter is the class used for passing data to the event (#2 above), and is called "e".

Example : public delegate void CustomEventHandler(object sender, CustomEventArgs e);

Use a protected virtual method to raise each event. (Only applicable to nonstatic events on unsealed classes, not to structs, sealed classes, or static events). The method provides a way for a derived class to handle the event using an override. Overriding is a more flexible, faster, and more natural way to handle base class events in derived classes. The name of the method should start with "On" and be followed with the name of the event. Use one parameter named e, which should be typed as the event argument class.

The following C# features are used in the sample code:

  1. Event - The event keyword is used to declare an event in a publisher class.
  2. EventArgs Class - Represents the base class for classes that contain event data, and provides a value to use for events that do not include event data.
  3. EventHandler<T> delegate - Represents a method that handles general events.

    C# Event Following .NET Standards

    using System;
    using System.Collections.Generic;

    namespace dotNetEvent
    {
        // 1. Create class for event arguments at scope
        //    visible to both publisher and subscriber
       /*******************************
        *   EventArgs Derived Class   *
        *******************************/
        public class MyEventArgs : EventArgs
        {
            public MyEventArgs(string s)
            {
                arg1 = s;
            }
            private string arg1;

            public string Arg1
            {
                get { return arg1; }
                set { arg1 = value; }
            }
        }

       /*******************************
        *      Publisher Class        *
        *******************************/
        class Publisher
        {
            // 2. Create the event using EventHandler<T>,
            //    This allows you to skip declaring a delegate.
            public event EventHandler<MyEventArgs> RaiseMyEvent;

            // 3. Create method to do work and call will
            //    call the method that raises the event.
            public void PubProcessing()
            {
                // Note: Work can be performed prior to
                //       or after the event is raised.
                OnRaiseMyEvent(new MyEventArgs("Event arg1"));
            }

            // 4. Declare protected virtual method to allow derived
            // classes to override the event invocation behavior
            protected virtual void OnRaiseMyEvent(MyEventArgs 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<MyEventArgs> myHandler = RaiseMyEvent;

                // Event is null if there are no subscribers
                if (myHandler != null)
                {
                    // Format the string to send inside the MyEventArgs parameter
                    e.Arg1 += String.Format(" at {0}", DateTime.Now.ToString());

                    // Raise the event.
                    myHandler(this, e);
                }
            }
        }

       /*******************************
        *   Subscribers Class         *
        *******************************/
        class Subscriber
        {
            private string id;
            public Subscriber(string ID, Publisher pub)
            {
                id = ID;

                // 1. Subscribe to the event
                pub.RaiseMyEvent += HandleMyEvent;
            }

            // 2. Define Action to take (event handler).
            void HandleMyEvent(object sender, MyEventArgs e)
            {
                Console.WriteLine(id + " argument 1: {0}", e.Arg1);
            }
        }

        class Program
        {
            static void Header()
            {
                Console.WriteLine("************************************************************");
                Console.WriteLine("***  Event: One Publisher, Two Subscribers, One Argument ***");
                Console.WriteLine("***                                                      ***");
                Console.WriteLine("***      1. Conforms to .NET framework guidelines.       ***");
                Console.WriteLine("***      2. Uses MyEventArgs to pass arguments to event. ***");
                Console.WriteLine("***      3. Uses EventHandler<T>.                        ***");
                Console.WriteLine("************************************************************\n");
            }
           
            static void Main(string[] args)
            {
                Header();
                Publisher publisher = new Publisher(); // Create Publisher Object
                Subscriber subscriber1 = new Subscriber("-> subscriber1", publisher); // Create First Subscriber Object
                Subscriber subscriber2 = new Subscriber("-> subscriber2", publisher); // Create Second Subscriber Object
                publisher.PubProcessing();             // Call the method that raises the event.
                Console.WriteLine();
            }
        }
    }