方法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; }
}
我正在尝试确定要在我的代码库中使用哪个代码,并根据我的知识,这三个代码的行为相同。
问题与What's the method signature for passing an async delegate?
不同如果我表现出更多的逻辑,您可能会知道我的担心
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;
}
}
答案 0 :(得分:3)
await
与返回Task
两者之间的区别:
await ActionAsync(context, async x => await IsOddAsync(x).ConfigureAwait(false));
await ActionAsync(context, x => IsOddAsync(x));
在某些情况下,您不需要await
(当然也不需要async
)
在以下情况下,执行异步操作的方法不需要使用await:
- 方法内部只有一个异步调用
- 异步调用位于方法的结尾
- 没有必要在任务中发生捕获/处理异常
请参见Returning a Task without await。
在这种情况下,您可以中间返回Task
。
请注意,行为上的差异很小-取决于IsOddAsync
的实现方式:
重要提示:返回Task而不是等待它会更改方法的异常行为,因为它不会在启动任务的方法内而是在等待任务的方法内抛出异常。
正如加布里埃尔·卢西(Gabriel Luci)所指出的,在IsOddAsync
的当前实现中(一次调用和一个await
),行为上没有区别。
x => IsOddAsync(x)
与IsOddAsync
两者之间的区别
await ActionAsync(context, x => IsOddAsync(x));
await ActionAsync(context, IsOddAsync);
在第一个方法中,您将使用参数x
创建一个匿名(lambda)方法。由于IsOddAsync
还有一个参数(具有相同的类型),因此不需要lambda方法。
请注意,如果IsOddAsync
具有其他参数(例如,和第二个参数,那么您需要lambda。示例:
await ActionAsync(context, x => IsOddAsync(x, "mySecondParameter"));
在这种情况下,除了在堆栈中引发异常时的调用堆栈之外,行为没有其他差异。
答案 1 :(得分: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));
通常,您的问题可以归结为两个问题:
async
/ await
还是保留关键字?这个比较细微。在这种情况下省略async
很好,因为所有async
lambda所做的就是调用一个方法并传递其参数。在调用IsOddAsync
之前或之后,lambda不会引发异常。
但是,如果您的lambda更为复杂-在将其传递给x
之前对IsOddAsync
进行操作,或者对结果进行操作,或者使用using
块,那么您可以d希望保留async
/ await
关键字以实现最大的可维护性。更多信息here。