我在确保异步任务中的事件顺序时遇到问题。其他异步任务继承的类具有以下功能,并在构造函数参数中使用 EventHandlers(ExecutionProgress,ExecutionStarted,ExecutionCompleted):
public abstract Task Operation(IProgress<EventArgs> progress);
public virtual void Execute()
{
ExecuteAsync()
}
private void ReportProgress(EventArgs args)
{
if(ExecutionProgress != null) ExecutionProgress(this, args);
}
private async Task ExecuteAsync()
{
if(ExecutionStarted != null) ExecutionStarted(this, EventArgs.Empty)
await Operation(new Progress<EventArgs>(ReportProgress));
if(ExecutionCompleted != null) ExecutionCompleted(this, EventArgs.Empty)
}
现在在我的一个类中,它继承自异步任务,我使用以下内容覆盖Operation:
public override async Task Operation(IProgress<EventArgs> progress)
{
// run the synchronous function in another thread
JobResults results = await Task.Run(() => worker.DoYourJob());
progress.Report(results);
}
在尝试访问 JobResults 时,经常(但并非总是)运行此代码会在 ExecutionCompleted 事件处理程序中导致 NullReference异常。这是因为写入成员变量的 ExecutionProgress 事件通常在 ExecutionCompleted 之后因任何原因被触发。我认为标准没有说明事件排序,但我正在寻找一个很好的解决方案来确保确定性排序。 我只想在处理完所有ExecutionProgress事件后才触发ExecutionCompleted。
这里有什么好看的解决方案?在处理完所有进度报告事件之前,有没有办法等待。
答案 0 :(得分:3)
这些事件都按顺序解雇。如果您的事件处理程序是异步的,这似乎就是这种情况,那么触发事件的代码将在启动事件处理程序后立即继续执行,而不是在他们完成。
如果触发事件的代码不需要继续,直到所有处理程序都已完成,那么您需要重新构造此类,以便事件处理程序有一些方法可以在完成时向此类指示。有许多方法可以做到这一点,从允许处理程序在完成时告诉它的事件中传递参数,或者让事件处理程序的签名返回Task
而不是{{{ 1}}(在触发事件时你需要void
这些任务。)