an0*_*007 3 c# events asynchronous event-handling async-await
基本上,我有一个调用事件处理程序的方法。事件处理程序调用异步方法,我需要知道该方法的结果(true 或 false)。由于事件处理程序只能返回 void,因此我创建了自己的EventArgssuccess 属性,如果运行正常,我会在该方法中将其设置为 true。
public virtual async Task<bool> TrySomething()
{
var args = new MyEventArgs();
SomeEvent?.Invoke(this, args);
return args.Success;
}
Run Code Online (Sandbox Code Playgroud)
SomeEvent连接到SomeEventHandler
private async void SomeEventHandler(object sender, MyEventArgs e)
{
e.Success = await AnAsyncMethod();
}
private asyc Task<bool> AnAsyncMethod()
{
//...
}
Run Code Online (Sandbox Code Playgroud)
我感到困惑的是,是否有任何保证该方法TrySomething将等待SomeEvent完成所以Success已经设置,然后返回它?如果没有,我怎样才能确保它能做到呢?
是否可以保证 TrySomething 方法将等待 SomeEvent 完成,以便在返回之前设置成功?
No. 的async void意思是“当我完成后不要通知呼叫者”。因此,引发事件的代码无法知道事件处理程序何时完成,除非您自己编写附加逻辑。
如果没有,我怎样才能确保它能做到呢?
嗯,这是一个更棘手的问题。.NET 事件被设计为我所说的“通知事件”——也就是说,当事件触发时,它会通知所有侦听器。不需要“等待”,因为监听者无法向通知者提供反馈。
您的代码是我所说的“命令事件”的示例- 代码是通知事件event但与通知事件的语义不匹配。您的代码需要处理程序的响应。
因此,您需要问自己的第一个问题是“我真的希望这成为一个事件吗?” 对此的一个很好的试金石是“如果有多个处理程序,我可以定义有意义的语义吗?”
更具体地说,如果多个处理程序连接到该事件,您的代码应该如何表现?也许答案是“这没有意义”。或者答案可能是“我想等待所有这些都完成,并且只有当所有这些都‘成功’时才‘成功’”。或者“等待所有人,如果其中任何一个‘成功’ ,则‘成功’”。或者“等待第一个完成并使用该结果”。或者“等待他们一次完成一个,在第一次成功时停止”。或者“等待他们一次完成一个,在第一次失败时停止”。这些是我立即想到的选择;可能还有更多。
如果答案是“这不会在我的代码中发生”或“多个处理程序没有意义”或“现在很难做出决定”,那么适当的答案是删除event. 这不是一个事件。这是一个方法调用。在设计模式术语中,events用于实现观察者模式,但您拥有的是策略模式,这就是为什么events 不适合。在这种情况下,您可以使用Gabriel 的答案或类似的答案,其中使用接口定义策略,而不是引发事件,而是调用该接口上的方法。
但是,如果拥有多个处理程序确实有意义,并且可以使用有意义的语义,那么您需要修改类型EventArgs以具有某种响应“收集器”,然后使用事件引发代码解释这些回应。确切的代码会根据您需要的语义而有所不同。
| 归档时间: |
|
| 查看次数: |
6134 次 |
| 最近记录: |