Improving .NET Events
by Richard Grimes

Listing One

public class Test
{
   // Tell the compiler to generate a delegate class
   delegate void OneParam(int x);
   void Proc(int x)
   {/* code */}
   public void InvokeCode()
   {
      // Create a delegate object and initialize with a method pointer
      OneParam d = new OneParam(Proc);
      // Invoke the delegate
      d(42);
   }
}


Listing  Two

public class Test
{
   // Indicate that the class can generate the event
   public event EventHandler SomethingHappened;
   public void DoSomething()
   {
      // Code here...
      // Now raise the event
      if (SomethingHappened != null)
         SomethingHappened(this, new EventArgs());
   }
}
public class UseCode
{
   void InformMe(object sender, EventArgs args)
   { /* handle event */ }
   public void UseTestObject()
   {
      Test t = new Test();
      t.SomethingHappened += new EventHandler(InformMe);
      t.DoSomething();
   }
}


Listing Three

public class Test
{
   EventHandlerList events = new EventHandlerList();
   // This is the 'key' object for our event
   static object EventSomethingHappened;
   static Test()
   {
      EventSomethingHappened = new object();
   }
   // Declare the event and the custom event methods
   public event EventHandler SomethingHappened
   {
      add
      {
         events.AddHandler(
            EventSomethingHappened, value);
      }
      remove
      {
         events.RemoveHandler(
            EventSomethingHappened, value);
      }
   }
   // Helper method to get the event delegate and
   // invoke it
   protected void RaiseSomethingHappened(EventArgs args)
   {
      EventHandler d;
      d = (EventHandler)events[EventSomethingHappened];
      d(this, args);
   }
   public void DoSomething()
   {
      // Code...
      RaiseSomethingHappened(new EventArgs());
   }
}


Listing Four 

protected void RaiseSomethingHappened(EventArgs args)
{
   EventHandler d ;
   d = (EventHandler)events[EventSomethingHappened];
   Delegate[] dels = d.GetInvocationList();
   // Invoke each delegate individually
   foreach(Delegate del in dels)
   {
      EventHandler eh = del as EventHandler;
      try
      {
         eh(this, args);
      }
      catch(Exception){}
   }
}


Listing Five

class MultiException : Exception
{
   // Helper class to hold info about the exception
   public struct ExceptionData
   {
      public Exception theException;
      public Delegate theDelegate;
      public ExceptionData(Exception e, Delegate d)
      {
         theException = e;
         theDelegate = d;
      }
   }
   // Field used to collate exception data
   ArrayList exceptions = new ArrayList();

   public MultiException(string str) : base(str) {}
   public void Add(Exception e, Delegate d)
   {
      exceptions.Add(new ExceptionData(e, d));
   }
   public bool HasExceptions
   {
      get {return (exceptions.Count != 0);}
   }
   public ExceptionData[] Exceptions
   {
      get
      {
         return (ExceptionData[])exceptions.ToArray(
            typeof(ExceptionData));
      }
   }
   // Return information about all the exceptions
   public override string ToString()
   {
      if (exceptions == null) return base.ToString();
      StringBuilder sb = new StringBuilder();
      sb.Append(base.ToString());
      sb.Append(Environment.NewLine);

      for (int idx = 0; idx < exceptions.Count; idx++)
      {
         ExceptionData ed;
         ed = (ExceptionData)exceptions[idx];
         sb.Append(String.Format(
            "{0} on {1} threw an exception:", 
            ed.theDelegate.Method.Name,
            ed.theDelegate.Target.GetType()));
         sb.Append(Environment.NewLine);
         sb.Append(ed.theException.ToString());
         sb.Append(Environment.NewLine);
      }
      return sb.ToString();
   }
}


Listing Six

protected void RaiseSomethingHappened(EventArgs args)
{
   MultiException exceptions = new MultiException(
      "delegate(s) thrown exceptions");
   EventHandler d;
   d = (EventHandler)events[EventSomethingHappened];
   Delegate[] dels = d.GetInvocationList();
   foreach(Delegate del in dels)
   {
      EventHandler eh = del as EventHandler;
      try
      {
         eh(this, args);
      }
      catch(Exception e)
      {
         exceptions.Add(e, eh);
      }
   }
   if (exceptions.HasExceptions)
      throw exceptions;
}


Listing Seven

try
{
   RaiseSomethingHappened(new EventArgs());
}
catch (MultiException me)
{
   Console.WriteLine("\n{0}", me.ToString());
   foreach(MultiException.ExceptionData ed 
              in me.Exceptions)
   {
      this.SomethingHappened -=
        (EventHandler)ed.theDelegate;
   }
}





1


