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