/// <summary>
 /// If the result is success, returns it. Otherwise throws the result of the otherwise function.
 /// </summary>
 public static A Get <A, E>(this ITry <A, E> t, Func <E, Exception> otherwise)
 {
     return(t.Match(
                s => s,
                e => throw otherwise(e)
                ));
 }
 /// <summary>
 /// Maps the successful result to a new try.
 /// </summary>
 public static ITry <B, E> FlatMap <A, E, B>(this ITry <A, E> t, Func <A, ITry <B, E> > f)
 {
     return(t.Match(
                s => f(s),
                e => Try.Error <B, E>(e)
                ));
 }
 private UserActionResult ToUserActionResult(ITry <Unit, SignInError> t) =>
 t.Match(
     s => UserActionResult.Success(),
     e => e.Match(
         SignInError.InvalidCredentials, _ => UserActionResult.Error(UserMessages.InvalidCredentials()),
         SignInError.NoConnection, _ => UserActionResult.Error(UserMessages.NoConnection())
         )
     );
 public override void WriteJson(
     JsonWriter writer,
     ITry <object> value,
     JsonSerializer serializer) => value
 .Match(
     _ => FromObject(_, serializer),
     _ => FromObject(_, serializer))
 .WriteTo(writer);
 private IOption <UserMessage> ProcessResult(ITry <ShoppingListWithItems, CookRecipeError> result) =>
 result.Match(
     s => UpdateShoppingList(s).Pipe(_ => Option.Empty <UserMessage>()),
     e => Option.Create(e.Match(
                            CookRecipeError.NotEnoughFoodstuffsInShoppingList,
                            _ => UserMessages.NotEnoughFoodstuffsInShoppingList()
                            ))
     );
 /// <summary>
 /// Maps the error result to a new try.
 /// </summary>
 public static ITry <B, F> FlatMapError <A, E, B, F>(this ITry <A, E> t, Func <E, ITry <B, F> > f)
     where A : B
     where E : F
 {
     return(t.Match(
                s => Try.Success <B, F>(s),
                e => f(e)
                ));
 }
Exemple #7
0
 private UserActionResult ToUserActionResult(ITry <Unit, SignUpError[]> t) =>
 t.Match(
     s => UserActionResult.Success(),
     e => e.First().Match(
         SignUpError.NoConnection, _ => UserActionResult.Error(UserMessages.NoConnection()),
         SignUpError.InvalidEmail, _ => Email.Invalidate().Pipe(u => UserActionResult.Error()),
         SignUpError.PasswordTooShort, _ => Password.Invalidate().Pipe(u => UserActionResult.Error()),
         SignUpError.AccountAlreadyExists, _ => UserActionResult.Error(UserMessages.AccountAlreadyExists())
         )
     );
Exemple #8
0
 /// <summary>
 /// Return the first success otherwise concatenate the error messages of both failures.
 /// </summary>
 /// <typeparam name="T"></typeparam>
 /// <param name="original"></param>
 /// <param name="fn"></param>
 /// <returns></returns>
 public static ITry <T> SelectFirstSuccess <T>(this ITry <T> original, Func <ITry <T> > fn) =>
 original.Match(
     success: (val) => original,
     failure: (firstError) =>
     fn().Let(
         secondResult => secondResult.Match(
             success: (_) => secondResult,
             failure: (secondError) => Try.Failure <T>(String.Concat(firstError, ", ", secondError))
             )
         )
     );
 /// <summary>
 /// If the result is success, returns it. Otherwise throws the exception.
 /// </summary>
 public static A Get <A, E>(this ITry <A, E> t)
     where E : Exception
 {
     return(t.Match(
                s => s,
                e =>
     {
         ExceptionDispatchInfo.Capture(e).Throw();
         return default;
     }
                ));
 }
Exemple #10
0
        private void RetrievingValues()
        {
            // A try is a specific case of coproduct. Match methods are applicable for all coproduct types.
            ITry <int, NetworkOperationError> number = Api.GetNumber();

            // Match is the preferred way how to retrieve values of tries (and coproducts in general). It is typesafe and future proof.
            // This overload takes two functions. Each of those have to return a value and result is stored in the stringifiedNumber variable.
            string stringifiedNumber = number.Match(
                result => result.ToString(),
                _ => "Unfortunately, we failed to obtain a number from the server."
                );

            // This overload accepts two optional functions. If either of them isn't provided, nothing happens for that case.
            number.Match(
                n => Console.Write($"Operation successful, result is: {n}."),
                _ => Console.Write("Operation failed, try again.")
                );
            number.Match(n => Console.Write($"Operation successful, result is: {n}."));
            number.Match(ifSecond: _ => Console.Write("Operation failed, try again."));

            // Get method will throw an exception for unsuccessful tries that have exception as the error. Using it is an anti-pattern.
            // You should rather use Match to branch your code into individual cases where each case is guaranteed to work.
            // This might be needed on the boundary with some other framework where you have to work with exceptions.
            ITry <int, Exception> numberWithException = number.MapError(e => new InvalidOperationException());
            int numberValue1 = numberWithException.Get();

            // You can also configure the exception that is thrown by mapping the error inside Get directly.
            int numberValue2 = number.Get(e => new InvalidOperationException());
            int numberValue3 = numberWithException.Get(ex => new Exception("Error when retrieving number", innerException: ex));

            // Because try is a coproduct, you can check the value directly. On try, there are named properties for this.
            IOption <int> successResult1 = number.Success;
            IOption <int> successResult2 = number.First;
            IOption <NetworkOperationError> errorResult  = number.Error;
            IOption <NetworkOperationError> errorResult2 = number.Second;
        }
 public static IOption <UserMessage> MapToUserMessage <A>(this ITry <A> aTry, Func <A, IOption <UserMessage> > mapper)
 {
     return(aTry.Match(mapper, e => Option.Create(UserMessage.Error(e))));
 }
 public static Task <IOption <UserMessage> > MapToUserMessageAsync <A>(this ITry <Task <A> > aTry, Func <A, IOption <UserMessage> > mapper)
 {
     return(aTry.Match(r => r.Map(mapper), e => Task.FromResult(Option.Create(UserMessage.Error(e)))));
 }
Exemple #13
0
 public static ITry <TNew> SelectMany <TOriginal, TNew>(this ITry <TOriginal> original, Func <TOriginal, ITry <TNew> > fn) =>
 original.Match(
     success: (val) => fn(val),
     failure: (err) => Try.Failure <TNew>(err)
     );
Exemple #14
0
 /// <summary>
 /// Functor mapping over success. Pure function application. Errors propogate.
 /// </summary>
 public static ITry <T> SelectError <T>(this ITry <T> val, Func <string, string> fn) =>
 val.Match(
     success: (_) => val,
     failure: (err) => Try.Failure <T>(fn(err))
     );
Exemple #15
0
 public static T GetValue <T>(this ITry <T> value) =>
 value.Match(
     success: (val) => val,
     failure: (message) => new InvalidOperationException(message).AsValue <T>()
     );
 private IOption <UserMessage> ProcessResult(ITry <ShoppingListWithItems, RemoveFoodstuffsError> result) =>
 result.Match(
     s => UpdateState().Pipe(_ => Option.Empty <UserMessage>()),
     e => e.Match(
         RemoveFoodstuffsError.FoodstuffIsRequiredInRecipe, _ => UserMessages.FoodstuffRequiredInRecipe().ToOption(),
         RemoveFoodstuffsError.FoodstuffNotInShoppingList, _ => throw new InvalidOperationException()