【问题标题】:Why doesn't a method containing an async lambda need to be Async itself?为什么包含异步 lambda 的方法本身不需要是异步的?
【发布时间】:2013-09-12 11:44:47
【问题描述】:

例如,每当我等待某些东西时,编译器都会通知我包含的方法必须是异步的。为什么没有以这种方式看到异步羔羊?如果 ForEach 隐藏了它,那么关于不返回 Task 对象和 ForEach 隐式异步无效是否存在一些危险?

public void SaveSome()
{
    Array.ForEach(Enumerable.Range(0,3).ToArray(), async x =>  await SaveRep());
}

【问题讨论】:

    标签: c# asynchronous lambda c#-5.0


    【解决方案1】:

    异步 ​​lambda 只是一种创建异步委托的简单方法。没有什么可说的,包含它的方法必须自己异步执行 anything - lambda 表达式中的任何 await 表达式不会使包含方法等待(除非它正在等待一个任务当然,碰巧依赖于委托)。

    基本上,lambda 表达式表达一些异步代码——它不是执行异步代码本身...所以包含方法不一定异步执行。 p>

    是的,您给出的示例是对 async lambdas 的误用 - 但是将方法设为 async 根本不会改善问题,而且只会产生误导。

    编辑:作为另一种思考方式,请考虑对原始代码进行以下重构:

    public void SaveSome()
    {
        Action<int> action = SaveRepAsync;
        Array.ForEach(Enumerable.Range(0,3).ToArray(), action);
    }
    
    private static async void SaveRepAsync(int x)
    {
        await SaveRep();
    }
    

    SaveSome 方法没有异步 - 只有 SaveRepAsync 方法有...所以这就是需要 async 修饰符的原因。这实际上只是对代码的微小重构(编译器会有效地进行重构)。如果您希望每个包含 async lambda 的方法都具有 async 修饰符,这就像在上面的代码中说,SaveSome 也应该具有修饰符......这没有任何意义,IMO。

    【讨论】:

    • 如果您能详细解释一下为什么上述方法在生产代码中是一个坏主意,我将不胜感激。我当前的异步心理模型要求:1)所有异步调用都是从返回类型为 Task 或 Task 的异步方法中调用的 2)在调用堆栈中一直执行此操作,就好像抛出异常一样 Task 将持有异常 3)只有事件处理程序应该是异步无效的。所以这是语言合法但不好,为什么?我的指导方针正确吗?
    • @Jaycee:嗯,你打电话给Array.ForEach,这通常会做一系列事情——但你的异步 lambda just 等待其他事情。您实际上只是在进行一次即发即弃的操作,但没有任何迹象表明一切何时完成。如果您真的想要一种完全即发即弃的方法,我个人会选择另一种表达方式。就Array.ForEach 而言,它只是被赋予了Action&lt;int&gt;
    • @Jaycee:更安全的解决方案是await Task.WhenAll(Enumerable.Range(0,3).Select(x =&gt; SaveRep())),它将每个元素投影到Task 中,然后等待所有元素。这样你就可以避免async void
    • @StephenCleary:当然,这改变了意思 - 在所有保存完成之前不会完成。目前我们并不真正知道 OP 想要达到什么目标,因此很难提供帮助。
    • @JonSkeet 谢谢两位,这只是我很好奇的一些单元测试代码。我最初有一个 for 循环,然后 CodeRush 给了我一个选项,使其成为 1 班轮。我认为我的指导方针是可以接受的。
    【解决方案2】:

    您只能在 async 方法中使用 awaitasync 方法,但您仍然可以在非异步方法中调用它们,就像您在上面所做的那样 - 在这个情况下,它更像是“一劳永逸”

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-07-20
      • 1970-01-01
      • 1970-01-01
      • 2019-06-05
      • 2014-08-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多