以正确的顺序从 async/await 函数触发事件

Triggering events from async/await functions in the right order

我无法确保异步任务中的事件顺序。其他异步任务继承的 class 具有以下功能,并在构造函数参数中采用 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)

}

现在,在我的一个 class 继承自异步任务的系统中,我使用以下内容覆盖 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);
}

运行 此代码经常(但并非总是)在 ExecutionCompleted 事件处理程序中导致 NullReference Exception访问 JobResults。这是因为写入成员变量的 ExecutionProgress 事件通常会在 ExecutionCompleted 之后被触发,无论出于何种原因。我认为该标准对事件排序没有任何说明,但我正在寻找一个很好的解决方案来确保此处的确定性排序。 我只想在处理完所有 ExecutionProgress 事件后才触发 ExecutionCompleted。

这里有什么好看的解决方案?有什么方法可以等待直到处理完所有进度报告事件。

事件全部触发。如果您的事件 处理程序 是异步的,这似乎是这种情况,那么触发事件的代码将在 开始 后立即继续执行事件处理程序,而不是在它们 完成.

如果触发事件的代码需要在所有处理程序完成后才能继续,那么您需要重组此 class 以便事件处理程序可以通过某种方式指示此 class 完成后。有很多方法可以做到这一点,从在事件中传递一个参数,允许处理程序在完成时告诉它,或者让事件处理程序的签名 return Task 而不是而不是void(触发事件时你需要await那些任务)。