LanguageExt - 当 Match lambda 异步时如何避免双重等待?

问题描述 投票:0回答:1

我在这里使用一个非常简单的示例,以避免与真实案例的细节混淆,并提供一个最小的完整示例。这里的代码可以粘贴到 Visual Studio、Visual Studio Code 或 LinqPad 中,只要你引用了 LanguageExt.Core Nuget 包,并且添加了以下

using
...

using LanguageExt;
using static LanguageExt.Prelude;

想象一下,我有一个 API,它接受

float
,并返回平方根加倍。我有如下辅助函数...

static Either<string, double> Sqrt(double d) =>
  d >= 0.0
    ? Math.Sqrt(d)
    : "Error: Negative number";

static Either<string, double> Double(double d) =>
  d > 10.0
    ? "Error: Too big to double"
    : 2 * d;

如果成功,我的 API 端点将返回“结果:23.3”形式的字符串,否则返回错误。

我将它们连接在一起,如下...

public static string Calc(double d) =>
  (from res1 in Sqrt(d)
   from res2 in Double(res1)
   select res2)
  .Match(res => $"Result: {res}",
    err => err);

这按预期工作。显然,我的真实代码会有比这更多的

from
子句,但我试图保持简单。

现在,假设(更现实)辅助函数是

async
,那么我需要修改我的端点,使其看起来像这样......

public static async Task<string> Calc(double d) =>
  await (from res1 in Sqrt(d).ToAsync()
         from res2 in Double(res1).ToAsync()
         select res2)
    .Match(res => $"Result: {res}",
      err => err);

再次,一切正常。

旁白: 我从阅读 LanguageExt 问题中 Paul Louth 的一些代码中学到了上面的编码风格。如果有更好的方法,请随时提出。我并不声称自己是这方面的专家。

但是,现在如果出现错误,我想记录它们、发送电子邮件等,因此

Match
方法的第二个 lambda 需要是
async
。为了避免编译器错误,我还需要制作第一个
async
,然后
await
结果...

public static async Task<string> CalcAsync2(double d) =>
  await await (from res1 in Sqrt(d).ToAsync()
               from res2 in Double(res1).ToAsync()
               select res2)
    .Match(async res => $"Result: {res}",
      async err => {
        // Log the error, send an email, etc (async);
        return err;
      });

这开始看起来像是我完全错误地做了这件事。也许我错了,但等待等待的任务似乎并不正确。

有人可以在这里发表评论吗?如果任何辅助方法返回

Left
,我希望能够记录错误,但如果所有
async
工作(实际上,尽可能多的工作)都在
 的序列中,我会更喜欢它from
线索,将 lambda 留在
Math
中,除了返回值之外几乎没有什么作用。

c# functional-programming language-ext
1个回答
0
投票

只需使用

MatchAsync

static Task<string> CalcAsync2(double d) =>
     (from res1 in Sqrt(d).ToAsync()
         from res2 in Double(res1).ToAsync()
         select res2)
     .MatchAsync(res => Task.FromResult($"Result: {res}"),
         async err =>
         {
             await Task.Delay(1);
             // Log the error, send an email, etc (async);
             return err;
         }
     );
© www.soinside.com 2019 - 2024. All rights reserved.