|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionOne of my favorite features about good old C was function pointers. Those of
you who haven't used function pointers missed out on the fun. When C++ was out
we also had pointers to member functions. The basic problem with function
pointers and pointers to member functions is that, neither of them is type-safe.
The .NET framework has a class named Delegates are called single-cast delegates when they encapsulate a single
method, and are called multi-cast delegates when they encapsulate more than one
method. Multi-cast delegates are useful as event-handlers. Multi-cast delegates
should not be confused with an array of delegates. Multi-cast delegates are
derived from the Basic operationsDeclaring delegatesIn Managed C++ we use the //delegate declaration using Managed C++ __delegate String* DelegateAbc(); //delegate declaration using C# public delegate String DelegateAbc(); Binding delegates to methodsFor a single-cast delegate we simple use the default delegate constructor
which the delegates inherit from //binding delegates using MC++ DelegateAbc *d1 = new DelegateAbc(t1,&Test::TestAbc); //instance method DelegateAbc *d2 = new DelegateAbc(0,&Test::TestStatic); //static method //binding delegates using C# DelegateAbc d1 = new DelegateAbc (t1.TestAbc); //instance method DelegateAbc d2 = new DelegateAbc (Test.TestAbc); //static method For multi-cast delegates we use the //multi-cast delegate using MC++ d1 = static_cast<DelegateAbc*> (Delegate::Combine(d1, new DelegateAbc(t1,&Test::TestAbc))); //multi-cast delegate using C# d1 = d2 + new DelegateAbc (Test.TestAbc); //using the + operator d1 += new DelegateAbc (Test.TestAbc); //using the += operator For removing a delegate from the invocation list of a multi-cast delegate we
use the //removing a delegate from a multi-cast delegate - MC++ d1 = static_cast<DelegateAbc*>(Delegate::Remove(d1,d2)); //removing a delegate from a multi-cast delegate - C# d1 = d1 - d2; //using the - operator d1 -= d3; //using the -= operator Invoking a delegateWhen we invoke a delegate, the encapsulated methods are synchronously called
in the order in which they were attached to the delegate. In Managed C++ this is
achieved by calling a method called //invoking a delegate with MC++ d1->Invoke("4"); //passing a string as argument d2->Invoke(); //no arguments //invoking a delegate with C# d1("4"); //passing a string as argument d2(); //no arguments Now we'll see some small sample programs that will make things clearer to you. Compile and run the programs and try and figure out whether the output you get makes sense. If you are confused, don't worry too much, just read the article once more and then think about it for some time. Things will slowly make sense. There are also some good articles on MSDN dealing with delegates which will enlighten you further. Program 1In this program we'll see how to declare and use a single-cast delegate. Our
delegate takes a /* Managed C++ Sample */ #include "stdafx.h" #using <mscorlib.dll> using namespace System; __delegate String* DelegateAbc(String* txt); __gc class Test { public: String* TestAbc(String* txt) { Console::WriteLine(txt); return "Hello from TestAbc"; } static String* TestStatic(String* txt) { Console::WriteLine(txt); return "Hello from TestStatic"; } }; int wmain(void) { Test *t1 = new Test(); DelegateAbc *d1 = new DelegateAbc(t1,&Test::TestAbc); Console::WriteLine(d1->Invoke("First call")); d1 = new DelegateAbc(0,&Test::TestStatic); Console::WriteLine(d1->Invoke("Second call")); return 0; } /* C# Sample */ using System; class DelegateDemo { delegate String DelegateAbc(String txt); public String TestAbc(String txt) { Console.WriteLine(txt); return "Hello from TestAbc"; } public static String TestStatic(String txt) { Console.WriteLine(txt); return "Hello from TestStatic"; } static void Main() { DelegateDemo t1 = new DelegateDemo(); DelegateAbc d1 = new DelegateAbc(t1.TestAbc); Console.WriteLine(d1("First call")); d1 = new DelegateAbc(DelegateDemo.TestStatic); Console.WriteLine(d1("Second call")); } } Program 2Now we'll see an example of using a multi-cast delegate. Our delegate takes
zero arguments and returns /* Managed C++ Sample */ #include "stdafx.h" #using <mscorlib.dll> using namespace System; __delegate void DelegateAbc(); __gc class Test { public: void TestAbc() { Console::WriteLine("This is from TestAbc"); } static void TestStatic() { Console::WriteLine("This is from the static method"); } }; int wmain(void) { Test *t1 = new Test(); DelegateAbc *d1 = new DelegateAbc(t1,&Test::TestAbc); DelegateAbc *d2 = new DelegateAbc(0,&Test::TestStatic); d1 = static_cast<DelegateAbc*> (Delegate::Combine(d1,d2)); d1->Invoke(); d1 = static_cast<DelegateAbc*>(Delegate::Remove(d1,d2)); Console::WriteLine(); d1->Invoke(); return 0; } /* C# Sample */ using System; class DelegateDemo { delegate void DelegateAbc(); public void TestAbc() { Console.WriteLine("This is from TestAbc"); } public static void TestStatic() { Console.WriteLine("This is from the static method"); } static void Main() { DelegateDemo t1 = new DelegateDemo(); DelegateAbc d1 = new DelegateAbc(t1.TestAbc); DelegateAbc d2 = new DelegateAbc(DelegateDemo.TestStatic); d1 = d1+d2; d1(); d1 -= d2; Console.WriteLine(); d1(); } } Program 3In this program we will see how we can pass a delegate object as an argument to a
method. The groovy thing about this is that the called method has absolutely no
idea what the passed delegate is referencing. In our little example we have a
delegate that takes an /* Managed C++ Sample */ #include "stdafx.h" #using <mscorlib.dll> using namespace System; __delegate int DelegateAbc(int); __gc class Test { public: int SquareMe(int i) { return i*i; } int CubeMe(int i) { return i*i*i; } void ShowResult(DelegateAbc* d, String* s,int i) { Console::WriteLine("{0} of {1} is {2}",s, i.ToString(),d->Invoke(i).ToString()); } }; int wmain(void) { Test *t = new Test(); t->ShowResult(new DelegateAbc(t,&Test::SquareMe),"Square",7); t->ShowResult(new DelegateAbc(t,&Test::CubeMe),"Cube",7); } /* C# Sample */ using System; class DelegateDemo { delegate int DelegateAbc(int i); public int SquareMe(int i) { return i*i; } public int CubeMe(int i) { return i*i*i; } void ShowResult(DelegateAbc d, String s,int i) { Console.WriteLine("{0} of {1} is {2}",s,i,d(i)); } static void Main() { DelegateDemo t = new DelegateDemo(); t.ShowResult(new DelegateAbc(t.SquareMe),"Square",7); t.ShowResult(new DelegateAbc(t.CubeMe),"Cube",7); } } ConclusionWell, summing up, a delegate is just about the equivalent of function
pointers except that delegates are objects and are type safe. Unlike function
pointers delegates can reference both static and instance methods of a class.
Delegates inherit from The great thing about delegates is that they don't care about the class whose member function they are referencing. All it cares about is that the arguments passed and the return type match that of its own. We can thus use delegates for black-box-invocation, where we don't know what member function the delegate is pointing to. Delegates are very useful as event handlers. When an event is raised the event handlers of the subscribing classes are invoked through delegates.
|
||||||||||||||||||||||