© 2004 Microsoft Corporation. All rights reserved.

Figure 2 .NET Delegate Classes
[serializable, ClassInterface(ClassInterfaceType.AutoDual)]
public abstract class Delegate : System.Object, ICloneable, ISerializable
{
   protected Delegate(Type target, string method);
   protected Delegate(object target, string method);
   public MethodInfo Method {get;}
   public object Target {get;}
   public virtual object Clone();
   public static Delegate Combine(Delegate[] delegates);
   public static Delegate Combine(Delegate a, Delegate b);
   protected virtual Delegate CombineImpl(Delegate d);
   public static Delegate CreateDelegate(Type type, MethodInfo method);
   public static Delegate CreateDelegate(
      Type type, Type target, string method);
   public static Delegate CreateDelegate(
      Type type, object target, string method);
   public object DynamicInvoke(object[] args);
   protected virtual object DynamicInvokeImpl(object[] args);
   public override bool Equals(object obj);
   public override int GetHashCode();
   public virtual Delegate[] GetInvocationList();
   protected virtual MethodInfo GetMethodImpl();
   public virtual void GetObjectData(
      SerializationInfo info, StreamingContext context);
   public static Delegate Remove(Delegate source, Delegate value);
   protected virtual Delegate RemoveImpl(Delegate d);
   public static bool operator ==(Delegate d1, Delegate d2);
   public static bool operator !=(Delegate d1, Delegate d2);
}

[serializable]
public abstract class MulticastDelegate : Delegate
{
   protected MulticastDelegate(Type target, string method);
   protected MulticastDelegate(object target, string method);
   protected override Delegate CombineImpl(Delegate follow);
   protected override object DynamicInvokeImpl(object[] args);
   public override bool Equals(object obj);
   public override Delegate[] GetInvocationList();
   protected override Delegate RemoveImpl(Delegate value);
   public static new bool operator ==(
      MulticastDelegate d1, MulticastDelegate d2);
   public static new bool operator !=(
      MulticastDelegate d1, MulticastDelegate d2);
}
Figure 3 Delegate Class Generated by the C# Compiler
public sealed class StringDelegate : System.MulticastDelegate
{
   public StringDelegate (object obj, int method);
   public virtual int Invoke(string str);
   public virtual IAsyncResult BeginInvoke(string str, 
      AsyncCallback asc, object stateObject);
   public virtual int EndInvoke(IAsyncResult result);
}
Figure 4 Delegate Referencing Private Method
class MyOtherCRT
{
   private int strlen(string s)
   {return s.Length;}
   public StringDelegate GetDel()
   {
      return new StringDelegate (strlen);
   }
}

MyOtherCRT b = new MyOtherCRT();
StringDelegate d = b.GetDel();
int i = d(".NET delegates");
Figure 5 CThreadClass
public class CThreadClass
{
   public void StartBigCalc()
   {
      Thread t = new Thread(new ThreadStart(DoBigCalc));
      t.Start();
   }
   public void DoBigCalc()
   {
      // do the calculation here
   }
}
Figure 6 Using a Separate Object to Pass Data
public class CWorker
{
   private int m_i;
   public CWorker(int i){m_i = i;}
   public void DoBigCalc()
   {
      // do the calculation here using m_i
   }
}

public class CThreadClass2
{
   public void StartBigCalc(int i)
   {
      CWorker w = new CWorker(i);
      Thread t = new Thread(new ThreadStart(w.DoBigCalc));
      t.Start();
   }
}
Figure 7 Returning Data via a Delegate Call
public delegate void InformMe(int i);

public class CWorker2
{
   private int m_i;
   private InformMe d;
   public CWorker2(int i, InformMe dd)
   {m_i = i; d = dd;}
   public void DoBigCalc()
   {
      d(CalcReturnVal(m_i));
   }
   protected int CalcReturnVal(int i);
}

public class CDoAsync3
{
   public void StartBigCalc(int i, InformMe d)
   {
      CWorker2 w = new CWorker2(i, d);
      Thread t = new Thread(new ThreadStart(w.DoBigCalc));
      t.Start();
   }
}
Figure 8 Calling a Method on a Thread
public class CCalling
{
   private int m_i;
   public void GiveMeAResult(int i)
   {
      m_i = i;
   }
   public int DoCalc(int i)
   {
      CDoAsync3 a = new CDoAsync3();
      a.StartBigCalc(i, new InformMe(this.GiveMeAResult));
      Thread.Sleep(1000); // hack
      return m_i;
   }
}
Figure 9 AsyncResult Object
public class AsyncResult : System.Object, IAsyncResult, IMessageSink
{
   internal AsyncResult(Message m);
   public virtual void SetMessageCtrl(IMessageCtrl mc);
   public virtual IMessage GetReplyMessage();
   public virtual object AsyncDelegate {get;}
   public bool EndInvokeCalled {get; set;}
   // IAsyncResult
   public virtual bool IsCompleted {get;}
   public virtual bool CompletedSynchronously {get;}
   public virtual object AsyncState {get;}
   public virtual WaitHandle AsyncWaitHandle {get;}
   // IMessageSink
   public virtual IMessageSink NextSink {get;}
   public virtual IMessageCtrl AsyncProcessMessage(
      IMessage msg, IMessageSink replySink);
   public virtual IMessage SyncProcessMessage(IMessage msg);
}
Figure 11 Calling a Method Asynchronously

Polling for Completion
StringDelegate d = new StringDelegate (A.strlen);
IAsyncResult ar;
ar = d.BeginInvoke("Hello", null, null);
while(!ar.IsCompleted)
{
   // do work
}
int i = d.EndInvoke(ar);
// use result
Waiting for Completion
StringDelegate d = new StringDelegate (A.strlen);
IAsyncResult ar;
ar = d.BeginInvoke("Hello", null, null);
// do work
ar.AsyncWaitHandle.WaitOne();
int i = d.EndInvoke(ar);
// use result
Figure 12 Calling a Delegate and Providing a Callback
public class CCaller
{
   private void CallMe(IAsyncResult ar)
   {
      StringDelegate d 
         = (StringDelegate)((AsyncResult)ar).AsyncDelegate;
      int i = d.EndInvoke(ar);
      // use result
   }
   public void DoCall()
   {
      StringDelegate d = new StringDelegate (A.strlen);
      d.BeginInvoke("Hello", new AsyncCallback(CallMe), null);
   }
}
Figure 13 Delegates with Ref or Out Parameters
class CAsyncCalls
{
   public delegate void times2(ref int i);
   public void p(ref int i)
   {
      i *= 2;
   }
   public void run()
   {
      times2 d = new times2(p);
      int i = 42;

      IAsyncResult ar;
      ar = d.BeginInvoke(ref i, null, null);
      ar.AsyncWaitHandle.WaitOne();
      Console.WriteLine("before EndInvoke {0}", i);
      d.EndInvoke(ref i, ar);
      Console.WriteLine("after EndInvoke {0}", i);
   }
}
Figure 14 Returning Data Through an In Parameter
class App
{
   delegate void GetData(byte[] b);
   static void GetBuf(byte[] b)
   {
      for (byte x = 0; x < b.Length; x++)
         b[x] = (byte)(x*x);
   }
   static void Main()
   {
      GetData d = new GetData(App.GetBuf);
      byte[] b = new byte[10];
      IAsyncResult ar;
      ar = d.BeginInvoke(b, null, null);
      ar.AsyncWaitHandle.WaitOne();
      for (int x = 0; x < b.Length; x++)
         Console.Write("{0} ", b[x]);
   }
}
Figure 15 Accessing an HTTP Server Asynchronously
void DumpPage(string host, string page)
{
      TcpClient c = new TcpClient(host, http);
      String str= "GET " + page + " HTTP/1.0\n\n";
      byte[] req = new byte[str.Length + 1];
      // convert request to bytes
      Encoding.ASCII.GetBytes(str, 0, str.Length, req, 0);

      NetworkStream s = (NetworkStream)c.GetStream();
      // make the request for the page
      s.Write(req, 0, req.Length);
      // ask for the data in 1000 byte chunks
      byte[] buf = new byte[1000];
      while (s.DataAvailable)
      {
         IAsyncResult asr;
         asr = s.BeginRead(buf, 0, buf.Length, null, null);
         // do some other work here...
         asr.AsyncWaitHandle.WaitOne();

         // get the results, read how many bytes were obtained
         int count = s.EndRead(asr);
         char[] ch = new char[count];
         Encoding.ASCII.GetChars(buf, 0, count, ch, 0);
         String resp = new String(ch);
         Console.Write(resp);
      }
}