c# - 等待事件处理程序的执行

标签 c# events logging async-await

我有一个数据存储库,它为我的应用程序模型提供持久层。所有对磁盘的访问都是异步的,所以我的整个持久层都是用 async/await 编写的。我的数据存储库允许其他模块订阅数据的变化:

 public event EventHandler<Journaling.DataChangeEventArgs> DataChanged;   
 protected void OnDataChanged(Journaling.Action a)
 {
      if (DataChanged != null)
      {
           DataChanged(this, new Journaling.DataChangeEventArgs(a));
      }
 }

当我告诉存储库删除一个被其他对象引用的对象时,它也会删除这些其他对象。

 public async Task<bool> DeleteAsync(Models.BaseModel model)
 {            
      await DeleteDependentModelsAsync(model).ConfigureAwait(false);
      if (await connection.DeleteAsync(model).ConfigureAwait(false) != 1)
          return false;
      else
      {
          var deleteAction = new Journaling.DeleteAction(model);
          OnDataChanged(deleteAction);
          return true;
      }
 }

此设置在某种程度上有效,但在删除引用其他对象的对象时遇到问题。考虑这个例子:

Object X 
  Object A1: references X
  Object A2: references X
  Object A3: references X

我有一个记录器模块,用于订阅数据存储库中的更改并将它们输出到一个文件中。记录器有时需要从存储库中获取额外的数据,以使其输出可读。删除对象X时的日志应该是:

A1 deleted (parent: X, more information contained in X)
A2 deleted (parent: X, more information contained in X)
A3 deleted (parent: X, more information contained in X)
X deleted

问题是 OnDataChange 不等待事件处理程序的执行。因此,在记录器的事件处理程序被调用一次之前,数据存储库会删除 A1-A3,然后删除 X。但是事件处理程序必须获取有关 X 的一些信息,这不再可能,因为数据存储库已经删除了 X。

我不得不等待 OnDataChanged 中事件处理程序的执行。这样我就可以确保记录器在下一个对象从存储中删除之前完成其工作。

任何人都可以在正确的方向上提示我如何做到这一点吗?我考虑过使用信号量,但这会破坏数据存储库和记录器之间的松散耦合。

最佳答案

我有一个 blog post on the subject of "asynchronous events" .一般来说,我建议使用“延迟”,这是 Windows 应用商店 API 中的一个概念。

例如,使用我的 AsyncEx 库中的 DeferralManager 类型,您可以首先启用您的事件参数类型以支持延迟:

public class DataChangeEventArgs : EventArgs
{
  private readonly DeferralManager _deferrals;

  public DataChangeEventArgs(DeferralManager deferrals, Journaling.Action a)
  {
    _deferrals = deferrals;
  }

  public IDisposable GetDeferral()
  {
    return deferrals.GetDeferral();
  }
}

然后你这样提出事件:

protected Task OnDataChangedAsync(Journaling.Action a)
{
  var handler = DataChanged;
  if (handler == null)
    return Task.FromResult<object>(null); // or TaskConstants.Completed

  var deferrals = new DeferralManager();
  var args = new Journaling.DataChangeEventArgs(deferrals, a);
  handler(args);
  return deferrals.SignalAndWaitAsync();
}

如果需要使用 await,消费代码可以使用延迟:

async void DataChangedHandler(object sender, Journaling.DataChangeEventArgs args)
{
  using (args.GetDeferral())
  {
    // Code can safely await in here.
  }
}

关于c# - 等待事件处理程序的执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28751338/

相关文章:

javascript - hammer.js 和 preventDefault();

ios - 收到的事件子类型是无法识别的选择器

java: jTabbedPane 选项卡单击事件

python - Django 日志记录到哪里?

python - 如果 python 有一个预处理器,那么停用调试日志记录的成本就会低得多。还有其他选择吗?

c# - 如何在 Monodroid 中结束来电?

C# .NET 将 JPEG 图像转换为位图结构

logging - Go 运行时日志记录详细程度更改

c# - MVC - 没有带有类型 'IEnumerable<SelectListItem>' 键的 Viewdata 项目

c# - MVVM 模式中的 Viewpager