简体   繁体   中英

IEnumerable of Options to Option of IEnumerable

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM