IEnumerable of Options to Option of IEnumerable

笑着哭i 提交于 2019-12-08 09:38:11

问题


I have a 3rd party method that get IEnumerable of T and evaluates it. I would like to introduce Option with exceptional values(either) in my LINQ evaluation statements(select, where...) for the value that needs to get fed into the method.

For each T element I would like to have a method that can return the transformed element or an error (leaving it as deferred execution) and If error is returned evaluation should stop there. (technically this can be achieved with throwing an exception, but this is exactly what im trying to avoid using Option)

I was wondering if this concept can be achieved with LINQ or more generally in C#?

If it can't be implemented this leads me to replace completely option in my code with throwing exceptions, because the same problem could show up for the client using my API with Options.

In summary this is what i am trying to achieve:

This could be one possible mothod signture to implement:

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

Which:

  • Should leave IEnumerable of T with deferred execution

  • Should return first error found

  • Should stop when error found

** Final method needs IEnumerable of T which will eval it (it could be 3rd party method that i cannot access) and I don't want to evaluate the IEnumerable twice


回答1:


After trying for a while to solve this problem, and having the feeling that exceptions should be able to be mimic with either monads, I posted a more conceptual version of this question.

Thanks, and based on mark's answer which as well confirmed my suspicion about "Either being isomorphic to C#/Java-style exceptions".

I was able to create the following implementation:

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());
    }

}

Note: If the ThirdPartyFunction will continue to to do side effects (like Console.WriteLine) after consuming the enumerable, This will still leave a gap between exception throwing and using error as return type:

  • Throwing exceptions approach: Will not execute any more side effects as well.
  • Eithers approach : Will let the ThirdPartyFunction to finish the execution, Client consuming the output of the function can ignore the return value, But any side effect happens inside will still execute.

For what I am after this will get the job done.



来源:https://stackoverflow.com/questions/44578286/ienumerable-of-options-to-option-of-ienumerable

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!