Delegate and Event

22
Overview All of us have been exposed to event driven programming of some sort or the other. C# adds on value to the often mentioned world of event driven programming by addin g support thro ugh event s and deleg ates. The emphasis of this article would be to identify what exactly happens when you add an event handler to your common UI controls. A simple simulation of what could possibly be going on behind the scenes when the AddOnClick or any similar event is added to the Button class will be explained. This will help you understand better the nature of event handling using multi cast delegates. Delegates A delegate in C# is similar to a function pointer in C or C++. Using a delegate allows the programmer to encapsulate a reference to a method inside a delegate object. The delegate objec t can then be pas sed to code which can call the refer enc ed method, without having to know at compile time which method will be invoked. Call a Function directly - No Delegate In most cases, when we call a function, we specify the function to be called directly. If the class MyClass has a function named Process, we'd normally call it like this (SimpleSample.cs ): using System;  namespace Akadia.NoDelegate { public class MyClass { public void Process() { Console.WriteLine("Process() begin"); Console.WriteLine("Process() end"); } }  public class Test { static void Main(string[] args) {  MyClass myClass = new MyClass(); myClass.Process(); } } } That works well in most situations. Sometimes, however, we don't want to call a function directly - we'd like to be able to pass it to somebody else so that they can call it. This is especially useful in an event-driven system such as a graphical user interface, when I want some code to be executed when the user clicks on a button, or when I want to log some information but can't specify how it is logged. 1

Transcript of Delegate and Event

Page 1: Delegate and Event

8/8/2019 Delegate and Event

http://slidepdf.com/reader/full/delegate-and-event 1/22

Page 2: Delegate and Event

8/8/2019 Delegate and Event

http://slidepdf.com/reader/full/delegate-and-event 2/22

The very basic Delegate

An interesting and useful property of a delegate is that it does not know or careabout the class of the object that it references. Any object will do; all that matters is

that the method's argument types and return type match the delegate's. This makesdelegates perfectly suited for "anonymous" invocation.

The signature of a single cast delegate is shown below:

delegate result-type identifier ([parameters]);

where:

o result-type: The result type, which matches the return type of 

the function.o identifier: The delegate name.

o parameters: The Parameters, that the function takes.

Examples:

 public delegate void SimpleDelegate ()

This declaration defines a delegate named SimpleDelegate, which will

encapsulate any method that takesno parameters and returns no value.

 public delegate int ButtonClickHandler (object obj1, object obj2)

This declaration defines a delegate named ButtonClickHandler, which will

encapsulate any method that takestwo objects as parameters and returns an int.

A delegate will allow us to specify what the function we'll be calling looks

like without having to specify which function to call. The declaration for a

delegate looks just like the declaration for a function, except that in this case, we'redeclaring the signature of functions that this delegate can reference.

There are three steps in defining and using delegates:

o Declaration

o Instantiation

o Invocation

A very basic example (SimpleDelegate1.cs):

using System;

namespace Akadia.BasicDelegate{  // Declaration

2

Page 3: Delegate and Event

8/8/2019 Delegate and Event

http://slidepdf.com/reader/full/delegate-and-event 3/22

   public delegate void SimpleDelegate();

class TestDelegate{

public static void MyFunc(){

Console.WriteLine("I was called by delegate ...");}

public static void Main(){

  // Instantiation  SimpleDelegate simpleDelegate = new SimpleDelegate( MyFunc);

  // Invocation  simpleDelegate();

}}

}

Compile an test:

# csc SimpleDelegate1.cs# SimpleDelegate1.exeI was called by delegate ...

Calling Static Functions

For our next, more advanced example (SimpleDelegate2.cs), declares a delegate

that takes a single string parameter and has no return type:

using System;

namespace Akadia.SimpleDelegate{  // Delegate Specification

public class MyClass{

  // Declare a delegate that takes a single string parameter// and has no return type.

   public delegate void LogHandler(string message);

  // The use of the delegate is just like calling a functiondirectly,

// though we need to add a check to see if the delegate is null

// (that is, not pointing to a function) before calling thefunction.public void Process(LogHandler logHandler){

if (logHandler != null){

logHandler("Process() begin");}

if (logHandler != null)

3

Page 4: Delegate and Event

8/8/2019 Delegate and Event

http://slidepdf.com/reader/full/delegate-and-event 4/22

{logHandler ("Process() end");

}}

}

  // Test Application to use the defined Delegatepublic class TestApplication{

  // Static Function: To which is used in the Delegate. To callthe Process()

// function, we need to declare a logging function: Logger()that matches

// the signature of the delegate.  static void Logger(string s)

{Console.WriteLine(s);

}

static void Main(string[] args)

{MyClass myClass = new MyClass();

  // Crate an instance of the delegate, pointing to thelogging function.

// This delegate will then be passed to the Process()function.

MyClass.LogHandler myLogger = newMyClass.LogHandler(Logger);

myClass.Process( myLogger);}

}}

Compile an test:

# csc SimpleDelegate2.cs# SimpleDelegate2.exeProcess() beginProcess() end

Calling Member Functions

In the simple example above, the Logger( ) function merely writes the string out. Adifferent function might want to log the information to a file, but to do this, the

function needs to know what file to write the information to (SimpleDelegate3.cs

)

4

Page 5: Delegate and Event

8/8/2019 Delegate and Event

http://slidepdf.com/reader/full/delegate-and-event 5/22

using System;using System.IO;

namespace Akadia.SimpleDelegate

{ // Delegate Specificationpublic class MyClass{

  // Declare a delegate that takes a single string parameter// and has no return type.

   public delegate void LogHandler(string message);  // The use of the delegate is just like calling a functiondirectly,

// though we need to add a check to see if the delegate is null// (that is, not pointing to a function) before calling the

function.public void Process(LogHandler logHandler){

if (logHandler != null)

{logHandler("Process() begin");

}

if (logHandler != null){

logHandler ("Process() end");}

}}

  // The FileLogger class merely encapsulates the file I/O   public class FileLogger

{

FileStream fileStream;StreamWriter streamWriter;  // Constructor

public FileLogger(string filename){

fileStream = new FileStream(filename, FileMode.Create);streamWriter = new StreamWriter(fileStream);

}  // Member Function which is used in the Delegate

public void Logger(string s){

streamWriter.WriteLine(s);}

public void Close(){

streamWriter.Close();fileStream.Close();

}}

5

Page 6: Delegate and Event

8/8/2019 Delegate and Event

http://slidepdf.com/reader/full/delegate-and-event 6/22

Page 7: Delegate and Event

8/8/2019 Delegate and Event

http://slidepdf.com/reader/full/delegate-and-event 7/22

   public class MyClass{

  // Declare a delegate that takes a single string parameter// and has no return type.public delegate void LogHandler(string message);

  // The use of the delegate is just like calling a functiondirectly,

// though we need to add a check to see if the delegate is null// (that is, not pointing to a function) before calling the

function.   public void Process(LogHandler logHandler)

{if (logHandler != null){

logHandler("Process() begin");}

if (logHandler != null){

logHandler ("Process() end");}

}}

  // The FileLogger class merely encapsulates the file I/O   public class FileLogger

{FileStream fileStream;StreamWriter streamWriter;

  // Constructorpublic FileLogger(string filename){

fileStream = new FileStream(filename, FileMode.Create);streamWriter = new StreamWriter(fileStream);

}

  // Member Function which is used in the Delegate   public void Logger(string s)

{streamWriter.WriteLine(s);

}

public void Close(){

streamWriter.Close();

fileStream.Close();}

}

  // Test Application which calls both Delegatespublic class TestApplication{

  // Static Function which is used in the Delegate  static void Logger(string s)

{

7

Page 8: Delegate and Event

8/8/2019 Delegate and Event

http://slidepdf.com/reader/full/delegate-and-event 8/22

Console.WriteLine(s);}

static void Main(string[] args){

FileLogger fl = new FileLogger("process.log");

MyClass myClass = new MyClass();

  // Crate an instance of the delegates, pointing to thestatic

// Logger() function defined in the TestApplication classand 

// then to member function on the fl instance of aFileLogger.   MyClass.LogHandler myLogger = null;

myLogger += new MyClass.LogHandler(Logger);myLogger += new MyClass.LogHandler(fl.Logger);

myClass.Process(myLogger);

fl.Close();}

}}

Compile an test:

# csc SimpleDelegate4.cs# SimpleDelegate4.exeProcess() beginProcess() end# cat process.logProcess() begin

Process() end

Events

The Event model in C# finds its roots in the event programming model that is

popular in asynchronous programming. The basic foundation behind thisprogramming model is the idea of "publisher and subscribers." In this model, you

have publishers who will do some logic and publish an "event." Publishers will then

send out their event only to subscribers who have subscribed to receive the specificevent.

In C#, any object can  publish a set of events to which other applications can

subscribe. When the publishing class raises an event, all the subscribed applicationsare notified. The following figure shows this mechanism.

8

Page 9: Delegate and Event

8/8/2019 Delegate and Event

http://slidepdf.com/reader/full/delegate-and-event 9/22

Conventions

The following important conventions are used with events:

o Event Handlers in the .NET Framework return void and take two

parameters.o The first paramter is the source of the event; that is the

publishing object.o The second parameter is an object derived from EventArgs.

o Events are properties of the class publishing the event.

o The keyword event controls how the event property is accessed

by the subscribing classes.

9

Page 10: Delegate and Event

8/8/2019 Delegate and Event

http://slidepdf.com/reader/full/delegate-and-event 10/22

Simple Event

Let's modify our logging example from above to use an event rather than a delegate:

using System;using System.IO;

namespace Akadia.SimpleEvent{  /* ========= Publisher of the Event ============== */

public class MyClass{

  // Define a delegate named LogHandler, which will encapsulate// any method that takes a string as the parameter and returns

no valuepublic delegate void LogHandler(string message);

 // Define an Event based on the above Delegate

   public event LogHandler Log;

  // Instead of having the Process() function take a delegate// as a parameter, we've declared a Log event. Call the Event,// using the OnXXXX Method, where XXXX is the name of the Event.public void Process(){

  OnLog("Process() begin");  OnLog("Process() end");

// By Default, create an OnXXXX Method, to call the Event   protected void OnLog(string message)

{if (Log != null)

  {  Log(message);  }  }

// The FileLogger class merely encapsulates the file I/Opublic class FileLogger{

FileStream fileStream;StreamWriter streamWriter;

 // Constructor

public FileLogger(string filename){

fileStream = new FileStream(filename, FileMode.Create);streamWriter = new StreamWriter(fileStream);

// Member Function which is used in the Delegatepublic void Logger(string s){

streamWriter.WriteLine(s);

10

Page 11: Delegate and Event

8/8/2019 Delegate and Event

http://slidepdf.com/reader/full/delegate-and-event 11/22

public void Close(){

streamWriter.Close();fileStream.Close();

}}

 /* ========= Subscriber of the Event ============== */

  // It's now easier and cleaner to merely add instances// of the delegate to the event, instead of having to// manage things ourselvespublic class TestApplication{

static void Logger(string s){

Console.WriteLine(s);}

 

static void Main(string[] args){

FileLogger fl = new FileLogger("process.log");MyClass myClass = new MyClass();

 // Subscribe the Functions Logger and fl.Logger

   myClass.Log += new MyClass.LogHandler(Logger);myClass.Log += new MyClass.LogHandler(fl.Logger);

  // The Event will now be triggered in the Process() MethodmyClass.Process();

 fl.Close();

}}

}

Compile an test:

# csc SimpleEvent.cs# SimpleEvent.exeProcess() beginProcess() end# cat process.logProcess() beginProcess() end

The Second Change Event Example

Suppose you want to create a Clock class that uses events to notify potentialsubscribers whenever the local time changes value by one second. Here is the

complete, documented example:

using System;using System.Threading;

11

Page 12: Delegate and Event

8/8/2019 Delegate and Event

http://slidepdf.com/reader/full/delegate-and-event 12/22

namespace SecondChangeEvent{  /* ======================= Event Publisher=============================== */

  // Our subject -- it is this class that other classes// will observe. This class publishes one event:// SecondChange. The observers subscribe to that event.public class Clock{

  // Private Fields holding the hour, minute and secondprivate int _hour;private int _minute;private int _second;

  // The delegate named SecondChangeHandler, which will encapsulate// any method that takes a clock object and a TimeInfoEventArgs// object as the parameter and returns no value. It's the// delegate the subscribers must implement.

   public delegate void SecondChangeHandler (object clock,TimeInfoEventArgs timeInformation

);

  // The event we publish   public event SecondChangeHandler SecondChange;

  // The method which fires the Event   protected void OnSecondChange(

object clock,TimeInfoEventArgs timeInformation

){

// Check if there are any Subscribersif (SecondChange != null){

// Call the EventSecondChange(clock,timeInformation);

}}

  // Set the clock running, it will raise an// event for each new secondpublic void Run(){

for(;;)

{  // Sleep 1 Second

Thread.Sleep(1000);

  // Get the current timeSystem.DateTime dt = System.DateTime.Now;

  // If the second has changed// notify the subscribersif (dt.Second != _second)

12

Page 13: Delegate and Event

8/8/2019 Delegate and Event

http://slidepdf.com/reader/full/delegate-and-event 13/22

{  // Create the TimeInfoEventArgs object

// to pass to the subscribersTimeInfoEventArgs timeInformation =

new TimeInfoEventArgs(dt.Hour,dt.Minute,dt.Second);

  // If anyone has subscribed, notify them  OnSecondChange (this,timeInformation);

}

  // update the state_second = dt.Second;_minute = dt.Minute;_hour = dt.Hour;

}}

}

  // The class to hold the information about the event// in this case it will hold only information// available in the clock class, but could hold// additional state informationpublic class TimeInfoEventArgs : EventArgs{

public TimeInfoEventArgs(int hour, int minute, int second){

this.hour = hour;this.minute = minute;this.second = second;

}public readonly int hour;public readonly int minute;public readonly int second;

}

  /* ======================= Event Subscribers=============================== */

  // An observer. DisplayClock subscribes to the// clock's events. The job of DisplayClock is// to display the current timepublic class DisplayClock{

  // Given a clock, subscribe to// its SecondChangeHandler event

public void Subscribe(Clock theClock){

  theClock.SecondChange +=new Clock.SecondChangeHandler(TimeHasChanged);

}

  // The method that implements the// delegated functionalitypublic void TimeHasChanged(

object theClock, TimeInfoEventArgs ti)

13

Page 14: Delegate and Event

8/8/2019 Delegate and Event

http://slidepdf.com/reader/full/delegate-and-event 14/22

{Console.WriteLine("Current Time: {0}:{1}:{2}",

ti.hour.ToString(),ti.minute.ToString(),ti.second.ToString());

}}

  // A second subscriber whose job is to write to a filepublic class LogClock{

public void Subscribe(Clock theClock){

  theClock.SecondChange +=new Clock.SecondChangeHandler(WriteLogEntry);

}

  // This method should write to a file// we write to the console to see the effect

  // this object keeps no state

public void WriteLogEntry(object theClock, TimeInfoEventArgs ti)

{Console.WriteLine("Logging to file: {0}:{1}:{2}",

ti.hour.ToString(),ti.minute.ToString(),ti.second.ToString());

}}

  /* ======================= Test Application=============================== */

  // Test Application which implements the// Clock Notifier - Subscriber Samplepublic class Test{

public static void Main(){

  // Create a new clockClock theClock = new Clock();

  // Create the display and tell it to// subscribe to the clock just createdDisplayClock dc = new DisplayClock();dc.Subscribe(theClock);

  // Create a Log object and tell it// to subscribe to the clockLogClock lc = new LogClock();lc.Subscribe(theClock);

  // Get the clock startedtheClock.Run();

}}

}

14

Page 15: Delegate and Event

8/8/2019 Delegate and Event

http://slidepdf.com/reader/full/delegate-and-event 15/22

Conclusion

The Clock class from the last sample could simply print the time rather tahn raising

an event, so why bother with the introduction of using delegates? The

advantage of the publisg / subscribe idiom is that any number of classes can benotified when an event is raised. The subscribing classes do not need to know

how the Clock works, and the Clock does not need to know what they are going to

do in response to the event. Similarly a button can publish an Onclick event, and anynumber of unrelated objects can subscribe to that event, receiving notification when

the button is clicked.

The publisher and the subscribers are decoupled by the delegate. This is

highly desirable as it makes for more flexible and robust code. The clock can chnagehow it detects time without breaking any of the subscribing classes. The subscribing

classes can change how they respond to time changes without breaking the Clock.The two classes spin indepentdently of one another, which makes for code that is

easier to maintain.

Article I. Callback (computer science)

(a) From Wikipedia, the free encyclopedia

A callback is often back on the level of the original caller.

In another common scenario, the callback is first registered and later calledasynchronously.

In computer programming, a callback is executable code that is passed asan argument to other code. It allows a lower-level software layer to call a

subroutine (or function) defined in a higher-level layer.

Usually, the higher-level code starts by calling a function within the lower-level code passing to it a pointer or handle to another function. While thelower-level function executes, it may call the passed-in function any number

of times to perform some subtask. In another scenario, the lower-levelfunction registers the passed-in function as a handler  that is to be called

asynchronously by the lower-level at a later time in reaction to something.programming

A callback can be used as a simpler alternative to polymorphism and

generic , in that the exact behavior of a function can be dynamicallydetermined by passing different (yet compatible) function pointers or handlesto the lower-level function. This can be a very powerful technique for codereuse.

15

Page 16: Delegate and Event

8/8/2019 Delegate and Event

http://slidepdf.com/reader/full/delegate-and-event 16/22

16

Page 17: Delegate and Event

8/8/2019 Delegate and Event

http://slidepdf.com/reader/full/delegate-and-event 17/22

Section I.2 Contents

[hide]

• 1 Motivation• 2 Example

• 3 Implementation

• 4 Special cases

• 5 See also

• 6 External links

Motivation

To understand the motivation for using callbacks, consider the problem of performing an arbitrary operation on each item in a list. One approach is toiterate over the list, operating on each object. This is the most commonsolution in practice, but it is not ideal; the code to manage the iterator (for

example, a for statement) must be duplicated at each point in the codewhere the list is traversed. Furthermore, if the list is updated by an

asynchronous process (for example, if an item is added or removed), theiterator might skip over items or become corrupt during the traversal.

An alternative might be to create a new library function that performs thedesired operation with appropriate synchronization. This approach still

requires each new library function to contain the code to traverse the list.This solution is not acceptable for generic libraries intended for variousapplications; the library developer cannot anticipate every application need,and the application developer should not need to know the details of the

library implementation.

Callbacks solve these shortcomings. One procedure is written to traverse the

list, and this procedure uses application-provided code to operate on eachitem. There is a clear distinction between the library and the application

without sacrificing flexibility.

A callback may also be regarded as a form of runtime binding, as discussed in theinfluential Design Patterns book (see the Chapter 1 summary).

Example

The following code in C demonstrates the use of callbacks for the specific case of 

searching an array for an item (in this case, the first integer greater than 5). First,the iteration approach:

17

Page 18: Delegate and Event

8/8/2019 Delegate and Event

http://slidepdf.com/reader/full/delegate-and-event 18/22

int i; for (i = 0; i < length; i++) {  if (array[i] > 5) { 

 break;  } } if (i < length) {

  printf("Item %d\n", i); } else {  printf("Not found\n"); }

Next, the callback approach:

/* LIBRARY CODE */ 

 int traverseWith(int array[], size_t length,int (*callback)(int index, int item, void *param),void *param)

 {  int exitCode = 0;  for (int i = 0; i < length; i++) {

exitCode = callback(i, array[i], param);  if (exitCode != 0) { 

 break;  }  }  return exitCode; } /* APPLICATION CODE */ 

 int search (int index, int item, void *param) {

  if (item > 5) {*(int *)param = index;

  return 1;  } else {  return 0;  } } /* (in another function) */ 

 int index; int found;found = traverseWith(array, length, &search, &index);

 if (found) {

  printf("Item %d\n", index); } else {

  printf("Not found\n"); }

Note that traverseWith receives an extra parameter that the callback can use for its

own purposes. Normally a callback uses such a parameter as a pointer to applicationdata outside its own scope (in this case, the variable that receives the index). This

feature is necessary only in a statically scoped language like C or C++ (in C++ and

18

Page 19: Delegate and Event

8/8/2019 Delegate and Event

http://slidepdf.com/reader/full/delegate-and-event 19/22

OO languages other solutions are however possible, see below). Lexically scopedlanguages supporting closures (including functional programming languages) can

provide access to application data automatically by callbacks referring to localvariables. In Lisp, for example, the same program would look like this:

; LIBRARY CODE 

 (defun traverseWith (array callback)  (let ((exitCode nil)  (i 0))  (while (and (not exitCode) (< i (length array)))  (setf exitCode (funcall callback i (aref array i)))  (setf i (+ i 1)))

exitCode)) ; APPLICATION CODE 

 (let (index found)  (setf found (traverseWith array (lambda (idx item)  (if (<= item 5)  nil  (progn  (setf index idx)

t))))))

The callback function is now defined at the point of use, and it refers to "index" by

name. Synchronization concerns have been omitted from these examples, but theycan easily be addressed in the traverseWith function. More importantly, they can be

addressed, or ignored, by changing only that function.

 

19

Page 20: Delegate and Event

8/8/2019 Delegate and Event

http://slidepdf.com/reader/full/delegate-and-event 20/22

20

Page 21: Delegate and Event

8/8/2019 Delegate and Event

http://slidepdf.com/reader/full/delegate-and-event 21/22

Implementation

The form of a callback varies among programming languages.

• C and C++ allow function pointers as arguments to other functions.

• Several programming languages (though especially functional programming

languages such as Scheme or ML) allow closures, a generalization of function

 pointers, as arguments to other functions.

• Several programming languages, especially interpreted languages, allow one to

 pass the name of a function A as a parameter to a function B and have B call A by

means of eval.

• In object-oriented programming languages, a call can accept an object that

implements some abstract interface, without specifying in detail how the object

should do so. The programmer who implements that object may use the interface'smethods exclusively for application-specific code. Such objects are effectively a bundle of callbacks, plus the data they need to manipulate. They are useful in

implementing various design patterns like Visitor , Observer , and Strategy.

• C++ allows objects to provide their own implementation of the function calloperation. The Standard Template Library accepts these objects (called  functors),

as well as function pointers, as parameters to various polymorphic algorithms

• Some systems have built-in programming languages to support extension andadaptation. These languages provide callbacks without the need for separate

software development tools.

Special cases

Callback functions are also frequently used as a means to handle exceptions arisingwithin the low level function, as a way to enable side-effects in response to some

condition, or as a way to gather operational statistics in the course of a largercomputation. Interrupt handlers in an operating system respond to hardware

conditions, signal handlers of a process are triggered by the operating system, andevent handlers process the asynchronous input a program receives.

A pure callback function is one which is purely functional (always returns the samevalue given the same inputs) and free of observable side-effects. Some uses of 

callbacks, such as the sorting example, require pure callback functions to operatecorrectly.

A special case of a callback is called a predicate callback, or just predicate for

short. This is a pure callback function which accepts a single input value and returns

a Boolean value. These types of callbacks are useful for filtering collections of valuesby some condition.

In event-driven programming, there is often use, in different forms, of the Observerpattern, which essentially allows the use of multicast callbacks, and where callbacks

21

Page 22: Delegate and Event

8/8/2019 Delegate and Event

http://slidepdf.com/reader/full/delegate-and-event 22/22