【问题标题】:await Task.CompletedTask for what?等待 Task.CompletedTask 是为了什么?
【发布时间】:2017-10-21 03:08:18
【问题描述】:

我使用在 Build2017 中介绍的 Windows Template Studio 创建了 UWP 应用。

下面的类是它生成的代码的一部分。

public class SampleModelService
{
    public async Task<IEnumerable<SampleModel>> GetDataAsync()
    {
        await Task.CompletedTask; // <-- what is this for?
        var data = new List<SampleModel>();

        data.Add(new SampleModel
        {
            Title = "Lorem ipsum dolor sit 1",
            Description = "Lorem ipsum dolor sit amet",
            Symbol = Symbol.Globe
        });

        data.Add(new SampleModel
        {
            Title = "Lorem ipsum dolor sit 2",
            Description = "Lorem ipsum dolor sit amet",
            Symbol = Symbol.MusicInfo
        });
        return data;
    }
}

我的问题是,这里的await Task.CompletedTask; 代码的目的和原因是什么?它实际上没有来自它的Task 结果接收器。

【问题讨论】:

    标签: c# uwp async-await task windows-10-universal


    【解决方案1】:

    它可以让后期更容易实现异步代码调用,而无需更改签名,从而避免重构调用代码。

    虽然脚手架示例代码是同步的,但 Template Studio 是专门围绕 async 数据访问层设计的,您应该通过修改生成的方法的主体来实现自己的数据访问。

    如果 async 实现实现,整个模板化应用程序中的代码都会发生重大变化,对于新开发人员来说,这将是一个非常陡峭的学习曲线,重点是模板的核心是用最少的努力甚至经验来启动和运行!

    另一种选择是从方法签名和该行中删除 async 关键字并执行

    return Task.FromResult<IEnumerable<SampleModel>>(data); 
    

    当你需要返回一个等待的任务时,你会看到这个构造,例如,当实现没有异步工作要做时。

    然而,在这种情况下,由于它是一个模板,他们希望人们将await Task.Completed 替换为await FetchDataFromDatabaseAsync(); 之类的东西。由于async 关键字已经存在,它最大限度地减少了实现您自己的异步调用所需的更改。

    无论如何,如果没有这个 await 构造,你可以这样做:

    public class SampleModelService
    {
        public Task<IEnumerable<SampleModel>> GetDataAsync()
        {
            var data = new List<SampleModel>();
    
            data.Add(new SampleModel
            {
                Title = "Lorem ipsum dolor sit 1",
                Description = "Lorem ipsum dolor sit amet",
                Symbol = Symbol.Globe
            });
    
            data.Add(new SampleModel
            {
                Title = "Lorem ipsum dolor sit 2",
                Description = "Lorem ipsum dolor sit amet",
                Symbol = Symbol.MusicInfo
            });
    
            return Task.FromResult<IEnumerable<SampleModel>>(data); 
         }
    }
    

    如果根本不需要返回任务(您没有任何异步代码),那么只需将其完全删除。 (但是你必须重构调用这个方法的代码)

    查看此代码,我怀疑有人会在开发过程的后期调用异步方法,并且已经预料到通过指定此方法返回 Task

    【讨论】:

    • 所以我们可以说,它是async签名的一种占位符。对吗?
    • 好吧,每当您await 某些东西时,您都需要将async 添加到方法签名中。有关为什么需要 async 关键字的更深入解释,请阅读这篇文章:blogs.msdn.microsoft.com/ericlippert/2010/11/11/…。在这种特殊情况下,添加 async 关键字是合理的。由于这是一个模板,他们希望人们将 await Task.Completed 替换为 await FetchDataFromDatabaseAsync();
    • return Task.Run(()=>{xx })?
    • 消费者不会对异常处理语义有期望吗?如果代码抛出异常会发生什么?通常它应该返回一个错误的任务,但在这种情况下它不会;异常会冒泡。
    • @rory.ap 正确,以减轻您可以捕获异常并返回 Task.FromException(exception);
    【解决方案2】:

    await Task.CompletedTask 如第一个答案所说,使实现此方法更容易,因为此实现不耗时,因此“await Task.CompletedTask;”或“返回 Task.FromResult(data);”两者都将同步运行。您可以使用上面提到的这两种模式,但是这种方法被设计为异步方法,因此当您的实现耗时但没有任何异步代码时,请使用 Task.Run 来创建一个任务。

    【讨论】:

      猜你喜欢
      • 2020-07-08
      • 2021-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-12
      • 2022-01-21
      • 2021-05-29
      相关资源
      最近更新 更多