Created
May 19, 2017 19:18
-
-
Save solvingj/adf45a7e86cbd0b4de0db6f119af8af5 to your computer and use it in GitHub Desktop.
Exceptional
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
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