Result
represents the result of an operation. If the operation fails, Result will contain the exception that occurred;
otherwise, Result
will contain the value resulting from the operation.
The method responsible for the operation must return a Result
with the value resulting from the operation,
or in case of failure, it must return a Result
with an exception.
The consumer code must extract the result through one of the available methods.
The result of the operation can be extracted through several methods such as:
Match()
, ValueOrDefault
, CaseSuccess()
, CaseFailure()
, IsSuccess()
and IsFailure()
.
Note that no exceptions are thrown. Exceptions are just created and returned to the calling code which must decide what to do with them.
Example of a method responsible for the validation operation.
public static Result<string> TryValidate(string? s, IFormatProvider? provider = default)
{
if (s is null)
return new Result<string>(new ArgumentNullException(nameof(s)));
if (s.Length > MaxLength)
return new Result<string>(new ArgumentException(
message: $"{nameof(Name)} is invalid. The value '{s}' must be at most {MaxLength} characters and currently has {s.Length} characters.",
paramName: nameof(s)));
return new Result<string>(s);
}
Example of two methods that use Result
.
public static Result<Name> TryParse(string? s, IFormatProvider? provider = default) =>
TryValidate(s, provider).Match(
Success: x => new Result<Name>(new Name(x)),
Failure: e => new Result<Name>(e));
public static bool IsValid(string? s, IFormatProvider? provider = null) =>
TryValidate(s, provider).Match(
Success: x => true,
Failure: e => false);
R Match<R>(Func<T, R> Success, Func<Exception, R> Failure)
If it is a successful result, it returns the value of the Success function,
otherwise it returns the value of the Failure function.
Match(Action<T> Success, Action<Exception> Failure)
If it is a successful result, it executes the Success action, otherwise it executes the Failure action.
R CaseSuccess<R>(Func<T, R> Success, Func<Exception, R> defaultValue)
If it is a successful result, it returns the value of the Success function,
otherwise it returns the value of the defaultValue function.
bool CaseSuccess(Action<T> Success)
If it is a successful result, it executes the Success action, otherwise it returns false.
T ValueOrDefault(Func<Exception, T> Failure) => Match(value => value, Failure)
If it is a successful result, it returns the value of the result, otherwise it returns the value of the Failure function.
bool CaseFailure(Action<Exception> Failure)
If it is a failure result, it executes the Failure action and return true, otherwise it returns false.
bool IsSuccess()
If it is a successful result, it returns true, otherwise it returns false.
bool IsFailure()
If it is a failure result, it returns true, otherwise it returns false.
C# functional language extensions - louthy/language-ext
Don't throw exceptions in C#. Do this instead - Nick Chapsas