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

时间:2015-11-18 16:06:03

标签: c# multithreading asynchronous async-await .net-4.5

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

我有一个命令调度程序类,它在自己的线程中运行并处理已添加到其队列中的命令。有问题的方法如下:

security:
    encoders:
        FOS\UserBundle\Model\UserInterface: sha512

role_hierarchy:
    ROlE_Client:      ROLE_Client
    ROlE_Agent:       ROLE_Agent
    ROLE_SUPER_ADMIN: ROLE_SUPER_ADMIN

providers:
    fos_userbundle:
        id: fos_user.user_provider.username

firewalls:
    main:
        pattern: ^/
        form_login:
            provider: fos_userbundle
            csrf_provider: form.csrf_provider
            #always_use_default_target_path: false
            #default_target_path:            /affichage
        logout:       true
        anonymous:    true

access_control:
    - { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/admin/, role: ROLE_ADMIN }
    - { path: ^/affichage, role: ROLE_Agent }

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

  1. 我的执行者可以处理异步和非异步ICommandItems
  2. 执行程序仅在上一个命令完成后才开始执行命令。
  3. 我很乐意同步执行这些方法但现在到处都会造成死锁。

2 个答案:

答案 0 :(得分:6)

  

我的问题是我的一些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);
  }
}

答案 1 :(得分: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);
    }
}

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