Result<T, E>
Control Flow
IsOkAnd
Use IsOkAnd
when you need to check if the Result
is an Ok
and the value inside the Ok
matches a predicate.
Result<DateTime, Error> safeParseResult = SafeParse("2025-01-01");
safeParseResult.IsOkAnd(dateTime => dateTime > new DateTime(2024, 1, 1)); // true
IsErrAnd
Use IsErrAnd
when you need to check if the Result
is an Err
and the value inside the Err
matches a predicate.
Result<DateTime, Error> safeParseResult = SafeParse("2025");
// ^? Err<DateTime, Error>(new Error(ErrorCodes.MalformedDateTime))
safeParseResult.IsErrAnd(error => error.Code == ErrorCodes.MalformedDateTime); // true
Transform
MapErr
The counterpart to Map, use MapErr
when you need to transform the contained value if it is an Err
. It is useful when you need to transform the Err
type in order to continue chaining monadic operations.
Result<string, string> GenerateName();
Result<int, Error> GetLength(string value);
Result<int, Error> lengthResult = GenerateName() // Result<string, string>
.MapErr(message => new Error(message)) // Result<string, Error>
.Map(name => GetLength(name)) // Result<Result<int, Error>, Error>
.Flatten(); // Result<int, Error>
Consume
ExpectErr
The counterpart to Inspect, use ExpectErr
when you want to consume the monadic wrapper and fail loudly when the Result
is an Ok
. It allows you to provide a meaningful exception message to explain why the error is expected.
Result<int, string> result = Result.Ok<int, string>(10);
result.ExpectErr("Must be error"); // throws UnmetExpectationException with message "Must be error"
An UnmetExpectationException
with your provided message will be thrown when the value is a success.
UnwrapErr
The counterpart to Unwrap, use UnwrapErr
when you are certain the Result
is an Err
and you want to fail loudly if it is an Ok
.
Result<int, string> ok = Result.Ok<int, string>(10);
ok.UnwrapErr(); // throws UnwrapException
Result<int, string> err = Result.Err<int, string>("Error");
err.UnwrapErr(); // returns "Error"
An UnwrapException
will be thrown if the Result
is an Ok
.
Side-Effect
InspectErr
The counterpart to Inspect, use InspectErr
when you want to run a side effect against an Err
without modifying the underlying value. The most common use case for InspectErr
is to log an error in the event of a failure.
Result<string, string> result = GetUser("John")
.InspectErr(err => Console.WriteLine($"Get user failed: {err.Message}"))
.Map(user => user.Username)
.MapErr(err => err.Message);
Logical Operators
And
Use And
when you need to chain together a series of Result
instances and you want to know about the first Err
or the last Ok
in the chain.
Arguments passed to And
are eagerly evaluated. If your arguments are the result of a function call, use AndThen instead, which is lazily evaluated.
Ok1
Ok2
Ok2
Ok
Err
Err
Err
Ok
Err
Err1
Err2
Err1
var x = Result.Ok<int, string>(1);
var y = Result.Err<int, string>("late error");
Debug.Assert(x.And(y) == Result.Err<int, string>("late error"));
var x = Result.Err<int, string>("early error");
var y = Result.Ok<int, string>(1);
Debug.Assert(x.And(y) == Result.Err<int, string>("early error"));
var x = Result.Err<int, string>("early error");
var y = Result.Err<int, string>("late error");
Debug.Assert(x.And(y) == Result.Err<int, string>("early error"));
var x = Result.Ok<int, string>(1);
var y = Result.Ok<int, string>(2);
Debug.Assert(x.And(y) == Result.Ok<int, string>(2));
AndThen
Use AndThen
when you need to chain a series of functions together that all return Result
instances and you only care about the first Err
or the last Ok
. It performs the same operation as And for each lazily evaluated function.
Result<string, string> SquareThenToString(int value)
=> Result.Try<int, string>(() => value ^ 2, _ => "overflow")
.Map(x => x.ToString());
var x = Result.Ok<int, string>(2);
var y = Result.Ok<int, string>(4);
Debug.Assert(x.AndThen(SquareThenToString) == y);
var x = Result.Ok<int, string>(Int.MaxValue);
Debug.Assert(x.AndThen(SquareThenToString) == Result.Err<string, string>("overflow"));
var x = Result.Err<int, string>("NaN");
Debug.Assert(x.AndThen(SquareThenToString) == Result.Err<string, string>("NaN"));
Or
Use Or
when you need to chain together a series of Result
instances and you want to know about the first Ok
or the last Err
in the chain.
Arguments passed to Or
are eagerly evaluated. If your arguments are the result of a function call, use OrElse instead, which is lazily evaluated.
Ok1
Ok2
Ok1
Ok
Err
Ok
Err
Ok
Ok
Err1
Err2
Err2
var x = Result.Ok<int, string>(1);
var y = Result.Ok<int, string>(2);
Debug.Assert(x.Or(y) == Result.Ok<int, string>(1));
var x = Result.Ok<int, string>(1);
var y = Result.Err<int, string>("error");
Debug.Assert(x.Or(y) == Result.Ok<int, string>(1));
var x = Result.Err<int, string>("error");
var y = Result.Ok<int, string>(1);
Debug.Assert(x.Or(y) == Result.Ok<int, string>(1));
var x = Result.Err<int, string>("error 1");
var y = Result.Err<int, string>("error 2");
Debug.Assert(x.Or(y) == Result.Err<int, string>("error 2"));
OrElse
Use OrElse
when you need to chain a series of functions together that all return Result
instances and you only care about the first Ok
or the last Err
. It performs the same operation as Or for each lazily evaluated function.
Result<string, string> SquareThenToString(int value)
=> Result.Try<int, string>(() => value ^ 2, _ => "overflow")
.Map(x => x.ToString());
var x = Result.Ok<int, string>(2);
var y = Result.Ok<int, string>(4);
Debug.Assert(x.OrElse(SquareThenToString) == x;
var x = Result.Ok<int, string>(Int.MaxValue);
Debug.Assert(x.OrElse(SquareThenToString) == Result.Err<string, string>("overflow"));
var x = Result.Err<int, string>("NaN");
Debug.Assert(x.OrElse(SquareThenToString) == Result.Err<string, string>("NaN"));
Last updated
Was this helpful?