为了账号安全,请及时绑定邮箱和手机立即绑定

async Func

async Func

C#
饮歌长啸 2023-12-17 10:49:07
方法内的 3 个调用有什么区别WhatDifferences?这是测试代码: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;    }}
查看完整描述

2 回答

?
慕婉清6462132

TA贡献1804条经验 获得超2个赞

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

在这个具体例子中,这基本上是正确的。

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

await ActionAsync(context, IsOddAsync);

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

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

这个函数的作用相同,但对于异步 lambda,因此编译器生成的方法也有一个 async 状态机:

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

一般来说,你的问题可以归结为两个问题:

  1. 我应该使用方法组而不是 lambda 吗?是的你应该。这样做没有任何缺点,而且效率更高、代码更短,而且对可维护性没有任何影响。

  2. 我应该删除async/await还是保留关键字?这个更加细致。

在这种特殊情况下省略 没问题,因为 lambda 所做的只是调用单个方法并传递其参数。在调用 之前或之后,lambda 不可能抛出异常。async asyncIsOddAsync

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


查看完整回答
反对 回复 2023-12-17
?
鸿蒙传说

TA贡献1865条经验 获得超7个赞

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);

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

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

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

在这种情况下,除了内部抛出异常时的调用堆栈之外,行为没有任何区别。


查看完整回答
反对 回复 2023-12-17
  • 2 回答
  • 0 关注
  • 86 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信