-
Notifications
You must be signed in to change notification settings - Fork 95
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #106 from feO2x/exceptions-for-invalid-use
Exceptions for invalid use - review and extensions
- Loading branch information
Showing
6 changed files
with
223 additions
and
144 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
namespace ErrorOr; | ||
|
||
internal static class EmptyErrors | ||
{ | ||
public static List<Error> Instance { get; } = []; | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,46 +1,60 @@ | ||
namespace ErrorOr; | ||
|
||
public readonly partial record struct ErrorOr<TValue> : IErrorOr<TValue> | ||
{ | ||
/// <summary> | ||
/// Creates an <see cref="ErrorOr{TValue}"/> from a value. | ||
/// </summary> | ||
public static implicit operator ErrorOr<TValue>(TValue value) | ||
{ | ||
return new ErrorOr<TValue>(value); | ||
} | ||
|
||
/// <summary> | ||
/// Creates an <see cref="ErrorOr{TValue}"/> from an error. | ||
/// </summary> | ||
public static implicit operator ErrorOr<TValue>(Error error) | ||
{ | ||
return new ErrorOr<TValue>(error); | ||
} | ||
|
||
/// <summary> | ||
/// Creates an <see cref="ErrorOr{TValue}"/> from a list of errors. | ||
/// </summary> | ||
public static implicit operator ErrorOr<TValue>(List<Error> errors) | ||
{ | ||
if (errors.Count == 0) | ||
{ | ||
throw new InvalidOperationException("Cannot create an ErrorOr<TValue> from an empty list of errors. Provide at least one error."); | ||
} | ||
|
||
return new ErrorOr<TValue>(errors); | ||
} | ||
|
||
/// <summary> | ||
/// Creates an <see cref="ErrorOr{TValue}"/> from a list of errors. | ||
/// </summary> | ||
public static implicit operator ErrorOr<TValue>(Error[] errors) | ||
{ | ||
if (errors.Length == 0) | ||
{ | ||
throw new InvalidOperationException("Cannot create an ErrorOr<TValue> from an empty array of errors. Provide at least one error."); | ||
} | ||
|
||
return new ErrorOr<TValue>(errors.ToList()); | ||
} | ||
} | ||
namespace ErrorOr; | ||
|
||
public readonly partial record struct ErrorOr<TValue> : IErrorOr<TValue> | ||
{ | ||
/// <summary> | ||
/// Creates an <see cref="ErrorOr{TValue}"/> from a value. | ||
/// </summary> | ||
public static implicit operator ErrorOr<TValue>(TValue value) | ||
{ | ||
return new ErrorOr<TValue>(value); | ||
} | ||
|
||
/// <summary> | ||
/// Creates an <see cref="ErrorOr{TValue}"/> from an error. | ||
/// </summary> | ||
public static implicit operator ErrorOr<TValue>(Error error) | ||
{ | ||
return new ErrorOr<TValue>(error); | ||
} | ||
|
||
/// <summary> | ||
/// Creates an <see cref="ErrorOr{TValue}"/> from a list of errors. | ||
/// </summary> | ||
/// <exception cref="ArgumentNullException">Thrown when <paramref name="errors"/> is null.</exception> | ||
/// <exception cref="ArgumentException">Thrown when <paramref name="errors" /> is an empty list.</exception> | ||
public static implicit operator ErrorOr<TValue>(List<Error> errors) | ||
{ | ||
if (errors is null) | ||
{ | ||
throw new ArgumentNullException(nameof(errors)); | ||
} | ||
|
||
if (errors.Count == 0) | ||
{ | ||
throw new ArgumentException("Cannot create an ErrorOr<TValue> from an empty list of errors. Provide at least one error.", nameof(errors)); | ||
} | ||
|
||
return new ErrorOr<TValue>(errors); | ||
} | ||
|
||
/// <summary> | ||
/// Creates an <see cref="ErrorOr{TValue}"/> from a list of errors. | ||
/// </summary> | ||
/// <exception cref="ArgumentNullException">Thrown when <paramref name="errors"/> is null.</exception> | ||
/// <exception cref="ArgumentException">Thrown when <paramref name="errors" /> is an empty array.</exception> | ||
public static implicit operator ErrorOr<TValue>(Error[] errors) | ||
{ | ||
if (errors is null) | ||
{ | ||
throw new ArgumentNullException(nameof(errors)); | ||
} | ||
|
||
if (errors.Length == 0) | ||
{ | ||
throw new ArgumentException("Cannot create an ErrorOr<TValue> from an empty array of errors. Provide at least one error.", nameof(errors)); | ||
} | ||
|
||
return new ErrorOr<TValue>(errors.ToList()); | ||
} | ||
} |
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,87 +1,99 @@ | ||
using System.Diagnostics.CodeAnalysis; | ||
|
||
namespace ErrorOr; | ||
|
||
/// <summary> | ||
/// A discriminated union of errors or a value. | ||
/// </summary> | ||
/// <typeparam name="TValue">The type of the underlying <see cref="Value"/>.</typeparam> | ||
public readonly partial record struct ErrorOr<TValue> : IErrorOr<TValue> | ||
{ | ||
private readonly TValue? _value = default; | ||
private readonly List<Error>? _errors = null; | ||
|
||
/// <summary> | ||
/// Prevents a default <see cref="ErrorOr"/> struct from being created. | ||
/// </summary> | ||
public ErrorOr() | ||
{ | ||
throw new InvalidOperationException("Default construction of ErrorOr<TValue> is invalid. Please use provided factory methods to instantiate."); | ||
} | ||
|
||
private ErrorOr(Error error) | ||
{ | ||
_errors = [error]; | ||
IsError = true; | ||
} | ||
|
||
private ErrorOr(List<Error> errors) | ||
{ | ||
_errors = errors; | ||
IsError = true; | ||
} | ||
|
||
private ErrorOr(TValue value) | ||
{ | ||
_value = value; | ||
IsError = false; | ||
} | ||
|
||
/// <summary> | ||
/// Gets a value indicating whether the state is error. | ||
/// </summary> | ||
[MemberNotNullWhen(true, nameof(_errors))] | ||
[MemberNotNullWhen(true, nameof(Errors))] | ||
[MemberNotNullWhen(false, nameof(Value))] | ||
[MemberNotNullWhen(false, nameof(_value))] | ||
public bool IsError { get; } | ||
|
||
/// <summary> | ||
/// Gets the list of errors. If the state is not error, the list will contain a single error representing the state. | ||
/// </summary> | ||
public List<Error> Errors => IsError ? _errors! : throw new InvalidOperationException("The Errors property cannot be accessed when no errors have been recorded. Check IsError before accessing Errors."); | ||
|
||
/// <summary> | ||
/// Gets the list of errors. If the state is not error, the list will be empty. | ||
/// </summary> | ||
public List<Error> ErrorsOrEmptyList => IsError ? _errors! : []; | ||
|
||
/// <summary> | ||
/// Gets the value. | ||
/// </summary> | ||
public TValue Value => _value!; | ||
|
||
/// <summary> | ||
/// Gets the first error. | ||
/// </summary> | ||
public Error FirstError | ||
{ | ||
get | ||
{ | ||
if (!IsError) | ||
{ | ||
throw new InvalidOperationException("The FirstError property cannot be accessed when no errors have been recorded. Check IsError before accessing FirstError."); | ||
} | ||
|
||
return _errors![0]; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Creates an <see cref="ErrorOr{TValue}"/> from a list of errors. | ||
/// </summary> | ||
public static ErrorOr<TValue> From(List<Error> errors) | ||
{ | ||
return errors; | ||
} | ||
} | ||
using System.Diagnostics.CodeAnalysis; | ||
|
||
namespace ErrorOr; | ||
|
||
/// <summary> | ||
/// A discriminated union of errors or a value. | ||
/// </summary> | ||
/// <typeparam name="TValue">The type of the underlying <see cref="Value"/>.</typeparam> | ||
public readonly partial record struct ErrorOr<TValue> : IErrorOr<TValue> | ||
{ | ||
private readonly TValue? _value = default; | ||
private readonly List<Error>? _errors = null; | ||
|
||
/// <summary> | ||
/// Prevents a default <see cref="ErrorOr"/> struct from being created. | ||
/// </summary> | ||
/// <exception cref="InvalidOperationException">Thrown when this method is called.</exception> | ||
public ErrorOr() | ||
{ | ||
throw new InvalidOperationException("Default construction of ErrorOr<TValue> is invalid. Please use provided factory methods to instantiate."); | ||
} | ||
|
||
private ErrorOr(Error error) | ||
{ | ||
_errors = [error]; | ||
} | ||
|
||
private ErrorOr(List<Error> errors) | ||
{ | ||
_errors = errors; | ||
} | ||
|
||
private ErrorOr(TValue value) | ||
{ | ||
_value = value; | ||
} | ||
|
||
/// <summary> | ||
/// Gets a value indicating whether the state is error. | ||
/// </summary> | ||
[MemberNotNullWhen(true, nameof(_errors))] | ||
[MemberNotNullWhen(true, nameof(Errors))] | ||
[MemberNotNullWhen(false, nameof(Value))] | ||
[MemberNotNullWhen(false, nameof(_value))] | ||
public bool IsError => _errors is not null; | ||
|
||
/// <summary> | ||
/// Gets the list of errors. If the state is not error, the list will contain a single error representing the state. | ||
/// </summary> | ||
/// <exception cref="InvalidOperationException">Thrown when no errors are present.</exception> | ||
public List<Error> Errors => IsError ? _errors : throw new InvalidOperationException("The Errors property cannot be accessed when no errors have been recorded. Check IsError before accessing Errors."); | ||
|
||
/// <summary> | ||
/// Gets the list of errors. If the state is not error, the list will be empty. | ||
/// </summary> | ||
public List<Error> ErrorsOrEmptyList => IsError ? _errors : EmptyErrors.Instance; | ||
|
||
/// <summary> | ||
/// Gets the value. | ||
/// </summary> | ||
/// <exception cref="InvalidOperationException">Thrown when no value is present.</exception> | ||
public TValue Value | ||
{ | ||
get | ||
{ | ||
if (IsError) | ||
{ | ||
throw new InvalidOperationException("The Value property cannot be accessed when errors have been recorded. Check IsError before accessing Value."); | ||
} | ||
|
||
return _value; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Gets the first error. | ||
/// </summary> | ||
/// <exception cref="InvalidOperationException">Thrown when no errors are present.</exception> | ||
public Error FirstError | ||
{ | ||
get | ||
{ | ||
if (!IsError) | ||
{ | ||
throw new InvalidOperationException("The FirstError property cannot be accessed when no errors have been recorded. Check IsError before accessing FirstError."); | ||
} | ||
|
||
return _errors[0]; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Creates an <see cref="ErrorOr{TValue}"/> from a list of errors. | ||
/// </summary> | ||
public static ErrorOr<TValue> From(List<Error> errors) | ||
{ | ||
return errors; | ||
} | ||
} |
Oops, something went wrong.