如何用async/await实现命令模式

本文关键字:实现 命令 模式 await 何用 async | 更新日期: 2023-09-27 18:22:30

我目前正在升级一些现有代码以供windows通用使用,并且正在努力转换命令模式以使用新的async/await功能。

我有一个命令调度程序类,它在自己的线程中运行,并处理添加到队列中的命令。有问题的方法看起来像这样:

private List<ICommandItem> _items;
private void ProcessCommands()
{
    while(_items.count > 0)
    {
        _items[0].Execute();
        _items.RemoveAt(0);
    }
}

我的问题是,我的一些ICommandItem.Execute()方法现在需要异步,因为它们涉及文件io,而其他方法没有异步方法。我如何修改上面的模式以便:

  1. 我的执行器可以处理异步和非异步ICommandItems
  2. 执行器只有在上一个命令完成后才开始执行该命令

我很乐意同步执行这些方法,但现在这会导致到处出现死锁。

如何用async/await实现命令模式

我的问题是,我的一些ICommandItem.Execute()方法现在需要异步,因为它们涉及文件io,而其他方法没有异步方法。

从技术上讲,异步(Task-返回)签名只意味着实现可能是异步的。因此,虽然您可以引入一个单独的异步接口,但另一种方法是将现有接口更改为Task-返回:

interface ICommandItem
{
  Task ExecuteAsync(); // Used to be "void Execute();"
}

您的同步实现必须更改才能返回Task:

Task ICommandItem.ExecuteAsync()
{
  // Do synchronous work.
  return Task.CompletedTask; // If you're not on 4.6 yet, you can use "Task.FromResult(0)"
}

异步实现很简单:

async Task ICommandItem.ExecuteAsync()
{
  await ...; // Do asynchronous work.
}

您的"跑步者"只需使用await:

private async Task ProcessCommandsAsync()
{
  while(_items.count > 0)
  {
    await _items[0].ExecuteAsync();
    _items.RemoveAt(0);
  }
}

您可以提供第二个接口,IAsyncCommandItem:

public interface IAsyncCommandItem : ICommandItem
{
}

在while循环中,检查项目是否实现了此接口,并对其进行处理:

private async void ProcessCommands()
{
    while(_items.count > 0)
    {
        var command = _items[0] as IAsyncCommandItem;
        if (command != null)
        {
            await command.Execute();
        }
        else
        {
            _items[0].Execute();
        }
        _items.RemoveAt(0);
    }
}

当然,这是假设您可以自由地修改特定的命令类来实现新接口。