等待事件处理程序

10

那么这里是委托和事件。

public delegate Task SomeEventHandler(SomeEventArgs e);

...


public event SomeEventHandler OnSomething;

订阅者(多个)

some.OnSomething += DoSomething;

...

public async Task DoSomething(SomeEventArgs e) {
    await SomethingElse();
    e.A = true;
}

事件调用

if (this.OnSomething != null)
    await this.OnSomething(args);

// Here args.A is false
// It should be true
问题在于即使DoSomething没有完成,最后部分仍然会继续。问题出在哪里?

问题在于即使DoSomething没有完成,最后部分仍然会继续。问题出在哪里?


2
我认为事件委托的签名不兼容CLS。按照它们的性质和通常的约定,事件应该是void委托,并且您不应该依赖它们被触发的顺序。对于这种逻辑,您最好使用自定义类。 - noseratio - open to work
4
同意;这种事件签名不是标准做法。当WinRT面临这个问题时,他们发明了"延迟"(deferrals);我建议你使用类似的模式。我在我的async events博客文章中有更多细节。 - Stephen Cleary
1个回答

12

问题在于多个SomeEventHandler实例正在运行,因此会创建多个Task值。 await调用仅在其中一个上运行,因此是否等待DoSomething方法完全取决于机会。

要解决此问题,您需要await每个创建的Task值。

if (this.OnSomething != null) {
  foreach (var d in this.OnSomething.GetInvocationList().Cast<SomeEventHandler>()) {
    await d(args);
  }
]

哈哈,就是这样。谢谢。 - Aleksandar Toplek
这应该是标准行为。也许在C# v.next中? :D - Aleksandar Toplek
1
@AleksandarToplek 这个问题可以追溯到 C# 1.0,实际上是 CLR 的一个特性而不是 C# 的一个特性。在这个时候改变它将会导致主要的向后兼容性问题。 - JaredPar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接