IEnumerable选项的IEnumerable选项

时间:2017-06-15 23:02:31

标签: c# linq monads optional

我有第三方方法获得T的IEnumerable并对其进行评估。 我想在我的LINQ评估语句(select,where ...)中引入Option with exceptional values(或者),以获取需要输入方法的值。

对于每个T元素,我希望有一个方法可以返回转换后的元素或错误(将其保留为deferred execution)并且如果返回错误,则评估应该停在那里。 (从技术上讲,这可以通过抛出异常来实现,但这正是我试图避免使用Option)

我想知道这个概念是否可以用LINQ实现,或者更普遍地用C#实现?

如果无法实现,这会导致我在代码中使用抛出异常替换完全选项,因为使用带有选项的API可以为客户端显示相同的问题。

总之,这正是我想要实现的目标:

这可能是实现的一个可能的方法:

public Option<IEnumerable<T>,TError> Sequence<T,TError>(IEnumerable<Option<T,TError>> options)

其中:

  • 应该使用延迟执行将IE的数量保留为

  • 应该返回第一个错误

  • 发现错误时应停止

**最终方法需要IE的数量,它将评估它(它可能是我无法访问的第三方方法)    而且我不想两次评估IEnumerable

1 个答案:

答案 0 :(得分:0)

在尝试了一段时间来解决这个问题,并且感觉异常应该能够模仿monad之后,我发布了more conceptual version of this question

谢谢,并基于马克的回答,这也证实了我对“与C#/ Java风格异常同构”的怀疑。

我能够创建以下实现:

public static class LinqEitherExtension
{
    public static IEnumerable<T> UntilException<T,TException>(
        this IEnumerable<Option<T,TException>> enumerable, 
        Action<TException> errorHandler
        )
    {
        return enumerable
            .TakeWhile(e =>
                           {
                               e.MatchNone(errorHandler);
                               return e.HasValue;
                           })
            .SelectMany(e => e.ToEnumerable());
    }
}


public class Program
{
    static void Main(string[] args)
    {
        var numbers = new List<int> {1, 2, 3, 4, 5};
        ThirdPartyFunction(numbers.Select(CheckNumbers).UntilException(Console.WriteLine));
        //returns: 
        //1     
        //2
        //3 is exceptional number.
    }

    public static Option<int,string> CheckNumbers(int number)
    {
        return number == 3
            ? Option.None<int, string>("3 is exceptional number.")
            : number.Some<int, string>();
    }

    //Cannot be accessed/altered
    public static void ThirdPartyFunction(IEnumerable<int> numbers)
    {
        foreach (var number in numbers) Console.WriteLine(number.ToString());
    }

}

注意:如果在使用枚举之后,ThirdPartyFunction将继续执行副作用(如Console.WriteLine),那么在抛出异常和使用错误作为返回类型之间仍然存在差距:

  • 抛出异常方法:不再执行任何副作用。
  • Eithers方法:将让ThirdPartyFunction完成执行,客户端消耗函数的输出可以忽略返回值,但内部发生的任何副作用仍然会执行。

对于我之后的事情将完成工作,但我想可能有更好的解决方案。