提问者:小点点

如何实现返回TaskT>的接口方法?


我有一个接口

interface IFoo
{
  Task<Bar> CreateBarAsync();
}

创建有两种方法,一种是异步的,一种是同步的。我想为这两个方法中的每一个提供一个接口实现。

对于异步方法,其实现可能如下所示:

class Foo1 : IFoo
{
  async Task<Bar> CreateBarAsync()
  {
    return await AsynchronousBarCreatorAsync();
  }
}

但是我应该如何实现使用同步方法创建的类呢?

我可以实现方法以同步运行:

  async Task<Bar> CreateBarAsync()
  {
    return SynchronousBarCreator();
  }

然后,编译器将警告不要在方法签名中使用:

此异步方法缺少'await'运算符,将同步运行。考虑使用'await'运算符等待非阻塞API调用,或'await task.run(...)'在后台线程上执行与CPU绑定的工作。

或者,我可以实现显式返回的方法。在我看来,这样代码的可读性就会降低:

  Task<Bar> CreateBarAsync()
  {
    return Task.Run(() => SynchronousBarCreator());
  }

从性能的角度来看,我认为这两种方法的开销差不多,或者?

我应该选择哪种方法;同步实现方法,还是显式地将同步方法调用包装在中?

编辑

我正在从事的项目实际上是一个。NET4项目,带有来自Microsoft async NuGet包的async/await扩展。在.NET4上,可以将替换为。我有意识地在上面的示例中使用了.NET4.5方法,希望能使首要问题更加清晰。


共3个答案

匿名用户

当您必须从接口实现异步方法并且您的实现是同步的时,您可以使用Ned's解决方案:

public Task<Bar> CreateBarAsync()
{
    return Task.FromResult<Bar>(SynchronousBarCreator());
}

使用此解决方案,方法看起来是异步的,但实际上是同步的。

或您提出的解决方案:

  Task<Bar> CreateBarAsync()
  {
    return Task.Run(() => SynchronousBarCreator());
  }

这样方法才是真正的异步方法。

您没有一个通用的解决方案来匹配“如何实现返回任务的接口方法”的所有情况。这取决于上下文:您的实现是否足够快,以至于在另一个线程上调用它是毫无用处的?如何使用这个接口?何时调用这个方法(它会冻结应用程序吗?甚至有可能在另一个线程中调用您的实现吗?

匿名用户

请尝试以下操作:

class Foo2 : IFoo
{
    public Task<Bar> CreateBarAsync()
    {
        return Task.FromResult<Bar>(SynchronousBarCreator());
    }
}

使用提供的值创建指定类型的已经完成的任务。

匿名用户

如果您使用的是.NET4.0,则可以使用:

Task<Bar> CreateBarAsync()
{
    var tcs = new TaskCompletionSource<Bar>();
    tcs.SetResult(SynchronousBarCreator());
    return tcs.Task
}

最后,如果您的方法没有任何异步性,您应该考虑公开一个同步端点(codeCreatebar/code>),它将创建一个新的。这样就不会有什么意外,也不需要用冗余的包装。