Skip to content

Commit

Permalink
Made the Error a class rather than a struct to support inner errors
Browse files Browse the repository at this point in the history
  • Loading branch information
matsakiv committed Aug 29, 2024
1 parent db1d4f0 commit d927fc6
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 102 deletions.
48 changes: 36 additions & 12 deletions Incendium.Result/Error.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
namespace Incendium
{
/// <summary>
/// Represents error struct that contains code, message and exception
/// Represents error type that contains code, message, exception and inner error
/// </summary>
/// <param name="code">Error code</param>
/// <param name="message">Error message</param>
/// <param name="exception">Inner exception</param>
public readonly struct Error(int code, string? message, Exception? exception)
/// <param name="innerError">Inner error</param>
public class Error(int code, string? message, Exception? exception, Error? innerError)
{
/// <summary>
/// Gets error code
Expand All @@ -22,51 +23,74 @@ public readonly struct Error(int code, string? message, Exception? exception)
/// Gets inner exception
/// </summary>
public Exception? Exception { get; init; } = exception;
/// <summary>
/// Gets inner error
/// </summary>
public Error? InnerError { get; init; } = innerError;

/// <summary>
/// Initialize a new instance of the error
/// </summary>
public Error()
: this(0, message: null, exception: null, innerError: null)
{
}

/// <summary>
/// Initialize a new instance of the error struct with a specified error code
/// Initialize a new instance of the error with a specified error code
/// </summary>
/// <param name="code">Error code</param>
public Error(int code)
: this(code, message: null, exception: null)
: this(code, message: null, exception: null, innerError: null)
{
}

/// <summary>
/// Initialize a new instance of the error struct with a specified error message
/// Initialize a new instance of the error with a specified error message
/// </summary>
/// <param name="message">Error message</param>
public Error(string message)
: this(code: 0, message: message, exception: null)
: this(code: 0, message: message, exception: null, innerError: null)
{
}

/// <summary>
/// Initialize a new instance of the error struct with a specified inner exception
/// Initialize a new instance of the error with a specified inner exception
/// </summary>
/// <param name="exception">Inner exception</param>
public Error(Exception exception)
: this(code: 0, message: null, exception: exception)
: this(code: 0, message: null, exception: exception, innerError: null)
{
}

/// <summary>
/// Initialize a new instance of the error struct with a specified error code and message
/// Initialize a new instance of the error with a specified error code and message
/// </summary>
/// <param name="code">Error code</param>
/// <param name="message">Error message</param>
public Error(int code, string message)
: this(code, message, exception: null)
: this(code, message, exception: null, innerError: null)
{
}

/// <summary>
/// Initialize a new instance of the error struct with a specified error message and inner exception
/// Initialize a new instance of the error with a specified error message and inner exception
/// </summary>
/// <param name="message">Error message</param>
/// <param name="exception">Inner exception</param>
public Error(string message, Exception exception)
: this(code: 0, message, exception: exception)
: this(code: 0, message, exception: exception, innerError: null)
{
}

/// <summary>
/// Initialize a new instance of the error with a specified error code, message and inner error
/// </summary>
/// <param name="code">Error code</param>
/// <param name="message">Error message</param>
/// <param name="error">Inner error</param>
public Error(int code, string message, Error? error)
: this(code, message, exception: null, innerError: error)
{
}
}
Expand Down
26 changes: 0 additions & 26 deletions Incendium.Result/Extensions/ErrorExtensions.cs

This file was deleted.

2 changes: 1 addition & 1 deletion Incendium.Result/Incendium.Result.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<Title>Incendium.Result</Title>
<Authors>mativ</Authors>
<Description>Provides a Result&lt;T&gt; type that allows a method to return both a value and an error in Rust style without exceptions</Description>
<Version>1.0.2</Version>
<Version>1.0.3</Version>
<Copyright>Copyright © Igor Matsak</Copyright>
</PropertyGroup>

Expand Down
17 changes: 0 additions & 17 deletions Incendium.Result/NullableResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,6 @@ public NullableResult(T? value)
/// </summary>
/// <param name="error">Error</param>
public NullableResult(Error error)
{
Error = error;
}

/// <summary>
/// Initialize a result instance from the non-null error value with nullable type
/// </summary>
/// <param name="error">Non-null error value with nullable type</param>
/// <exception cref="ArgumentNullException"></exception>
public NullableResult(Error? error)
{
Error = error ?? throw new ArgumentNullException(nameof(error));
}
Expand All @@ -55,13 +45,6 @@ public NullableResult(Error? error)
/// </summary>
/// <param name="error">Error</param>
public static implicit operator NullableResult<T>(Error error) => new(error);
/// <summary>
/// Initialize a result instance from the non-null error value with nullable type
/// </summary>
/// <param name="error">Non-null error value with nullable type</param>
/// <exception cref="ArgumentNullException"></exception>
public static implicit operator NullableResult<T>(Error? error) => new(error);

/// <summary>
/// Deconstruct struct to success value and error value
/// </summary>
Expand Down
34 changes: 20 additions & 14 deletions Incendium.Result/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ if (error != null) {
log.LogError(
error.Exception(),
"Error with code {@code} and message {@message}",
error.Code(),
error.Message());
error.Code,
error.Message);
}
```

Expand All @@ -53,12 +53,15 @@ The `Result<T>` instance can be created only from non-null value or from non-nul
```cs
public Result<Foo> GetFooAsync() {
return new Foo(); // correct
return new Error(); // correct
return (Foo)null; // incorrect, CS8600 warning, throws ArgumentNullException
return (Foo)null!; // incorrect, throws ArgumentNullException
return (Foo?)null; // incorrect, CS8604 warning, throws ArgumentNullException
return (Foo?)null!; // incorrect, throws ArgumentNullException
return (Error?)null; // incorrect, throws ArgumentNullException
// return new Error(); // correct
// return (Foo)null; // incorrect, CS8600 and CS8625 warnings, throws ArgumentNullException
// return (Foo)null!; // incorrect, throws ArgumentNullException
// return (Foo?)null; // incorrect, CS8625 warning, throws ArgumentNullException
// return (Foo?)null!; // incorrect, throws ArgumentNullException
// return (Error)null; // incorrect, CS8600 and CS8625 warnings, throws ArgumentNullException
// return (Error)null!; // incorrect, throws ArgumentNullException
// return (Error?)null; // incorrect, CS8625 warning, throws ArgumentNullException
// return (Error?)null!; // incorrect, throws ArgumentNullException
}
```

Expand All @@ -67,12 +70,15 @@ public Result<Foo> GetFooAsync() {
If the successful return value can be null, you must use the `NullableResult<T>` type:

```cs
public async NullableResult<Foo> GetFooAsync() {
public NullableResult<Foo> GetFooAsync() {
return new Foo(); // correct
return new Error(); // correct
return (Foo?)null; // correct
return (Foo)null; // correct with CS8600 warning
return (Foo)null!; // correct
return (Error?)null; // incorrect, throws ArgumentNullException
// return new Error(); // correct
// return (Foo?)null; // correct
// return (Foo)null; // correct with CS8600 warning
// return (Foo)null!; // correct
// return (Error)null; // incorrect, CS8600 and CS8625 warnings, throws ArgumentNullException
// return (Error)null!; // incorrect, throws ArgumentNullException
// return (Error?)null; // incorrect, CS8625 warning, throws ArgumentNullException
// return (Error?)null!; // incorrect, throws ArgumentNullException
}
```
18 changes: 0 additions & 18 deletions Incendium.Result/Result.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,6 @@ public Result(T value)
/// </summary>
/// <param name="error">Error</param>
public Result(Error error)
{
Value = default!;
Error = error;
}

/// <summary>
/// Initialize a result instance from the non-null error value with nullable type
/// </summary>
/// <param name="error">Non-null error value with nullable type</param>
/// <exception cref="ArgumentNullException"></exception>
public Result(Error? error)
{
Value = default!;
Error = error ?? throw new ArgumentNullException(nameof(error));
Expand All @@ -62,13 +51,6 @@ public Result(Error? error)
/// </summary>
/// <param name="error">Error</param>
public static implicit operator Result<T>(Error error) => new(error);
/// <summary>
/// Initialize a result instance from the non-null error value with nullable type
/// </summary>
/// <param name="error">Non-null error value with nullable type</param>
/// <exception cref="ArgumentNullException"></exception>
public static implicit operator Result<T>(Error? error) => new(error);

/// <summary>
/// Deconstruct struct to success value and error value
/// </summary>
Expand Down
22 changes: 8 additions & 14 deletions Incendium.Tests/Result/ResultsTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
using Incendium.Extensions;

namespace Incendium.Result
{
public class ResultsTests
Expand Down Expand Up @@ -27,12 +25,12 @@ public void Test_Result_FailCreateFromNullErrorValue()
// asserts
Assert.Throws<ArgumentNullException>(() =>
{
var result = new Result<TestObject>((Error?)null);
var result = new Result<TestObject>((Error)null!);
});

Assert.Throws<ArgumentNullException>(() =>
{
Result<TestObject> result = (Error?)null;
Result<TestObject> result = (Error)null!;
});
}

Expand All @@ -58,10 +56,8 @@ public void Test_Result_DeconstructWhenError()
// asserts
Assert.Null(result);
Assert.NotNull(error);
Assert.Equal(100, error.Value.Code);
Assert.Equal("Error", error.Value.Message);
Assert.Equal(100, error.Code());
Assert.Equal("Error", error.Message());
Assert.Equal(100, error.Code);
Assert.Equal("Error", error.Message);
}

[Fact]
Expand All @@ -84,12 +80,12 @@ public void Test_NullableResult_FailCreateFromNullErrorValue()
// asserts
Assert.Throws<ArgumentNullException>(() =>
{
var result = new NullableResult<TestObject>((Error?)null);
var result = new NullableResult<TestObject>((Error)null!);
});

Assert.Throws<ArgumentNullException>(() =>
{
NullableResult<TestObject> result = (Error?)null;
NullableResult<TestObject> result = (Error)null!;
});
}

Expand All @@ -115,10 +111,8 @@ public void Test_NullableResult_DeconstructWhenError()
// asserts
Assert.Null(result);
Assert.NotNull(error);
Assert.Equal(100, error.Value.Code);
Assert.Equal("Error", error.Value.Message);
Assert.Equal(100, error.Code());
Assert.Equal("Error", error.Message());
Assert.Equal(100, error.Code);
Assert.Equal("Error", error.Message);
}

private static Result<TestObject> GetResult(bool withError)
Expand Down

0 comments on commit d927fc6

Please sign in to comment.