I just did an interesting exercise of considering a number of alternatives to firing events asynchronously. Here are the three alternatives I thought are interesting. At the end of this post I provide for some other possibilities, each with their own pros and cons.
For each version the following are assumed
public delegate void DataArrivedDelegate( object sender,
DataArrivedEventArgs e );
public event DataArrivedDelegate DataArrived;
Version 1 simply fires the event using BeginInvoke. This version has the disadvantage that the event cannot have more than one target delegate otherwise you get an exception.
public virtual void OnDataArrived( DataArrivedEventArgs e )
{
if ( DataArrived != null )
DataArrived.BeginInvoke( this, e, new AsyncCallback(
DataArrivedCompleted ), null );
}
private void DataArrivedCompleted( IAsyncResult ar )
{
if ( DataArrived != null )
DataArrived.EndInvoke( ar );
}
Version 2 uses a thread from the thread pool to fire the event. The net result is similar to version 1 except that the event can have multiple target delegates.
public virtual void OnDataArrived(DataArrivedEventArgs e )
{
if ( DataArrived != null )
System.Threading.ThreadPool.QueueUserWorkItem( new
System.Threading.WaitCallback( FireDataArrived ), e );
}
private void FireDataArrived( object e )
{
if ( DataArrived != null )
DataArrived( this, (DataArrivedEventArgs)e );
}
Version 3 enumerates the individual delegates and fires each one using BeginInvoke. This version is different in that each delegate is fired asynchronously.
public virtual void OnDataArrived( DataArrivedEventArgs e )
{
if ( DataArrived != null )
foreach( DataArrivedDelegate d in
DataArrived.GetInvocationList() )
{
if ( d != null )
d.BeginInvoke( this, e,
new AsyncCallback(DataArrivedHandlerCompleted), d );
}
}
private void DataArrivedHandlerCompleted( IAsyncResult ar )
{
DataAvailabilityEventHandler e =
(DataArrivedDelegate)ar.AsyncState;
e.EndInvoke( ar );
}
Another alternative
Each implementation could also have used custom threads, however I feel that the only benefit derived from a custom thread would be the control over the thread priority while the disadvantage of having possibly unbounded thread count could be disastrous. A solution to the unbounded thread count would be to use a custom thread pool, of which there are a number of good implementations.
There are a number of issues arising from using a non-standard event firing mechanism, so this post should be considered instructional rather than a recommended practice.