Subscribe

RSS Feed (xml)

Generic Delegates

Like methods, delegates can also be generic. The syntax is similar to that of a generic method, with the type parameter being specified after the delegate’s name. To declare a generic delegate, use this general form:
delegate ret-type delegate-name<type-parameter-list>(arg-list);
Notice the placement of the type parameter list. It immediately follows the delegate’s name. The advantage of generic delegates is that they let you define, in a type-safe manner, a generalized form that can then be matched to any specific type of method.
The following program demonstrates a generic delegate called SomeOp that has one type parameter called T. It returns type T and takes an argument of type T.
// A simple generic delegate.

using System;

// Declare a generic delegate.
delegate T SomeOp(T v);

class GenDelegateDemo {
  // Return the summation of the argument.
  static int sum(int v) {
    int result = 0;
    for(int i=v; i>0; i--)
      result += i;

    return result;
  }

  // Return a string containing the reverse of the argument.
  static string reflect(string str) {
    string result = "";

    foreach(char ch in str)
      result = ch + result;

    return result;
  }

  public static void Main() {
    // Construct an int delegate. Notice use of method group
    // conversion on generic delegate.
    SomeOp intDel = sum;
    Console.WriteLine(intDel(3));

    // Construct a string delegate. Also use method group conversion.
    SomeOp strDel = reflect;
    Console.WriteLine(strDel("Hello"));
  }
}
The output is shown here:
6
olleH
Let’s look closely at this program. First, notice how the SomeOp delegate is declared:
delegate T SomeOp(T v);
Notice that T can be used as the return type even though the type parameter T is specified after the name SomeOp.
Inside GenDelegateDemo, the methods sum( ) and reflect( ) are declared, as shown here:
static int sum(int v) {

static string reflect(string str) {
The sum( ) method returns the summation of the integer value passed as an argument. The reflect( ) method returns a string that is the reverse of the string passed as an argument.
Inside Main( ), a delegate called intDel is instantiated and assigned a reference to sum( ):
SomeOp intDel = sum;
Because sum( ) takes an int argument and returns an int value, sum( ) is compatible with an int instance of SomeOp. Notice that the new C# 2.0 method group conversion syntax is used to assign sum to intDel. Method group conversions are fully compatible with generic delegates.
In similar fashion, the delegate strDel is created and assigned a reference to reflect( ):
SomeOp strDel = reflect;
Because reflect( ) takes a string argument and returns a string result, it is compatible with the string version of SomeOp.
Because of the type-safety inherent in generics, you cannot assign incompatible methods to delegates. For example, assuming the preceding program, the following statement would be in error:
SomeOp intDel = reflect; // Error!
Because reflect( ) takes a string argument and returns a string result, it cannot be assigned to an int version of SomeOp.
// Convert event example from Chapter 15 to
// use generic delegate.

using System;
// Derive a class from EventArgs.
class MyEventArgs : EventArgs {
  public int eventnum;
}

// Declare a generic delegate for an event.
delegate void MyEventHandler(T source, V args);

// Declare an event class.
class MyEvent {
  static int count = 0;

  public event MyEventHandler SomeEvent;

  // This fires SomeEvent.
  public void OnSomeEvent() {
    MyEventArgs arg = new MyEventArgs();

    if(SomeEvent != null) {
      arg.eventnum = count++;
      SomeEvent(this, arg);
    }
  }
}

class X {
  public void handler(T source, V arg) where V : MyEventArgs {
    Console.WriteLine("Event " + arg.eventnum +
                      " received by an X object.");
    Console.WriteLine("Source is " + source);
    Console.WriteLine();
  }
}

class Y {
  public void handler(T source, V arg) where V : MyEventArgs {
    Console.WriteLine("Event " + arg.eventnum +
                      " received by a Y object.");
    Console.WriteLine("Source is " + source);
    Console.WriteLine();
  }
}

class UseGenericEventDelegate {
  public static void Main() {
    X ob1 = new X();
    Y ob2 = new Y();
    MyEvent evt = new MyEvent();

    // Add handler() to the event list.
    evt.SomeEvent += ob1.handler;
    evt.SomeEvent += ob2.handler;
    // Fire the event.
    evt.OnSomeEvent();
    evt.OnSomeEvent();
  }
}
The output is shown here:
Event 0 received by an X object.
Source is MyEvent

Event 0 received by a Y object.
Source is MyEvent

Event 1 received by an X object.
Source is MyEvent

Event 1 received by a Y object.
Source is MyEvent

No comments:

Post a Comment

Archives

LocalsAdda.com-Variety In Web World

Fun Mail - Fun in the Mail