Multicasting

One of the most exciting features of a delegate is its support for multicasting.

Multicasting is the ability to create a chain of methods that will be automatically called when a delegate is invoked. Such a chain is very easy to create.

Simply instantiate a delegate, and then use the += operator to add methods to the chain. To remove a method, use – =. (You can also use the +, –, and = operators separately to add and subtract delegates, but += and – = are

more convenient.)

The only restriction is that the delegate being multicast must have a void return type.

Here is an example of multicasting. It reworks the preceding examples by

changing the string manipulation method’s return type to void, and using a ref

parameter to return the altered string to the caller.

// Demonstrate multicasting.

using System;

// Declare a delegate.

delegate void strMod(ref string str);

class StringOps {

// Replaces spaces with hyphens.

static void replaceSpaces(ref string a) {

Console.WriteLine(“Replaces spaces with hyphens.”);

a = a.Replace(‘ ‘, ‘-‘);

}

// Remove spaces.

static void removeSpaces(ref string a) {

string temp = “”;int i;

Console.WriteLine(“Removing spaces.”);

for(i=0; i < a.Length; i++)

if(a[i] != ‘ ‘) temp += a[i];

a = temp;

}

// Reverse a string.

static void reverse(ref string a) {

string temp = “”;

int i, j;

Console.WriteLine(“Reversing string.”);

for(j=0, i=a.Length-1; i >= 0; i–, j++)

temp += a[i];

a = temp;

}

public static void Main() {

// Construct delegates.

strMod strOp;

strMod replaceSp = new strMod(replaceSpaces);

strMod removeSp = new strMod(removeSpaces);

strMod reverseStr = new strMod(reverse);

string str = “This is a test”;

// set up multicast

strOp = replaceSp;

strOp += reverseStr; <——————————-Create a multicast.

// Call multicast

strOp(ref str);

Console.WriteLine(“Resulting string: ” + str);

Console.WriteLine();

// remove replace and add remove

strOp -= replaceSp;

strOp += removeSp; <————————-Create a different multicast.

str = “This is a test.”; // reset string

// Call multicast

strOp(ref str);

Console.WriteLine(“Resulting string: ” + str);

Console.WriteLine();

}

}

Here is the output:

Replaces spaces with hyphens.

Reversing string.

Resulting string: tset-a-si-sihT

Reversing string.

Removing spaces.

Resulting string: .tsetasisihT

In Main( ), four delegate instances are created. One, strOp, is null. The other three refer to specific string modification methods. Next, a multicast is created that calls removeSpaces( ) and reverse( ). This is accomplished via the following lines:

strOp = replaceSp;

strOp += reverseStr;

First, strOp is assigned a reference to replaceSp. Next, using +=, reverseStr is

added. When strOp is invoked, both methods are invoked, replacing spaces with hyphens and reversing the string, as the output illustrates.

Next, replaceSp is removed from the chain, using this line:

strOp -= replaceSp;

and removeSp is added using this line:

strOp += removeSp;

Then, StrOp is again invoked. This time, spaces are removed and the string is reversed.

Delegate Basic

An interesting and useful property of a delegate is that it does not know or care about 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 makes delegates perfectly suited for “anonymous” invocation.

The signature of a single cast delegate is shown below:

delegate result-type identifier ([parameters]);

where:

  • result-type: The result type, which matches the return type of the function.
  • identifier: The delegate name.
  • 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 takes
no 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 takes
two 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’re declaring the signature of functions that this delegate can reference.

There are three steps in defining and using delegates:

  • Declaration
  • Instantiation
  • Invocation

A very basic example (SimpleDelegate1.cs):

using System;

namespace Akadia.BasicDelegate
{
// Declaration
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.exe
I 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 function directly,
// 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”);
}
}
}

// Test Application to use the defined Delegate
public class TestApplication
{
// Static Function: To which is used in the Delegate. To call the 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 the logging function.
// This delegate will then be passed to the Process() function.

MyClass.LogHandler myLogger = new MyClass.LogHandler(Logger);
myClass.Process(myLogger);
}
}
}

Compile an test:

# csc SimpleDelegate2.cs
# SimpleDelegate2.exe
Process() begin
Process() end

Calling Member Functions

In the simple example above, the Logger( ) function merely writes the string out. A different 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)

using System;
using System.IO;

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 function directly,
// 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();
}
}

// Main() is modified so that the delegate points to the Logger()
// function on the fl instance of a FileLogger. When this delegate
// is invoked from Process(), the member function is called and
// the string is logged to the appropriate file.

public class TestApplication
{
static void Main(string[] args)
{
FileLogger fl = new FileLogger(“process.log”);

MyClass myClass = new MyClass();

// Crate an instance of the delegate, pointing to the Logger()
// function on the fl instance of a FileLogger.

MyClass.LogHandler myLogger = new MyClass.LogHandler(fl.Logger);
myClass.Process(myLogger);
fl.Close();
}
}
}

The cool part here is that we didn’t have to change the Process() function; the code to all the delegate is the same regardless of whether it refers to a static or member function.

Compile an test:

# csc SimpleDelegate3.cs
# SimpleDelegate3.exe
# cat process.log
Process() begin
Process() end

Why Delegates

In general, delegates are useful for two main reasons.

First, delegates support events.

Second, delegates give your program a way to execute a method at runtime without having to know precisely what that method is at compile time.

This ability is quite useful when you want to create a framework that allows components to be plugged in. For example, imagine a drawing program (a bit like the standard Windows Paint accessory). Using a delegate, you could allow the user to plug in special color filters or image analyzers. Furthermore, the user could create a sequence of these filters or analyzers. Such a scheme would be easily handled using a delegate.

Delegates

A delegate is a reference type used to encapsulate a method with a specific signature and return type. Simply it’s a reference type to method.

In C++ and many other languages, we can use this requirement with function pointers and pointers to member functions. Unlike function pointers, delegates are object-oriented and type-safe

A delegate is created with the delegate keyword, followed by a return type and the signature of the methods that can be delegated to it, as in the following:

public delegate int MyDelegate(object obj1, object obj2);

Simple Example:

  1. Create a new Windows application in VS 2008.
  2. Add code file and enter the Delegate definition

Commonly Delegates are defined in code file

public delegate int MyCalcDelegate(int x, int y);

  1. Add New class called Calculator tat contain Add(),Sub(), Mul(), Div().


class Calculator
{
public int Add(int x, int y)
{
return (x + y);
}
public int Sub(int x, int y)
{
return (x – y);
}
public int Mul(int x, int y)
{
return (x * y);
}
public int Div(int x, int y)
{
return (x / y);
}
}

  1. Add one Button named Delegate to the form and enter the give code

private void Delegate_Click(object sender, EventArgs e)

{

Calculator calc = new Calculator();

MyCalcDelegate del = new MyCalcDelegate (calc.Add);

int sum = del(10, 5);

del += new MyAreaDelegates(calc.Sub);

del += new MyAreaDelegates(calc.Mul);

del += new MyAreaDelegates(calc.Div);

Console.WriteLine(“Result:”+sum);

}

Change the Debugging properties as Console Application and run the application

Now you can see only result for Add().

If we want to call all methods in delegates, we must invoke “MulticastDelegate”

Multicast Delegate having the Invocation list. That Invocation list obtain by calling the method getInvocation().

We can modify the above coding as follow as

private void Delegate_Click(object sender, EventArgs e)

{

Calculator calc = new Calculator();

MyCalcDelegate del = new MyCalcDelegate (calc.Add);

del += new MyAreaDelegates(calc.Sub);

del += new MyAreaDelegates(calc.Mul);

del += new MyAreaDelegates(calc.Div);

Delegate[] myDel=del.GetInvocationList();

foreach(del d in myDel)

{

Int re=d(10,5);

Console.WriteLine(“Result is:”+re);

}

}