c# 中对 async Func<Task<T>> 的 3 次调用有何区别?
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 个行为都相同。
问题与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;
}
}
await
对比 return Task
两者的区别:
await ActionAsync(context, async x => await IsOddAsync(x).ConfigureAwait(false));
await ActionAsync(context, x => IsOddAsync(x));
在某些情况下,您不需要 await
(当然也不需要 async
)
Methods that perform asynchronous operations don't need to use await if:
- There is only one asynchronous call inside the method
- The asynchronous call is at the end of the method
- Catching/handling exception that may happen within the Task is not necessary
参见 Returning a Task without await。
在这种情况下,您可以 return 中间 Task
。
请注意,行为略有不同 - 取决于 IsOddAsync
的实施:
Important: Returning the Task instead of awaiting it, changes the exception behavior of the method, as it won't throw the exception inside the method which starts the task but in the method which awaits it.
正如 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"));
在这种情况下,行为没有区别,除了内部抛出异常时的调用堆栈。
I'm trying to decide which one to use in my codebase and based on my knowledge all 3 behave the same.
在这个具体实例中,这基本上是正确的。
这个创建一个引用 IsOddAsync
方法的委托:
await ActionAsync(context, IsOddAsync);
这个为 lambda 表达式创建了一个方法,委托引用了编译器生成的方法:
await ActionAsync(context, x => IsOddAsync(x));
这个也一样,但是对于异步 lambda,所以编译器生成的方法也有一个 async
状态机:
await ActionAsync(context, async x => await IsOddAsync(x).ConfigureAwait(false));
一般来说,您的问题归结为两个问题:
- 我应该使用方法组而不是 lambda 吗?是的你应该。这样做没有什么坏处,效率更高一点,代码更短,对可维护性没有任何影响。
- 我应该省略
async
/await
还是保留关键字?这个更微妙。
省略 async
在这种特殊情况下 很好,因为 async
lambda 所做的只是调用一个方法并传递其参数。在调用 IsOddAsync
.
之前或之后,lambda 不可能抛出异常
但是,如果您的 lambda 更复杂 - 在将 x
传递给 IsOddAsync
之前对其进行操作,或者对结果进行操作,或者使用 using
块,那么您希望保留 async
/await
关键字以获得最大的可维护性。更多信息 here.
方法 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 个行为都相同。
问题与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;
}
}
await
对比 return Task
两者的区别:
await ActionAsync(context, async x => await IsOddAsync(x).ConfigureAwait(false));
await ActionAsync(context, x => IsOddAsync(x));
在某些情况下,您不需要 await
(当然也不需要 async
)
Methods that perform asynchronous operations don't need to use await if:
- There is only one asynchronous call inside the method
- The asynchronous call is at the end of the method
- Catching/handling exception that may happen within the Task is not necessary
参见 Returning a Task without await。
在这种情况下,您可以 return 中间 Task
。
请注意,行为略有不同 - 取决于 IsOddAsync
的实施:
Important: Returning the Task instead of awaiting it, changes the exception behavior of the method, as it won't throw the exception inside the method which starts the task but in the method which awaits it.
正如 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"));
在这种情况下,行为没有区别,除了内部抛出异常时的调用堆栈。
I'm trying to decide which one to use in my codebase and based on my knowledge all 3 behave the same.
在这个具体实例中,这基本上是正确的。
这个创建一个引用 IsOddAsync
方法的委托:
await ActionAsync(context, IsOddAsync);
这个为 lambda 表达式创建了一个方法,委托引用了编译器生成的方法:
await ActionAsync(context, x => IsOddAsync(x));
这个也一样,但是对于异步 lambda,所以编译器生成的方法也有一个 async
状态机:
await ActionAsync(context, async x => await IsOddAsync(x).ConfigureAwait(false));
一般来说,您的问题归结为两个问题:
- 我应该使用方法组而不是 lambda 吗?是的你应该。这样做没有什么坏处,效率更高一点,代码更短,对可维护性没有任何影响。
- 我应该省略
async
/await
还是保留关键字?这个更微妙。
省略 async
在这种特殊情况下 很好,因为 async
lambda 所做的只是调用一个方法并传递其参数。在调用 IsOddAsync
.
但是,如果您的 lambda 更复杂 - 在将 x
传递给 IsOddAsync
之前对其进行操作,或者对结果进行操作,或者使用 using
块,那么您希望保留 async
/await
关键字以获得最大的可维护性。更多信息 here.