Last active
March 16, 2019 02:32
-
-
Save StephenCleary/986e214416f4ae4916dbe106a9fc9830 to your computer and use it in GitHub Desktop.
Try (error) monad in C#
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static class Try | |
{ | |
public static Try<T> FromException<T>(Exception exception) => Try<T>.FromException(exception); | |
public static Try<T> FromValue<T>(T value) => Try<T>.FromValue(value); | |
public static Try<T> Create<T>(Func<T> func) => Try<T>.Create(func); | |
} | |
public sealed class Try<T> | |
{ | |
public static Try<T> FromException(Exception exception) => new Try<T>(exception, default, true); | |
public static Try<T> FromValue(T value) => new Try<T>(default, value, false); | |
public static Try<T> Create(Func<T> func) | |
{ | |
try | |
{ | |
return FromValue(func()); | |
} | |
catch (Exception exception) | |
{ | |
return FromException(exception); | |
} | |
} | |
public Try<TResult> Map<TResult>(Func<T, TResult> func) => Bind(value => Try<TResult>.Create(() => func(value))); | |
public Try<TResult> Bind<TResult>(Func<T, Try<TResult>> bind) => | |
_exception != null ? Try<TResult>.FromException(_exception) : bind(_value); | |
public void Match(Action<Exception> whenException, Action<T> whenValue) | |
{ | |
if (_exception != null) | |
whenException(_exception); | |
else | |
whenValue(_value); | |
} | |
public Try<TResult> Select<TResult>(Func<T, TResult> func) => Map(func); | |
public Try<TResult> SelectMany<TOther, TResult>(Func<T, Try<TOther>> bind, Func<T, TOther, TResult> project) => | |
Bind(a => bind(a).Select(b => project(a, b))); | |
public void Deconstruct(out Exception exception, out T value) | |
{ | |
exception = _exception; | |
value = _value; | |
} | |
public T Value => _exception != null ? throw Rethrow() : _value; | |
public override string ToString() => _exception != null ? $"Exception: {_exception}" : $"Value: {_value}"; | |
private Try(Exception exception, T value, bool isException) | |
{ | |
if (isException) | |
{ | |
_exception = exception ?? throw new ArgumentNullException(nameof(exception)); | |
} | |
else | |
{ | |
_value = value; | |
} | |
} | |
private Exception Rethrow() | |
{ | |
ExceptionDispatchInfo.Capture(_exception).Throw(); | |
return _exception; | |
} | |
private readonly Exception _exception; | |
private readonly T _value; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment