这些扩展方法可以异步地调用事件。它们的灵感来自于这个StackOverflow答案。
public static void InvokeAsync<TEventArgs>(this EventHandler<TEventArgs> someEvent, object sender, TEventArgs args)
where TEventArgs : EventArgs
{
if (someEvent == null)
{
return;
}
var eventListeners = someEvent.GetInvocationList();
AsyncCallback endAsyncCallback = delegate(IAsyncResult iar)
{
var ar = iar as AsyncResult;
if (ar == null)
{
return;
}
var invokedMethod = ar.AsyncDelegate as EventHandler<TEventArgs>;
if (invokedMethod != null)
{
invokedMethod.EndInvoke(iar);
}
};
foreach (EventHandler<TEventArgs> methodToInvoke in eventListeners)
{
methodToInvoke.BeginInvoke(sender, args, endAsyncCallback, null);
}
}
public static void InvokeAsync(this EventHandler someEvent, object sender, EventArgs args)
{
if (someEvent == null)
{
return;
}
var eventListeners = someEvent.GetInvocationList();
AsyncCallback endAsyncCallback = delegate(IAsyncResult iar)
{
var ar = iar as AsyncResult;
if (ar == null)
{
return;
}
var invokedMethod = ar.AsyncDelegate as EventHandler;
if (invokedMethod != null)
{
invokedMethod.EndInvoke(iar);
}
};
foreach (EventHandler methodToInvoke in eventListeners)
{
methodToInvoke.BeginInvoke(sender, args, endAsyncCallback, null);
}
}
使用方法:
public class Foo
{
public event EventHandler<EventArgs> Bar;
public void OnBar()
{
Bar.InvokeAsync(this, EventArgs.Empty);
}
}
注意到一个额外的好处,您在调用事件之前不必检查事件是否为空。例如:
EventHandler<EventArgs> handler = Bar;
if (handler != null)
{
// Invoke the event
}
测试方法:
void Main()
{
EventHandler<EventArgs> handler1 =
delegate(object sender, EventArgs args)
{
Thread.Sleep(100);
Console.WriteLine("Handled 1");
};
EventHandler<EventArgs> handler2 =
delegate(object sender, EventArgs args)
{
Thread.Sleep(50);
Console.WriteLine("Handled 2");
};
EventHandler<EventArgs> handler3 =
delegate(object sender, EventArgs args)
{
Thread.Sleep(25);
Console.WriteLine("Handled 3");
};
var foo = new Foo();
foo.Bar += handler1;
foo.Bar += handler2;
foo.Bar += handler3;
foo.OnBar();
Console.WriteLine("Start executing important stuff");
Thread.Sleep(1000);
Console.WriteLine("Finished executing important stuff");
}
调用事件通常会产生以下输出:
开始执行重要的事情
已处理3个
已处理2个
已处理1个
完成执行重要的事情
如果同步调用事件,它将始终产生此输出,并延迟执行“重要”任务:
已处理1个
已处理2个
已处理3个
开始执行重要的事情
完成执行重要的事情