C++ Tutorial on 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. the reference 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 has the same signature as that of the delegate.

for example, consider a delegate −

public delegate int mydelegate (string s);

the preceding delegate can be used to reference any method that has a single 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 is 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 similar to 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 integer parameter and returns an integer 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 property of delegates you can create an invocation list of methods that will be called when a delegate is invoked. this is called multicasting of a delegate. the following 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

using delegates

the following example demonstrates the use of delegate. the delegate printstring can be used to reference method that takes a string as input and returns 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