Skip to content

Instantly share code, notes, and snippets.

@StephenCleary
Last active March 16, 2019 02:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save StephenCleary/986e214416f4ae4916dbe106a9fc9830 to your computer and use it in GitHub Desktop.
Save StephenCleary/986e214416f4ae4916dbe106a9fc9830 to your computer and use it in GitHub Desktop.
Try (error) monad in C#
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