在C#中使用Language-Ext返回的链式异步操作

Car*_*uez 5 c# functional-programming either async-await language-ext

我正在使用C#的Language-Ext库,我试图链接返回Either类型的异步操作.假设我有三个函数,如果它们成功则返回一个整数,如果失败则返回一个字符串,另一个函数将前三个函数的结果相加.在下面的示例实现中Op3失败并返回一个字符串.

public static async Task<Either<string, int>> Op1()
{
    return await Task.FromResult(1);
}

public static async Task<Either<string, int>> Op2()
{
    return await Task.FromResult(2);
}

public static async Task<Either<string, int>> Op3()
{
    return await Task.FromResult("error");
}

public static async Task<Either<string, int>> Calculate(int x, int y, int z)
{
    return await Task.FromResult(x + y + z);
}
Run Code Online (Sandbox Code Playgroud)

我想链接这些操作,我试图这样做:

var res = await (from x in Op1()
                 from y in Op2()
                 from z in Op3()
                 from w in Calculate(x, y, z)
                 select w);
Run Code Online (Sandbox Code Playgroud)

但是我们代码没有编译,因为我得到cannot convert from 'LanguageExt.Either<string, int>' to 'int'了参数的错误Calculate.我应该如何链接这些功能?

lou*_*ter 5

问题是 LINQ 查询无法确定要SelectMany使用哪个版本,因为x第二行中没有使用。Task<Either<L, R>>您可以通过将您的转换为来解决这个问题EitherAsync<L, R>

    public static async Task<int> M()
    {
        var res = from x in Op1().ToAsync()
                  from y in Op2().ToAsync()
                  from z in Op3().ToAsync()
                  from w in Calculate(x, y, z).ToAsync()
                  select w;

        return await res.IfLeft(0);
    }
Run Code Online (Sandbox Code Playgroud)

或者,不返回Task<Either<L, R>>return EitherAsync<L, R>

    public static EitherAsync<string, int> Op1() =>
        1;

    public static EitherAsync<string, int> Op2() =>
        2;

    public static EitherAsync<string, int> Op3() =>
        3;

    public static EitherAsync<string, int> Calculate(int x, int y, int z) =>
        x + y + z;

    public static async Task<int> M()
    {
        var res = from x in Op1()
                  from y in Op2()
                  from z in Op3()
                  from w in Calculate(x, y, z)
                  select w;

        return await res.IfLeft(0);
    }
Run Code Online (Sandbox Code Playgroud)