C# - Delegate and Event:-

C# - DELEGATES:-

 

  • C# delegates are similar to pointers to functions, in C or C++. A delegate is a reference type variable that holds the reference to a method. Thereference can be changed at runtime.
  • Delegates are especially used for implementing events and the call-back methods. All delegates are implicitly derived from the System.Delegate class.

Declaring Delegates

Delegate declaration determines the methods that can be referenced by the delegate. A delegate can refer to a method, which have the same sig nature as that of the delegate.

For example, consider a delegate:

public delegate int MyDelegate (string s);

 

Thepreceding delegate can be used to reference any method that has a sing le string parameter and returns an int type variable.

 

Syntax for delegate declaration is:

delegate <return type> <delegate-name> <parameter list>

 

Instantiating Delegates

Once a delegate type has been declared, a delegate object must be created with the new keyword and be associated with a particular method. When creating a delegate, the argument passed to the new expression is written like a method call, but without the arguments to the method. For example:

public delegate void printString(string s);

...

printString ps1 = new printString(WriteToScreen);

printString ps2 = new printString(WriteToFile);

Following example demonstrates declaration, instantiation and use of a delegate that can be used to reference methods that take an integ er parameter and returns an integ er value.

using System;

delegate int NumberChanger(int n);

namespace DelegateAppl

{

class TestDelegate

{

static int num = 10;

public static int AddNum(int p)

{

num += p;

return num;

}

public static int MultNum(int q)

{

num *= q;

return num;

}

public static int getNum()

{

return num;

}

static void Main(string[] args)

{

//create delegate instances

NumberChanger nc1 = new NumberChanger(AddNum);

NumberChanger nc2 = new NumberChanger(MultNum);

//calling the methods using the delegate objects

nc1(25);

Console.WriteLine("Value of Num: {0}", getNum());

nc2(5);

Console.WriteLine("Value of Num: {0}", getNum());

Console.ReadKey();

}

}

}

When the above code is compiled and executed, it produces the following result:

Value of Num: 35

Value of Num: 175

 

Multicasting of a Delegate

 

  • Delegate objects can be composed using the "+" operator. A composed delegate calls the two delegates it was composed from. Only delegates of the same type can be composed. The"-" operator can be used to remove a component delegate from a composed delegate.
  • Using this useful property of delegates you can create an invocation list of methods that will be called when a delegate is invoked. Thisis called multicasting of a delegate. Thefollowing program demonstrates multicasting of a delegate:

using System;

delegate int NumberChanger(int n);

namespace DelegateAppl

{

class TestDelegate

{

static int num = 10;

public static int AddNum(int p)

{

num += p;

return num;

}

public static int MultNum(int q)

{

num *= q;

return num;

}

public static int getNum()

{

return num;

}

static void Main(string[] args)

{

//create delegate instances

NumberChanger nc;

NumberChanger nc1 = new NumberChanger(AddNum);

NumberChanger nc2 = new NumberChanger(MultNum);

nc = nc1;

nc += nc2;

//calling multicast

nc(5);

Console.WriteLine("Value of Num: {0}", getNum());

Console.ReadKey();

}

}

}

When the above code is compiled and executed, it produces the following result:

Value of Num: 75

 

Use of Delegate

 

Thefollowing example demonstrates the use of delegate. Thedelegate printString can be used to reference methods that take a string as input and return nothing.

We use this delegate to call two methods, the first prints the string to the console, and the second one prints it to a file:

 

using System;

using System.IO;

namespace DelegateAppl

{

class PrintString

{

static FileStream fs;

static StreamWriter sw;

// delegate declaration

public delegate void printString(string s);

// this method prints to the console

public static void WriteToScreen(string str)

{

Console.WriteLine("The String is: {0}", str);

}

//this method prints to a file

public static void WriteToFile(string s)

{

fs = new FileStream("c:\\message.txt",

FileMode.Append, FileAccess.Write);

sw = new StreamWriter(fs);

sw.WriteLine(s);

sw.Flush();

sw.Close();

fs.Close();

}

// this method takes the delegate as parameter and uses it to

// call the methods as required

public static void sendString(printString ps)

{

ps("Hello World");

}

static void Main(string[] args)

{

printString ps1 = new printString(WriteToScreen);

printString ps2 = new printString(WriteToFile);

sendString(ps1);

sendString(ps2);

Console.ReadKey();

}

}

}

When the above code is compiled and executed, it produces the following result:

The String is: Hello World



C# - EVENTS:-

 

Events are basically a user action like key press, clicks, mouse movements, etc., or some occurrence like system generated notifications. Applications need to respond to events when they occur. For example, interrupts. Events are used for inter-process communication.

 

Using Delegates with Events

 

The events are declared and raised in a class and associated with the event handlers using delegates within the same class or some other class. The class containing the event is used to publish the event. This is called the publisher class. Some other class that accepts this event is called the subscriber class. Events use the publisher-subscriber model.

A publisher is an object that contains the definition of the event and the delegate. The event-delegate association is also defined in this object. A publisher class object invokes the event and it is notified to other objects.

 

A subscriber is an object that accepts the event and provides an event handler. Thedelegate in the publisher class invokes the method (event handler) of the subscriber class.

 

Declaring Events

T o declare an event inside a class, first a deleg ate type for the event must be declared. For example,

public delegate void BoilerLogHandler(string status);

Next, the event itself is declared, using the event keyword:

//Defining event based on the above delegate

public event BoilerLogHandler BoilerEventLog;

 

Thepreceding code defines a deleg ate named BoilerLogHandler and an event named BoilerEventLog, which

invokes the deleg ate when it is raised.

 

Example 1:

using System;

namespace SimpleEvent

{

using System;

public class EventTest

{

private int value;

public delegate void NumManipulationHandler();

public event NumManipulationHandler ChangeNum;

protected virtual void OnNumChanged()

{

if (ChangeNum != null)

{

ChangeNum();

}

else

{

Console.WriteLine("Event fired!");

}

}

public EventTest(int n )

{

SetValue(n);

}

public void SetValue(int n)

{

if (value != n)

{

value = n;

OnNumChanged();

}

}

}

public class MainClass

{

public static void Main()

{

EventTest e = new EventTest(5);

e.SetValue(7);

e.SetValue(11);

Console.ReadKey();

}

}

}

 

When the above code is compiled and executed, it produces the following result:

 

Event Fired!

Event Fired!

Event Fired!

 

Example 2:

Thisexample provides a simple application for troubleshooting for a hot water boiler system. When the maintenance engineer inspects the boiler, the boiler temperature and pressure is automatically recorded into a log file along with the remarks of the maintenance engineer.

 

using System;

using System.IO;

namespace BoilerEventAppl

{

// boiler class

class Boiler

{

private int temp;

private int pressure;

public Boiler(int t, int p)

{

temp = t;

pressure = p;

}

public int getTemp()

{

return temp;

}

public int getPressure()

{

return pressure;

}

}

// event publisher

class DelegateBoilerEvent

{

public delegate void BoilerLogHandler(string status);

//Defining event based on the above delegate

public event BoilerLogHandler BoilerEventLog;

public void LogProcess()

{

string remarks = "O. K";

Boiler b = new Boiler(100, 12);

int t = b.getTemp();

int p = b.getPressure();

if(t > 150 || t < 80 || p < 12 || p > 15)

{

remarks = "Need Maintenance";

}

OnBoilerEventLog("Logging Info:\n");

OnBoilerEventLog("Temparature " + t + "\nPressure: " + p);

OnBoilerEventLog("\nMessage: " + remarks);

}

protected void OnBoilerEventLog(string message)

{

if (BoilerEventLog != null)

{

BoilerEventLog(message);

}

}

}

// this class keeps a provision for writing into the log file

class BoilerInfoLogger

{

FileStream fs;

StreamWriter sw;

public BoilerInfoLogger(string filename)

{

fs = new FileStream(filename, FileMode.Append, FileAccess.Write);

sw = new StreamWriter(fs);

}

public void Logger(string info)

{

sw.WriteLine(info);

}

public void Close()

{

sw.Close();

fs.Close();

}

}

// The event subscriber

public class RecordBoilerInfo

{

static void Logger(string info)

{

Console.WriteLine(info);

}//end of Logger

static void Main(string[] args)

{

BoilerInfoLogger filelog = new BoilerInfoLogger("e:\\boiler.txt");

DelegateBoilerEvent boilerEvent = new DelegateBoilerEvent();

boilerEvent.BoilerEventLog += new

DelegateBoilerEvent.BoilerLogHandler(Logger);

boilerEvent.BoilerEventLog += new

DelegateBoilerEvent.BoilerLogHandler(filelog.Logger);

boilerEvent.LogProcess();

Console.ReadLine();

filelog.Close();

}//end of main

}//end of RecordBoilerInfo

}

When the above code is compiled and executed, it produces the following result:

Logging info:

Temperature 100

Pressure 12

Message: O. K