Skip to content

Instantly share code, notes, and snippets.

@solvingj
Created May 19, 2017 19:18
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 solvingj/adf45a7e86cbd0b4de0db6f119af8af5 to your computer and use it in GitHub Desktop.
Save solvingj/adf45a7e86cbd0b4de0db6f119af8af5 to your computer and use it in GitHub Desktop.
Exceptional
internal sealed class ExceptionalCommonLogic
{
public bool IsFailure { get; }
public bool IsSuccess => !IsFailure;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly Exception _exception;
public Exception Exception
{
[DebuggerStepThrough]
get
{
if (IsSuccess)
throw new InvalidOperationException("There is no exception for success.");
return _exception;
}
}
[DebuggerStepThrough]
public ExceptionalCommonLogic(bool isFailure, Exception exception)
{
if (isFailure)
{
if (exception == null)
throw new ArgumentNullException(nameof(exception), "There must be error for failure.");
}
else
{
if (exception != null)
throw new ArgumentException("There should be no exception for success.", nameof(exception));
}
IsFailure = isFailure;
_exception = exception;
}
}
public struct Exceptional : ISerializable
{
private static readonly Exceptional OkExceptional = new Exceptional(false, null);
void ISerializable.GetObjectData(SerializationInfo oInfo, StreamingContext oContext)
{
oInfo.AddValue("IsFailure", IsFailure);
oInfo.AddValue("IsSuccess", IsSuccess);
if (IsFailure)
{
oInfo.AddValue("Exception", Exception);
}
}
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly ExceptionalCommonLogic _logic;
public bool IsFailure => _logic.IsFailure;
public bool IsSuccess => _logic.IsSuccess;
public Exception Exception => _logic.Exception;
[DebuggerStepThrough]
private Exceptional(bool isFailure, Exception exception)
{
_logic = new ExceptionalCommonLogic(isFailure, exception);
}
[DebuggerStepThrough]
public static Exceptional Ok()
{
return OkExceptional;
}
[DebuggerStepThrough]
public static Exceptional Fail(Exception exception)
{
return new Exceptional(true, exception);
}
[DebuggerStepThrough]
public static Exceptional<T> Ok<T>(T value)
{
return new Exceptional<T>(false, value, null);
}
[DebuggerStepThrough]
public static Exceptional<T> Fail<T>(Exception exception)
{
return new Exceptional<T>(true, default(T), exception);
}
/// <summary>
/// Returns first failure in the list of <paramref name="exceptionals"/>. If there is no failure returns success.
/// </summary>
/// <param name="exceptionals">List of exceptionals.</param>
[DebuggerStepThrough]
public static Exceptional FirstFailureOrSuccess(params Exceptional[] exceptionals)
{
foreach (Exceptional exceptional in exceptionals)
{
if (exceptional.IsFailure)
return Fail(exceptional.Exception);
}
return Ok();
}
/// <summary>
/// Returns a result of failure which combined from all failures in the <paramref name="exceptionals"/> list. Error messages are separated by <paramref name="errorMessagesSeparator"/>.
/// If there is no failure returns success.
/// </summary>
/// <param name="errorMessagesSeparator">Separator for error messages.</param>
/// <param name="exceptionals">List of exceptionals.</param>
[DebuggerStepThrough]
public static Result Combine(string errorMessagesSeparator, params Exceptional[] results)
{
List<Exceptional> failedResults = results.Where(x => x.IsFailure).ToList();
if (!failedResults.Any())
return Result.Ok();
string errorMessage = string.Join(errorMessagesSeparator, failedResults.Select(x => x.Exception.Message).ToArray());
return Result.Fail(errorMessage);
}
[DebuggerStepThrough]
public static Result Combine(params Exceptional[] results)
{
return Combine(", ", results);
}
[DebuggerStepThrough]
public static Result Combine<T>(params Exceptional<T>[] exceptionals)
{
return Combine(", ", exceptionals);
}
[DebuggerStepThrough]
public static Result Combine<T>(string errorMessagesSeparator, params Exceptional<T>[] exceptionals)
{
Exceptional[] untyped = exceptionals.Select(exceptional => (Exceptional)exceptional).ToArray();
return Combine(errorMessagesSeparator, untyped);
}
}
public struct Exceptional<T>
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly ExceptionalCommonLogic _logic;
public bool IsFailure => _logic.IsFailure;
public bool IsSuccess => _logic.IsSuccess;
public Exception Exception => _logic.Exception;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly T _value;
public T Value
{
[DebuggerStepThrough]
get
{
if (!IsSuccess)
throw new InvalidOperationException("There is no value for failure.");
return _value;
}
}
//internal Exceptional(Exception ex)
//{
// _exception = ex ?? throw new ArgumentNullException(nameof(ex));
// _value = default(T);
//}
//// creating a new Exceptional
//public static Func<T, Exceptional<T>> Return() => t => t;
//public static implicit operator Exceptional<T>(Exception exception)
//{
// return new Exceptional<T>(exception);
//}
[DebuggerStepThrough]
internal Exceptional(bool isFailure, T value, Exception exception)
{
if (!isFailure && value == null)
throw new ArgumentNullException(nameof(value));
_logic = new ExceptionalCommonLogic(isFailure, exception);
_value = value;
}
public static implicit operator Exceptional(Exceptional<T> exceptional)
{
if (exceptional.IsSuccess)
return Exceptional.Ok();
else
return Exceptional.Fail(exceptional.Exception);
}
public override string ToString()
{
if (IsFailure)
return Exception.Message;
return _value.ToString();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment