简体   繁体   English

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

[英]How to implement Command Pattern with async/await

i'm currently upgrading some existing code for use by windows universal and am struggling to convert a command pattern to work with the new async/await functionality. 我目前正在升级一些现有的代码供windows universal使用,我正在努力转换命令模式以使用新的async / await功能。

I have a command scheduler class that runs within its own thread and processes commands that have been added to its queue. 我有一个命令调度程序类,它在自己的线程中运行并处理已添加到其队列中的命令。 The method in question looks like this: 有问题的方法如下:

private List<ICommandItem> _items;

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

My problem is that some of my ICommandItem.Execute() methods now need to be async because they involve file io whilst others have no async methods. 我的问题是我的一些ICommandItem.Execute()方法现在需要异步,因为它们涉及文件io而其他人没有异步方法。 How could I modify the above pattern so that: 我怎么能修改上面的模式,以便:

  1. my executor can handle both async and non-async ICommandItems 我的执行程序可以处理异步和非异步ICommandItems
  2. The executor only starts execution of a command once the previous command has completed. 执行程序仅在前一个命令完成后才开始执行命令。

I would be happy to just execute the methods synchronously but that now causes deadlocks everywhere. 我很乐意同步执行这些方法但现在到处都会导致死锁。

My problem is that some of my ICommandItem.Execute() methods now need to be async because they involve file io whilst others have no async methods. 我的问题是我的一些ICommandItem.Execute()方法现在需要异步,因为它们涉及文件io而其他人没有异步方法。

Technically, an asynchronous ( Task -returning) signature only means that the implementation may be asynchronous. 从技术上讲,异步( Task -returning)签名仅表示实现可能是异步的。 So, while you can introduce a separate asynchronous interface, another approach is to change the existing interface to be Task -returning: 因此,虽然您可以引入单独的异步接口,但另一种方法是将现有接口更改为Task -returning:

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

Your synchronous implementations will have to change to return a Task : 您的同步实现必须更改以返回Task

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

While asynchronous implementations are straightforward: 虽然异步实现很简单:

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

And your "runner" can just use await : 你的“跑步者”可以使用await

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

You could provide a second interface, IAsyncCommandItem: 您可以提供第二个接口IAsyncCommandItem:

public interface IAsyncCommandItem : ICommandItem
{
}

In your while loop, check to see if the item implements this interface, and handle it: 在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);
    }
}

This assumes, of course, that you have the freedom to modify specific command classes to implement the new interface. 当然,这假设您可以自由地修改特定的命令类来实现新接口。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM