/// <summary> /// Applies a function to a series of Result arguments /// </summary> /// <typeparam name="TFailure">Type of Failure</typeparam> /// <typeparam name="TResult">Type of Success</typeparam> /// <typeparam name="T1">Type of the first argument</typeparam> /// <typeparam name="T2">Type of the second argument</typeparam> /// <typeparam name="T3">Type of the third argument</typeparam> /// <param name="func">Function to call</param> /// <param name="first">First argument for the function</param> /// <param name="second">Second argument for the function</param> /// <param name="third">Third argument for the function</param> /// <returns>If all arguments are Success, then a Success is returned. Otherwise, all the Failures are concatentated into a Failure Result</returns> /// <exception cref="ArgumentNullException"></exception> public static IResult <IEnumerable <TFailure>, TResult> Apply <TResult, TFailure, T1, T2, T3>(Func <T1, T2, T3, TResult> func, IResult <TFailure, T1> first, IResult <TFailure, T2> second, IResult <TFailure, T3> third) { if (func == null) { throw new ArgumentNullException(nameof(func)); } if (first == null) { throw new ArgumentNullException(nameof(first)); } if (second == null) { throw new ArgumentNullException(nameof(second)); } if (third == null) { throw new ArgumentNullException(nameof(third)); } IResult <IEnumerable <TFailure>, TResult> doSuccess() { var firstValue = ((Success <TFailure, T1>)first).Value; var secondValue = ((Success <TFailure, T2>)second).Value; var thirdValue = ((Success <TFailure, T3>)third).Value; return(Success <IEnumerable <TFailure>, TResult>(func(firstValue, secondValue, thirdValue))); } IResult <IEnumerable <TFailure>, TResult> doFailure() { var errors = new List <TFailure>(); void addError(TFailure error) => errors.Add(error); first.Do(addError, _ => { }); second.Do(addError, _ => { }); third.Do(addError, _ => { }); return(Failure <IEnumerable <TFailure>, TResult>(errors)); } var firstIsSuccess = first is Success <TFailure, T1>; var secondIsSuccess = second is Success <TFailure, T2>; var thirdIsSuccess = third is Success <TFailure, T3>; return(firstIsSuccess && secondIsSuccess && thirdIsSuccess?doSuccess() : doFailure()); }