基础架构-同步和异步接口及实现?

时间:2019-04-24 09:11:43

标签: c# asynchronous async-await code-duplication

在实现库/基础结构时,该API的用户希望同步和异步使用代码,我读到混合同步和异步不是一个好主意(例如,同步实现包括等待异步实施)。

因此,显然,同步与异步实现应该分开。

是否有一种优雅的方法来避免代码(或更准确地说是“流”)在同步和异步实现中的重复,这显然会涉及到整个调用层次结构?

interface IMyInterface 
{
    void Foo();
    Task FooAsync();
}

class MyImplementation1 : IMyInterface
{
    public void Foo()
    {
        OtherMethod1();
        OtherMethod2();
        OtherMethod3();
        OtherMethod4();
    }

    public async Task FooAsync()
    {
        await OtherMethod1Async();
        await OtherMethod2Async();
        await OtherMethod3Async();
        await OtherMethod4Async();
    }

    private void OtherMethod1() { /* may contain other sync calls */ }
    private void OtherMethod2() { /* may contain other sync calls */ }
    private void OtherMethod3() { /* may contain other sync calls */ }
    private void OtherMethod4() { /* may contain other sync calls */ }  

    private async Task OtherMethod1Async() { /* may contain other async calls */ }
    private async Task OtherMethod2Async() { /* may contain other async calls */ }
    private async Task OtherMethod3Async() { /* may contain other async calls */ }
    private async Task OtherMethod4Async() { /* may contain other async calls */ }      
}

2 个答案:

答案 0 :(得分:1)

根据您的逻辑,您仍然可以共享一些逻辑。但是在不同之处,应该有所不同。

如果有帮助,您可以使用模板系统(例如T4)来生成代码。

答案 1 :(得分:1)

  

在实现库/基础结构时,该API的用户希望同时使用异步代码

理想情况下,库中的每个API应该自然同步或自然异步。我建议仅公开最自然的API。也就是说,如果您的库需要执行I / O,则可以选择仅公开异步API。

  

是否有一种优雅的方法来避免代码(或更准确地说是“流”)在同步和异步实现中的重复,这显然会涉及到整个调用层次结构?

我还没有找到理想的解决方案。我最接近的是boolean argument hack,在这里,您将异步API和同步API都转发给采用bool sync参数的内部方法。此内部方法具有异步签名(返回Task / Task<T>),但是如果synctrue,则它将始终返回已完成的任务。

最终看起来像这样:

interface IMyInterface 
{
  void Foo();
  Task FooAsync();
}

class MyImplementation1 : IMyInterface
{
  public void Foo() => Foo(sync: true).GetAwaiter().GetResult();
  public Task FooAsync() => Foo(sync: false);

  private async Task Foo(bool sync)
  {
    // Pass `sync` along to all methods that can be sync or async.
    await OtherMethod1(sync);
    await OtherMethod2(sync);
    await OtherMethod3(sync);
    await OtherMethod4(sync);
  }

  private async Task OtherMethod1(bool sync)
  {
    // When you have to choose sync/async APIs of other classes, then choose based on `sync`.
    if (sync)
      Thread.Sleep(1000); // synchronous placeholder
    else
      await Task.Delay(1000); // asynchronous placeholder
  }
}