【问题标题】:What is the best way to return completed Task?返回已完成任务的最佳方式是什么?
【发布时间】:2020-02-26 06:30:19
【问题描述】:

返回已完成的Task 对象的最佳方式是什么?

可以写成Task.Delay(0) 或Task.FromResult<bool>(true) 等等。

但是最有效的方法是什么?

【问题讨论】:

  • 这是什么原因?为此,您不需要任务。只需调用该方法。
  • @I4V 有时操作需要工作但有时不需要并且可以在不需要异步的情况下有效完成是一种常见的做法
  • 这是一篇关于边缘情况的好文章:blog.stephencleary.com/2016/12/eliding-async-await.html。 tl;dr 可以留下警告,因为这种方法可以避免很多删除 async 关键字的陷阱。
  • "attempt to use return Task.FromResult(mockToken); 给出:错误 CS4016" - 这就是为什么你在返回时不使用 async 方法一个任务对象。
  • 您的问题存在缺陷。您说“当接口需要异步任务 时”,但接口永远不能需要async。只能要求返回值为Task<T>。

标签: c# .net task-parallel-library .net-4.5 c#-5.0


【解决方案1】:

Stephen Toub (MSFT) 的回答:

如果每次都想要一个新的Task对象,Task.FromResult是最 高效的。 Task.Delay(0) 在其当前实现中将返回一个 缓存的任务,但这是一个实现细节。如果你想使用 一个缓存的任务,你应该自己缓存一个,例如私有静态 只读任务 s_completedTask = Task.FromResult(true);然后使用 s_completedTask。

【讨论】:

  • Andrii,你能给你 Toub 的声明引用的链接吗?从您的报价中搜索词组时,Google 不会返回任何结果
  • 我直接问他并在这里发布答案,因为我认为这很重要
【解决方案2】:

Task.FromResult 将是最直接的。它还包括一些常见整数等的内置结果。但是,如果您的值不是“显而易见的”值(并且不会有内置处理)但很可能在您的场景中经常返回 - 那么您可以创建自己的将结果缓存在一个字段中(如果合适,可能是静态的) - 但缓存任务很重要,而不是结果本身。l - 否则每次只需使用 Task.FromResult。

【讨论】:

    【解决方案3】:

    这是一个小演示,它显示了标记和未标记异步的方法之间的异常处理差异。

    public Task<string> GetToken1WithoutAsync() => throw new Exception("Ex1!");
    
    // Warning: This async method lacks 'await' operators and will run synchronously. Consider ...
    public async Task<string> GetToken2WithAsync() => throw new Exception("Ex2!");  
    
    public string GetToken3Throws() => throw new Exception("Ex3!");
    public async Task<string> GetToken3WithAsync() => await Task.Run(GetToken3Throws);
    
    public async Task<string> GetToken4WithAsync() { throw new Exception("Ex4!"); return await Task.FromResult("X");} 
    
    
    public static async Task Main(string[] args)
    {
        var p = new Program();
    
        try { var task1 = p.GetToken1WithoutAsync(); } 
        catch( Exception ) { Console.WriteLine("Throws before await.");};
    
        var task2 = p.GetToken2WithAsync(); // Does not throw;
        try { var token2 = await task2; } 
        catch( Exception ) { Console.WriteLine("Throws on await.");};
    
        var task3 = p.GetToken3WithAsync(); // Does not throw;
        try { var token3 = await task3; } 
        catch( Exception ) { Console.WriteLine("Throws on await.");};
    
        var task4 = p.GetToken4WithAsync(); // Does not throw;
        try { var token4 = await task4; } 
        catch( Exception ) { Console.WriteLine("Throws on await.");};
    }
    
    // .NETCoreApp,Version=v3.0
    Throws before await.
    Throws on await.
    Throws on await.
    Throws on await.
    

    已从 When async Task<T> required by interface, how to get return variable without compiler warning 移动(和编辑)

    【讨论】:

    • 除非在Guid.NewGuid().ToString() 抛出的情况下会改变GetToken() 的行为。
    • Guid.NewGuid().ToString() 不抛出。
    • 即使它确实抛出了,我认为这并不重要:确切的异常行为会有所不同,但不会以任何实质性方式。无论哪种情况,调用者都会看到异常;在上面的示例中,它将在对GetToken() 的调用上,而如果方法保留为async,它将在await 上。坦率地说,前者更好;快速失败。
    • 我只是指出,在某些情况下,此建议不会产生完全相同的行为。了解 GetToken() 是否可以同步抛出异常,或者总是返回 Task 是用户从这个答案推断的一个重要考虑因素。
    • @PatrickRoberts 这是一个公平且重要的观点。我添加了一个小演示来展示您提出的问题;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-18
    • 1970-01-01
    • 2018-03-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多