我已经开始学习函数式编程,虽然在通常情况下链接方法看起来很棒(我认为),但是在处理异步/等待时确实变得很丑
C++
有什么方法可以消除这种噪音?
编辑:
await (await (await CosmosDbRepository<ApplicationProcess>
.GetItemAsync(param.ProcessId))
.Historize(() => _analyseFinanciereService.ProcessAsync(),
ProcessStepEnum.Application))
.Notify(p => p.GetLastStep());
Edit2:带有接受Task的扩展方法
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)
...
这就是我一直在寻找的内容,即使我对最新评论感到困惑
答案 0 :(得分:2)
我以LinqPad query上传的所有显示的代码,因此您可以立即尝试。
函数式编程的概念为monad(我强烈建议陌生的C#程序员从提供的链接开始)。 C#任务可能被认为是monad,据我了解,这正是您所需要的。
出于这个答案的目的,我简化了您所拥有的示例:
await (await (await A.GetNumber()).DoubleIt()).SquareIt()
其中的方法如下(为方便起见,将其定义为静态):
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);}
}
现在,您只需一点点胶就可以轻松地将它们链接起来:
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));
}
AndThen
方法的行为与单子绑定完全一样:
await
A.GetNumber()
.AndThen(A.DoubleIt)
.AndThen(A.SquareIt)
更重要的是,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));
}
使用它,您可以使用以下语法:
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);
您得到number: 3 doubled: 6, squared: 9
。
简单的SelectMany版本将允许您使用squared
作为最后select
行中唯一的表达式。 “ hardcodre”版本允许您使用任何使用在from
关键字之后定义的值的表达式。
答案 1 :(得分:0)
我试图以一种方式实现它-只有当源任务成功完成(没有错误)时,它才应该继续执行下一个任务。这似乎工作正常,但尝试思考在任何情况下都可能失败:-
return await await sourceTask.ContinueWith(async st =>
{
var res = await st; //
return await contWith(res);
}, TaskContinuationOptions.NotOnFaulted & TaskContinuationOptions.OnlyOnRanToCompletion;