namespace System.Extensions { public class Result { private readonly object value; public Result(TSuccess successValue) { value = successValue; } public Result(TFailure failureValue) { value = failureValue; } public bool TryExtractSuccess(out TSuccess successValue) { if (value is TSuccess success) { successValue = success; return true; } else { successValue = default; return false; } } public bool TryExtractFailure(out TFailure failureValue) { if (value is TFailure failure) { failureValue = failure; return true; } else { failureValue = default; return false; } } public Result Do(Action onSuccess, Action onFailure) { if (onSuccess is null) { throw new ArgumentNullException(nameof(onSuccess)); } if (onFailure is null) { throw new ArgumentNullException(nameof(onFailure)); } if (value is TSuccess) { onSuccess.Invoke(); } else if (value is TFailure) { onFailure.Invoke(); } return this; } public Result DoAny(Action onSuccess = null, Action onFailure = null) { if (value is TSuccess) { onSuccess?.Invoke(); } else if (value is TFailure) { onFailure?.Invoke(); } return this; } public Result Do(Action onSuccess, Action onFailure) { if (onSuccess is null) { throw new ArgumentNullException(nameof(onSuccess)); } if (onFailure is null) { throw new ArgumentNullException(nameof(onFailure)); } if (value is TSuccess success) { onSuccess.Invoke(success); } else if (value is TFailure failure) { onFailure.Invoke(failure); } return this; } public Result DoAny(Action onSuccess = null, Action onFailure = null) { if (value is TSuccess success) { onSuccess?.Invoke(success); } else if (value is TFailure failure) { onFailure?.Invoke(failure); } return this; } public T Switch(Func onSuccess, Func onFailure) { if (onSuccess is null) { throw new ArgumentNullException(nameof(onSuccess)); } if (onFailure is null) { throw new ArgumentNullException(nameof(onFailure)); } if (value is TSuccess success) { return onSuccess.Invoke(success); } else if (value is TFailure failure) { return onFailure.Invoke(failure); } throw new InvalidOperationException($"{nameof(value)} must be of type {typeof(TSuccess)} or {typeof(TFailure)} in order to switch to {typeof(T)}"); } public T SwitchAny(Func onSuccess = null, Func onFailure = null) { if (value is TSuccess success) { return onSuccess is null ? default : onSuccess.Invoke(success); } else if (value is TFailure failure) { return onFailure is null ? default : onFailure.Invoke(failure); } throw new InvalidOperationException($"{nameof(value)} must be of type {typeof(TSuccess)} or {typeof(TFailure)} in order to switch to {typeof(T)}"); } public Result Switch(Func onSuccess, Func onFailure) { if (onSuccess is null) { throw new ArgumentNullException(nameof(onSuccess)); } if (onFailure is null) { throw new ArgumentNullException(nameof(onFailure)); } if (value is TSuccess success) { return Result.Success(onSuccess.Invoke(success)); } else if (value is TFailure failure) { return Result.Failure(onFailure.Invoke(failure)); } throw new InvalidOperationException($"{nameof(value)} must be of type {typeof(TSuccess)} or {typeof(TFailure)} in order to switch to Result of type {typeof(V)} or {typeof(K)}"); } public Result SwitchAny(Func onSuccess, Func onFailure) { if (value is TSuccess success) { return Result.Success(onSuccess is null ? default : onSuccess.Invoke(success)); } else if (value is TFailure failure) { return Result.Failure(onFailure is null ? default : onFailure.Invoke(failure)); } throw new InvalidOperationException($"{nameof(value)} must be of type {typeof(TSuccess)} or {typeof(TFailure)} in order to switch to Result of type {typeof(V)} or {typeof(K)}"); } public Optional ToOptional() { if (value is TSuccess) { return Optional.FromValue(value.Cast()); } return Optional.None(); } public static implicit operator Result(TSuccess success) { return Success(success); } public static implicit operator Result(TFailure failure) { return Failure(failure); } public static Result Success(TSuccess value) { return new Result(value); } public static Result Failure(TFailure value) { return new Result(value); } } }