在我的代码中,有很多地方我需要等到事件发生后再继续。任务(与await
结合使用)对此非常理想,因此我认为我会为EventHandler<T>
制作一种可以简化此类情况的扩展方法。
我需要像这样的伪代码:
event EventHandler<int> AllFinished;
async Task<int> DoThings()
{
InitiateAnAction();
var n = await /* wait for AllFinished to fire */;
return n;
}
我的第一个想法是,我实施了从EventHandler
到Task
的明确演员,但我发现operators cannot be overloaded with extension methods。如果它有效,它将看起来像这样:
var n = await (Task)AllFinished;
我的第二次尝试是使用普通的扩展方法。这是我使用的代码:
public static Task<(object sender, T args)> Once<T>(this EventHandler<T> e)
{
var tcs = new TaskCompletionSource<(object, T)>();
EventHandler<T> d = null;
d = delegate (object sender, T args)
{
tcs.SetResult( (sender, args) );
e -= d;
};
e += d;
return tcs.Task;
}
但是我发现了events can't be passed as arguments,因此e += d
和e -= d
没有做任何事情(他们甚至没有发出错误)。如果它有效,它就会像这样使用:
var (sender, number) = await AllFinished.Once();
有没有优雅的等待事件的方式?我之前的两次尝试中,我更喜欢单线:
var n = await (Task)AllFinished;
var (sender, number) = await AllFinished.Once();
如果可能,请避免将事件的名称作为字符串传递。这种方法使得无法使用IntelliSense重命名功能,当我忘记它时可能会破坏我的代码。
如果您认为等待方法中的事件是设计不良的结果,您可以深入我的original Cef-related question并在那里发布更好的解决方案。