Xav*_* Sc 12 .net c# method-chaining async-await
我已经开始学习函数式编程,虽然在正常情况下链接方法看起来很棒(在我看来),但在处理 async/await 时它真的变得很难看
await (await (await CosmosDbRepository<ApplicationProcess>
.GetItemAsync(param.ProcessId))
.Historize(() => _analyseFinanciereService.ProcessAsync(),
ProcessStepEnum.Application))
.Notify(p => p.GetLastStep());
Run Code Online (Sandbox Code Playgroud)
有什么办法可以消除这种噪音吗?
编辑 :
public static async Task<ApplicationProcess> Historize(
this ApplicationProcess process,
Func<Task> fn,
ProcessStepEnum stepEnum)
{
var dateStart = DateTime.UtcNow;
var error = string.Empty;
try
{
await fn();
return process;
}
…
public static async Task Notify<TResult>(
this ApplicationProcess process,
Func<ApplicationProcess, TResult> fn)
...
Run Code Online (Sandbox Code Playgroud)
Edit2:使用扩展方法接受任务
await CosmosDbRepository<ApplicationProcess>
.GetItemAsync(param.ProcessId)
.HistorizeAsync(() => _analyseFinanciereService.ProcessAsync(), ProcessStepEnum.Application)
.NotifyAsync(p => p.GetLastStep());
Run Code Online (Sandbox Code Playgroud)
所以这就是我一直在寻找的,即使我对最新的评论感到困惑
Grz*_*cki 14
我上传的所有代码都是作为LinqPad 查询上传的,因此您可以立即尝试。
函数式编程有一个monad的概念(我强烈建议不熟悉的 C# 程序员从提供的链接开始)。AC# 任务可能被认为是一个 monad,据我所知,它正是您所需要的。
为了这个答案的目的,我做了一个你所拥有的简化示例:
await (await (await A.GetNumber()).DoubleIt()).SquareIt()
Run Code Online (Sandbox Code Playgroud)
其中方法如下(为了方便起见,定义为静态):
public static class A
{
public static Task<int> GetNumber(){return Task.FromResult(3);}
public static Task<int> DoubleIt(this int input){return Task.FromResult(2 * input);}
public static Task<int> SquareIt(this int input){return Task.FromResult(input * input);}
}
Run Code Online (Sandbox Code Playgroud)
现在您只需用一点胶水就可以轻松地将它们链接起来,如下所示:
public static async Task<TOut> AndThen<TIn, TOut>(this Task<TIn> inputTask, Func<TIn, Task<TOut>> mapping)
{
var input = await inputTask;
return (await mapping(input));
}
Run Code Online (Sandbox Code Playgroud)
该AndThen方法的行为与 monadic 绑定完全一样:
await A
.GetNumber()
.AndThen(A.DoubleIt)
.AndThen(A.SquareIt)
Run Code Online (Sandbox Code Playgroud)
更重要的是,C# 有很好的语法来处理 monad:LINQ 查询理解语法。您只需要定义一个 SelectMany 方法,该方法适用于您想要的类型(在本例中为 Task),您就可以开始使用了。
下面我实现了 SelectMany 最“核心”的重载(带有附加resultSelector),它为您提供了最大的灵活性。简单版本几乎与AndThen(我认为只需重命名即可)完全相同。
public static async Task<TOut> SelectMany<TIn, TInterm, TOut>(
this Task<TIn> inputTask,
Func<TIn, Task<TInterm>> mapping,
Func<TIn, TInterm, TOut> resultSelector)
{
var input = await inputTask;
return resultSelector(input, await mapping(input));
}
Run Code Online (Sandbox Code Playgroud)
有了它,您可以使用以下语法:
var task =
from num in A.GetNumber()
from doubled in num.DoubleIt()
from squared in num.SquareIt()
select $"number: {num} doubled: {doubled}, squared: {squared}";
Console.WriteLine(await task);
Run Code Online (Sandbox Code Playgroud)
你得到number: 3 doubled: 6, squared: 9.
简单的 SelectMany 版本将允许您squared在最后select一行中用作唯一可能的表达式。“硬编码”版本允许您使用任何使用from关键字后定义的任何值的表达式。
| 归档时间: |
|
| 查看次数: |
4530 次 |
| 最近记录: |