Files

221 lines
5.4 KiB
C#

namespace FinancialApi.Domain;
public interface IFinancialError
{
int ErrorCode { get; }
string Message { get; }
Exception? Exception { get; }
}
public sealed class FinancialError : IFinancialError
{
public FinancialError(int errorCode, string message, Exception? exception = null)
{
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(errorCode);
ErrorCode = errorCode;
Message = message ?? throw new ArgumentNullException(nameof(message));
Exception = exception;
}
public int ErrorCode { get; }
public string Message { get; }
public Exception? Exception { get; }
public override string ToString() => $"Error: {ErrorCode} - {Message}{(Exception == null ? "" : $"\n{Exception}")}";
}
public sealed class FinancialResult<T>
{
private readonly T? _resultValue;
private readonly FinancialError? _resultError;
public FinancialResult(T resultValue)
{
IsError = false;
_resultValue = resultValue;
_resultError = null;
}
public FinancialResult(FinancialError resultError)
{
IsError = true;
_resultValue = default;
_resultError = resultError;
}
public bool IsError { get; }
/// <summary>
/// Error indicator
/// </summary>
public bool IsSuccess => !IsError;
/// <summary>
/// Result Values
/// </summary>
public T? Value => _resultValue;
public FinancialError? Error => _resultError;
public static implicit operator FinancialResult<T>(T resultValue) => new(resultValue);
public static implicit operator FinancialResult<T>(FinancialError resultError) => new(resultError);
public static FinancialResult<T> Success(T successValue)
{
return new FinancialResult<T>(successValue);
}
public static FinancialResult<T> Failure(FinancialError failureValue)
{
return new FinancialResult<T>(failureValue);
}
public TResult Match<TResult>(
Func<T, TResult> success,
Func<FinancialError, TResult> failure,
Func<TResult> nullValue
)
{
return IsError switch
{
false when _resultValue == null => nullValue(),
true => failure(_resultError!),
_ => success(_resultValue)
};
}
public TResult Match<TResult>(Func<T, TResult> success, Func<FinancialError, TResult> failure)
{
return IsError switch
{
true => failure(_resultError!),
_ => success(_resultValue!)
};
}
public TResult? Match<TResult>(Func<T, TResult> success)
{
return IsError switch
{
true => default,
_ => success(_resultValue!)
};
}
public void Match(Action<T> success, Action<FinancialError> failure, Action nullValue)
{
switch (IsError)
{
case false when _resultValue == null:
nullValue.Invoke();
return;
case true:
failure.Invoke(_resultError!);
return;
default:
success(_resultValue);
break;
}
}
public void Match(Action<T> success, Action<FinancialError> failure)
{
switch (IsError)
{
case true:
failure.Invoke(_resultError!);
return;
default:
success(_resultValue!);
break;
}
}
public void Match(Action<T> success)
{
if (IsError)
{
return;
}
success(_resultValue!);
}
public async Task<TResult> MatchAsync<TResult>(
Func<T, Task<TResult>> success,
Func<FinancialError, Task<TResult>> failure,
Func<Task<TResult>> nullValue
)
{
return IsError switch
{
false when _resultValue == null => await nullValue(),
true => await failure(_resultError!),
_ => await success(_resultValue)
};
}
public async Task<TResult> MatchAsync<TResult>(
Func<T, Task<TResult>> success,
Func<FinancialError, Task<TResult>> failure
)
{
return IsError switch
{
true => await failure(_resultError!),
_ => await success(_resultValue!)
};
}
public async Task<TResult?> MatchAsync<TResult>(Func<T, Task<TResult>> success)
{
return IsError switch
{
true => default,
_ => await success(_resultValue!)
};
}
public async Task MatchAsync(Func<T, Task> success, Func<FinancialError, Task> failure, Func<Task> nullValue)
{
switch (IsError)
{
case false when _resultValue == null:
await nullValue.Invoke();
return;
case true:
await failure.Invoke(_resultError!);
return;
default:
await success(_resultValue!);
break;
}
}
public async Task MatchAsync(Func<T, Task> success, Func<FinancialError, Task> failure)
{
switch (IsError)
{
case true:
await failure.Invoke(_resultError!);
return;
default:
await success(_resultValue!);
break;
}
}
public async Task MatchAsync(Func<T, Task> success)
{
if (IsError)
{
return;
}
await success(_resultValue!);
}
}