繁体   English   中英

async Func 的 3 次调用有什么区别<task<t> &gt; 在 c# 中? </task<t>

[英]What are differences between the 3 calls for async Func<Task<T>> in c#?

方法WhatDifferences中的 3 个调用之间有什么区别?

这是测试代码:

async Task WhatDifferences(Context context)
{
    await ActionAsync(context, async x => await IsOddAsync(x).ConfigureAwait(false));
    await ActionAsync(context, x => IsOddAsync(x));
    await ActionAsync(context, IsOddAsync);
}

async Task<T> ActionAsync<T>(Context context, Func<Context, Task<T>> action)
{
    return await action(context).ConfigureAwait(false);
}

async Task<bool> IsOddAsync(Context context)
{
    return await Task.Run(() => context.Count++ % 2 == 1).ConfigureAwait(false);
}

class Context
{
    public int Count { get; set; }
}

我正在尝试决定在我的代码库中使用哪一个,并且根据我的知识,所有 3 个行为都相同。

问题与传递异步委托的方法签名不同?

如果我表现出更多的逻辑,你可能会知道我的担忧

async Task<T> ActionAsync<T>(Context context, Func<Context, Task<T>> action)
{
    using (var transaction = new TransactionScope())
    {
        //do some async logic before action
        var result = await action(context).ConfigureAwait(false);
        //do other async validation logic after action
        return result;
    }
}

await与返回Task

和...之间的不同:

await ActionAsync(context, async x => await IsOddAsync(x).ConfigureAwait(false));
await ActionAsync(context, x => IsOddAsync(x));

在某些情况下,您不需要await (当然也不需要async

在以下情况下,执行异步操作的方法不需要使用 await:

  • 方法内部只有一个异步调用
  • 异步调用在方法的最后
  • 不需要捕获/处理任务中可能发生的异常

请参阅在没有等待的情况下返回任务

在这种情况下,您可以中间返回Task

请注意,行为存在细微差别 - 取决于IsOddAsync的实现:

重要提示:返回任务而不是等待它,会改变方法的异常行为,因为它不会在启动任务的方法中抛出异常,而是在等待它的方法中抛出异常。

正如 Gabriel Luci 所指出的,使用IsOddAsync的当前实现(一个调用和一个await ),行为没有区别。

x => IsOddAsync(x)IsOddAsync

和...之间的不同

await ActionAsync(context, x => IsOddAsync(x));
await ActionAsync(context, IsOddAsync);

在第一个中,您正在创建一个带有参数x的匿名(lambda)方法。 由于IsOddAsync也有一个参数(类型相同),因此不需要 lambda 方法。

请注意您需要 lambda 如果IsOddAsync有其他参数,例如和第二个参数,那么您需要 lambda。 例子:

await ActionAsync(context, x => IsOddAsync(x, "mySecondParameter"));

在这种情况下,行为没有区别,除了调用堆栈中抛出异常时。

我正在尝试决定在我的代码库中使用哪一个,并且根据我的知识,所有 3 个行为都相同。

在这个特定的例子中,这基本上是正确的。

这个创建了一个引用IsOddAsync方法的委托:

await ActionAsync(context, IsOddAsync);

这为 lambda 表达式创建了一个方法,并且委托引用了该编译器生成的方法:

await ActionAsync(context, x => IsOddAsync(x));

和这个一样,但是对于一个异步 lambda,所以编译器生成的方法也有一个async state 机器:

await ActionAsync(context, async x => await IsOddAsync(x).ConfigureAwait(false));

一般来说,您的问题归结为两个问题:

  1. 我应该使用方法组而不是 lambdas 吗? 是的你应该。 这样做没有缺点,而且它的效率更高,代码更短,对可维护性没有任何影响。
  2. 我应该省略async / await还是保留关键字? 这个比较细致。

在这种特殊情况下删除async很好,因为 lambda 所做的所有async操作都是调用单个方法并传递其参数。 在调用IsOddAsync之前或之后,不可能从 lambda 引发异常。

但是,如果您的 lambda 更复杂 - 在将x传递给IsOddAsync之前对其进行操作,或者对结果进行操作,或者使用using块,那么您需要保留async / await关键字以获得最大的可维护性。 更多信息在这里

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM