Delegates and Events

Sunday, 29 August 2010 00:22 by Harpreet

Read this article in your language IT | EN | DE | ES

Definition:

Delegate is class type object which holds the reference to a method(s) of any class. It is also referred as a type safe function pointers.

Advantages:

  • Encapsulating the method's call from caller.
  • Effective use of Delegate improves the performance of application.
  • Used to call a method asynchronously.

Creating and using delegates involve four steps. They include:

1.      Delegate declaration

2.      Delegate methods definition

3.      Delegate instantiation

4.      Delegate invocation

A delegate declaration defines a class using the class System.Delegate as a base class. Delegate methods are any functions (defined in a class) whose signature matches the delegate signature exactly. The delegate instance holds the reference to delegate methods. The instance is used to invoke the methods indirectly.

Delegate Declaration:

<.syntax>

Modifier delegate return-type delegate-name (parameters);

Delegate may take any of the following modifiers:

·         new

·         public

·         protected

·         internal

·         private

The new modifier is only permitted on delegates declared within another type. It signifies that the delegate hides an inherited member by the same name.

Since delegate is a class type, it can be defined in any place where a class definition is permitted e.g.,

·         Inside a class

·         Outside all classes

·         As the top level object in a namespace

Delegate types are implicitly sealed and therefore it is not possible to derive any type from a delegate type. It is also not permissible to derive a non-delegate class type from System.Delegate.

Delegate Methods:
The methods whose references are encapsulated into a delegate instance are known as delegate methods or callable entities. Delegates are type-safe to the extent that they ensure the matching of signatures of the delegate methods. However, they do not care 

·         What type of object the method is being called against, and

·         Whether the method is a static or an instance method.

e.g., the delegate

delegate string GetAString()

can be made to refer to the method ToString() using an int object N as follow:

int N=100;

GetAString s1=new GetAString(N.ToString);

Delegate Instantiation:

<.Syntax>

new delegate-type (expression)

While instantiate the method, if no matching method exists, or more than one matching method exists, an error occurs. It is also not possible to create a delegate that would refer to a constructor, indexer, or user-defined operator.

Delegate Invocation:

<.syntax>

Delegate_object (parameter list)

For example:

Delegate1(x,y); //void delegate

Double a=delegate1(1.09,2.19); //double type value

QuickDelegateDemo.cs

using System;

namespace QuickDelegateDemo
{
    // 1. Delegate Declaration.
    public delegate double UnitConversion(double from);

    class Program
    {
        // 2. Define handler method.
        public static double FeetToInches(double feet)
        {
            return feet * 12;
        }

        static void Main(string[] args)
        {
            // 3. Create delegate instance.
            UnitConversion doConversion = new UnitConversion(FeetToInches);
 
            Console.WriteLine("Feet to Inches Converter");
            Console.WriteLine("------------------------\n");

            Console.Write("Please enter feet:  ");
            double feet = Double.Parse(Console.ReadLine());

            // 4. Use delegate just like a method.
            double inches = doConversion(feet);

            Console.WriteLine("\n{0} Feet = {1} Inches.\n", feet, inches);
            Console.ReadLine();
        }
    }
}

Dynamic Delegate Invocation
Sometimes you don't know what method you want to execute until runtime. One option is to use a delegate, which allows you to separate implementation of method logic from the controlling application logic, as shown in Listing 2.

QuickDelegateDemo.cs
using System;

// 1. Define delegate.
public delegate double UnitConversion(double from);

class DynamicDelegates
{
    // 2. Define handler methods.
    public double FeetToInches(double feet)
    {
        return feet * 12;
    }

    public double YardsToInches(double yards)
    {
        return yards * 36;
    }

    // Factory method for returning delegate
    public UnitConversion GetConversionMethod(string conversionType)
    {
        UnitConversion conversion;

        switch (conversionType)
        {
            case "1":
                conversion = new UnitConversion(FeetToInches);
                break;
            case "2":
                conversion = new UnitConversion(YardsToInches);
                break;
            default:
                throw new ArgumentException("Unrecognized conversion type: " + conversionType, conversionType);
        }

        return conversion;
    }

    // show menu and return units to convert and type of conversion
    public void GetUserInput(out double units, out string conversionType)
    {
        Console.WriteLine("Units Converter");
        Console.WriteLine("------------------------\n");
        Console.WriteLine("1 - Feet to Inches");
        Console.WriteLine("2 - Yards to Inches");
        Console.Write("\nPlease select conversion option (1 or 2):  ");
        conversionType = Console.ReadLine();
        Console.Write("\n\nPlease enter units:  ");

        units = Double.Parse(Console.ReadLine());
    }

    static void Main()
    {
        DynamicDelegates dels = new DynamicDelegates();

        double units;
        string conversionType;

        dels.GetUserInput(out units, out conversionType);

        // 3. get delegate instance via factory method.
        UnitConversion doConversion = dels.GetConversionMethod(conversionType);

        // 4. Use delegate just like a method.
        double inches = doConversion(units);

        Console.WriteLine("\n{0} Units = {1} Inches.\n", units, inches);
        Console.ReadLine();
    }
}

Above code allows the user to implement multiple conversions. In this case, it is only two conversions, but you could expand this example to many more methods. The way it is implemented, using a delegate, allows the algorithm in the Main method to remain untouched while new conversions are added to the application.

Multicast Delegate:
It is a Delegate which holds the reference of more than one method. Mutlicast delegate, also known as combinable delegates, must satisfy the following conditions: 

·         The return type of the delegate must be void.

·         None of the parameters of the delegate type can be declared as output parameters, using out keyword.

Simple Program using Multicast Delegate
delegate void Delegate_Multicast(int x, int y);
Class Class2
{
static void Method1(int x, int y) {
  Console.WriteLine("You r in Method 1");
}
static void Method2(int x, int y) {
  Console.WriteLine("You r in Method 2");
}
public static void Main()
{
  Delegate_Multicast func = new Delegate_Multicast(Method1);
  func += new Delegate_Multicast(Method2);
  func(1,2);             // Method1 and Method2 are called
  func -= new Delegate_Multicast(Method1);
  func(2,3);             // Only Method2 is called
}
}             
Explanation:
In the above example you can see that two methods are defined named method1 and method2 which takes two integer parameters and return type as void. In the main method the Delegate object is created using the following statement

Delegate_Multicast func = new Delegate_Multicast(Method1);

Then the Delegate is added using the += operator and removed using -= operator.

Delegates and Events
An event is a type member that enables a type to send notifications about things that happen in that type.

Events are better than delegates for implementing callbacks, because they provide more protection. In fact, the underlying implementation of an event is actually a delegate. Event restrictions include protection from accidental assignment and prevention of outside callers invoking the event.

With delegates, an assignment of a delegate (=), rather than an add (+=) will wipe out all delegates previously added to its invocation list, which is something you generally don't want happening to events that your code raises.

The other restriction, preventing outside callers from raising your event, gives you full control over the behavior of your type. It is necessary for a type to control the logic that raises its own events. To have something outside your type reaching in and firing your events could wreak havoc with your application. If you want code outside your type to be able to fire your event, you should provide a convenience method that will still give you more control over how the event is raised. Listing 4 shows how to use events and shows their restrictions as well as demonstrating the hazards you could face with delegates.

Listing 4: EventListener.cs
using System;
class EventListener
{
    static void Main()
    {
        EventPublisher publisher = new EventPublisher();
        EventListener  listener  = new EventListener();

        publisher.InterestingEvent += new EventHandler(listener.HandlerOne);
        publisher.InterestingEvent += new EventHandler(listener.HandlerTwo);

        publisher.InterestingDelegate += new EventHandler(listener.HandlerOne);

        // assignment accidentally wiped out delegate for listener.HandlerOne
        publisher.InterestingDelegate = new EventHandler(listener.HandlerTwo);

        // illegal
       
//publisher.InterestingEvent = null;

        // can't invoke event outside of its containing class
        
//publisher.InterestingEvent(listener, EventArgs.Empty);

        Console.WriteLine("\nInvoking Event:\n");
        publisher.FireEvent();

        Console.WriteLine("\nInvoking Delegate:\n");
        publisher.InterestingDelegate(listener, EventArgs.Empty);

        Console.ReadLine();
    }

    public void HandlerOne(object sender, EventArgs e)
    {
        Console.WriteLine("HandlerOne Called.");
    }

    public void HandlerTwo(object sender, EventArgs e)
    {
        Console.WriteLine("HandlerTwo Called.");
    }
}

class EventPublisher
{
    // declare event
    public event EventHandler InterestingEvent;

    // declare public delegate
    public EventHandler InterestingDelegate;

    public void FireEvent()
    {
        InterestingEvent(this, EventArgs.Empty);
    }
}

The EventPublisher class in Listing 4 has a declaration for both a delegate and an event. Since the event can be raised only from within its containing type, the FireEvent method is declared for the purpose of raising the event. (Normally, the event would be raised for some type of state change within the type, but this example is simplified to demonstrate the mechanics.)

The EventListener class adds delegates to both the InterestingEvent event and InterestingDelegate delegate of the publisher instance. Using the assignment operator on InterestingDelegate demonstrates the type of accidents that can happen with delegates. Assignment of a null value to InterestingEvent and a direct invocation of InterestingEvent are commented out in the listing. You can uncomment those lines separately, to verify the type of compiler error you'll see when trying each, proving the inherent safety of events over delegates in this situation. While InterestingDelegate is invoked directly, InterestingEvent is invoked indirectly, showing one way to cause an event invocation from outside a type. A similar scenario is possible in .NET Windows Forms where you can call PerformClick on Button and MenuItem types to simulate a mouse button click.

This article focused on delegates and explained why they are valuable to C# application development. Delegates allow you to refer to methods to dynamically invoke code and call multiple methods together. When executed, each member of a delegate's invocation list is executed synchronously, in the order they were added. A delegate's invocation list can be manipulated by adding and removing delegates.

One of the primary uses of delegates in .NET is to implement callback methods for events. Events are safer than delegates for callbacks because they protect against accidental assignment and provide protection against direct invocation from outside code. Delegates allow you to refer to methods, invoke multiple methods simultaneously, and are the underlying mechanism for implementing C# events.

 

 

Categories:   OOPS
Actions:   E-mail | Permalink | Comments (2) | Comment RSSRSS comment feed

Comments

September 21. 2010 11:10

Киевские проститутки

Thanks so much for posting this!  I have been pulling my hair out trying to resolve the issue... even rolling back to BE 1.6 which stopped the error but lost ability to use Recaptcha.  

Киевские проститутки

February 24. 2011 03:31

make money online

I do agree with all the ideas you have presented in your post. They are really convincing and will definitely work. Still, the posts are too short for beginners. Could you please extend them a bit from next time? Thanks for the post.

make money online

About me

Chat with Admin

Gmail: dotnetcracknews@gmail.com
Mobile: +91-9871115233

Calendar

<<  May 2012  >>
MoTuWeThFrSaSu
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910

View posts in large calendar
Disclaimer

The articles documented here contain some material excerpted from net, I will try to make sure that I mention reference to those sites, but if I miss out on some areas it is not intentional.

© Copyright 2012