c#:链式异步方法
c#: Chain asynchronous methods
我发现一段代码展示了如何链接异步方法。这是代码:
public static class ExtensionMethod
{
public static async Task<TResult> MapAsync<TSource, TResult>(
this Task<TSource> @this,
Func<TSource, Task<TResult>> fn)
{
return await fn(await @this);
}
}
public partial class Program
{
public async static Task<int> FunctionA
(int a) => await Task.FromResult(a * 1);
public async static Task<int> FunctionB(
int b) => await Task.FromResult(b * 2);
public async static Task<int> FunctionC(
int c) => await Task.FromResult(c * 3);
public async static void AsyncChain()
{
int i = await FunctionC(10)
.MapAsync(FunctionB)
.MapAsync(FunctionA);
Console.WriteLine("The result = {0}", i);
}
}
但是我不明白为什么在扩展方法MapAsync
里面我们有await fn(await @this)
?
有人能给我解释一下吗?
这是因为为了获得上一次调用的值(在本例中是存储在任务 @this
中的值),必须等待它。因为 await
现在正在该方法中使用并且必须标记为 async
,所以您现在不能再简单地 return 来自 fn
的结果,因为它是一个任务。 (我相信你知道,用非常简单的术语来说,将方法标记为异步意味着方法签名有点忽略 Task 并且只想要一个泛型类型的实例作为 return 或者什么都没有,如果它没有使用 Task
的通用版本。)
为了回应您关于链接同步和异步方法的评论,这种使用 Task 的方法仍然适用于同步方法,您只需假装它的异步通过包装任务的结果(已标记为已完成)。像这样:
public async static Task<int> AsyncFunction(int x)
=> await SomeAsyncMethodThatReturnsTaskOfInt();
public static Task<int> SyncFunction(int x)
=> Task.FromResult(SomeSyncMethodThatReturnsInt());
public async static void AsyncChain()
{
int i = await AsyncFunction(10)
.MapAsync(SyncFunction);
Console.WriteLine("The result = {0}", i);
}
您可以从 FunctionA、FunctionB 和 FunctionC 定义中删除所有 async/awaits,因为它们可以 return 任务。
Stephen Cleary 在 Eliding await 上发表了一篇很好的文章,更好地解释了当该方法唯一要做的事情是 returning [= 时,何时应该和不应该使用 await 15=].
说了这么多,Gusman 的评论是完全正确的,对于一个相当简单的 ContinueWith
我发现一段代码展示了如何链接异步方法。这是代码:
public static class ExtensionMethod
{
public static async Task<TResult> MapAsync<TSource, TResult>(
this Task<TSource> @this,
Func<TSource, Task<TResult>> fn)
{
return await fn(await @this);
}
}
public partial class Program
{
public async static Task<int> FunctionA
(int a) => await Task.FromResult(a * 1);
public async static Task<int> FunctionB(
int b) => await Task.FromResult(b * 2);
public async static Task<int> FunctionC(
int c) => await Task.FromResult(c * 3);
public async static void AsyncChain()
{
int i = await FunctionC(10)
.MapAsync(FunctionB)
.MapAsync(FunctionA);
Console.WriteLine("The result = {0}", i);
}
}
但是我不明白为什么在扩展方法MapAsync
里面我们有await fn(await @this)
?
有人能给我解释一下吗?
这是因为为了获得上一次调用的值(在本例中是存储在任务 @this
中的值),必须等待它。因为 await
现在正在该方法中使用并且必须标记为 async
,所以您现在不能再简单地 return 来自 fn
的结果,因为它是一个任务。 (我相信你知道,用非常简单的术语来说,将方法标记为异步意味着方法签名有点忽略 Task 并且只想要一个泛型类型的实例作为 return 或者什么都没有,如果它没有使用 Task
的通用版本。)
为了回应您关于链接同步和异步方法的评论,这种使用 Task 的方法仍然适用于同步方法,您只需假装它的异步通过包装任务的结果(已标记为已完成)。像这样:
public async static Task<int> AsyncFunction(int x)
=> await SomeAsyncMethodThatReturnsTaskOfInt();
public static Task<int> SyncFunction(int x)
=> Task.FromResult(SomeSyncMethodThatReturnsInt());
public async static void AsyncChain()
{
int i = await AsyncFunction(10)
.MapAsync(SyncFunction);
Console.WriteLine("The result = {0}", i);
}
您可以从 FunctionA、FunctionB 和 FunctionC 定义中删除所有 async/awaits,因为它们可以 return 任务。
Stephen Cleary 在 Eliding await 上发表了一篇很好的文章,更好地解释了当该方法唯一要做的事情是 returning [= 时,何时应该和不应该使用 await 15=].
说了这么多,Gusman 的评论是完全正确的,对于一个相当简单的 ContinueWith