diff --git a/src/ResultObject/Result.Constructor.cs b/src/ResultObject/Result.Constructor.cs
index 78150a4..8596c50 100755
--- a/src/ResultObject/Result.Constructor.cs
+++ b/src/ResultObject/Result.Constructor.cs
@@ -1,40 +1,34 @@
namespace ResultObject;
///
-/// Helper class to create instances with type inference.
+/// Helper class to create instances with type inference.
///
public static class Result
{
- ///
- /// Creates a successful result with a default value of .
- ///
- /// A successful instance with a value of null .
- public static Result Success() => new(default, null);
-
///
/// Creates a successful result with the specified value.
///
- /// The type of the result value.
- /// The value of the successful result.
- /// A successful instance containing the provided value.
- public static Result Success(T value) => new(value, null);
+ /// The type of the result value.
+ /// The value associated with a successful result.
+ /// A successful instance containing the provided value.
+ public static Result Success(TValue value) => new(value, null);
///
/// Creates a failed result with the specified error information.
///
- /// The type of the result value.
- /// A that contains detailed information about the failure.
- /// A failed instance with no value and the provided error.
- public static Result Failure(ResultError error) => new(default, error);
+ /// The type of the result value, which will be null in case of failure.
+ /// A containing detailed information about the failure.
+ /// A failed instance with no value and the provided error.
+ public static Result Failure(ResultError error) => new(default, error);
///
/// Creates a failed result with the specified error code, reason, and message.
///
- /// The type of the result value.
- /// The error code representing the type of failure.
- /// A short description of the failure reason.
- /// A detailed message explaining the error.
- /// A failed instance with no value and the provided error information.
- public static Result Failure(string code, string reason, string message) =>
+ /// The type of the result value, which will be null in case of failure.
+ /// A code representing the type of failure.
+ /// A brief description of the failure reason.
+ /// A detailed message explaining the failure.
+ /// A failed instance with no value and an error containing the specified details.
+ public static Result Failure(string code, string reason, string message) =>
new(default, new ResultError(code, reason, message));
}
\ No newline at end of file
diff --git a/src/ResultObject/Result.Operator.cs b/src/ResultObject/Result.Operator.cs
deleted file mode 100755
index 93d0f5a..0000000
--- a/src/ResultObject/Result.Operator.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-namespace ResultObject;
-
-///
-/// Helper class encapsulating the implicit operators of the Result class.
-///
-public partial class Result
-{
- ///
- /// Implicitly converts a to its value.
- ///
- ///
- /// This conversion will return the value if the result is successful and the value is not null.
- /// If the result is unsuccessful or the value is null, it will return the default value for the type (e.g., null for reference types, 0 for integers).
- ///
- /// This is useful in scenarios where you want a convenient way to retrieve the result's value without explicit null-checking or error handling, such as non-critical operations where a default value is acceptable.
- ///
- /// The result object to convert.
- /// The value of the result if successful and not null; otherwise, the default value of .
- public static implicit operator T?(Result result) =>
- result.IsFailure || result.Value is null ? default : result.Value;
-
- ///
- /// Implicitly converts the value to a successful result.
- ///
- /// The value to convert.
- public static implicit operator Result(T value) => new(value, null);
-}
\ No newline at end of file
diff --git a/src/ResultObject/Result.cs b/src/ResultObject/Result.cs
index 9b7b18c..6991993 100755
--- a/src/ResultObject/Result.cs
+++ b/src/ResultObject/Result.cs
@@ -1,70 +1,82 @@
namespace ResultObject;
///
-/// Represents the result of an operation, which can either be a success or a failure.
+/// Represents the result of an operation, which can either be a success with a value or a failure with an error.
///
-/// The type of the value in case of a successful result.
-public partial class Result(T? value, ResultError? error)
+/// The type of the value associated with a successful result.
+public class Result(TValue? value, ResultError? error)
{
///
- /// Gets a value indicating whether the result is successful.
+ /// Gets a value indicating whether the result represents a successful outcome (i.e., no error occurred).
///
- public bool IsSuccess => Error is null;
+ public bool IsSuccess { get; } = error == null;
///
- /// Gets a value indicating whether the result is a failure.
+ /// Gets a value indicating whether the result represents a failure (i.e., an error occurred).
///
- public bool IsFailure => Error is not null;
+ public bool IsFailure { get; } = error != null;
///
- /// Gets the value associated with a successful result, or null if the result is a failure.
+ /// Gets the value of a successful result.
+ /// Throws an exception if the result represents a failure or if the value is null even though the result is marked as successful.
///
- public T? Value { get; } = value;
+ ///
+ /// Thrown when trying to access the value of a failed result, or when the result is successful but the value is null.
+ ///
+ public TValue Value
+ {
+ get
+ {
+ if (IsFailure)
+ {
+ throw new InvalidOperationException("Cannot retrieve value from a failed result.");
+ }
- ///
- /// Gets the error details associated with a failed result, or null if the result is successful.
- ///
- public ResultError? Error { get; } = error;
+ if (value == null)
+ {
+ throw new InvalidOperationException("Value is null despite the operation being successful.");
+ }
+
+ return value;
+ }
+ }
///
- ///
- /// Creates a new Result instance representing the same failure as this result,
- /// but with the value type cast to a different type.
- ///
- ///
- /// The new result will contain the same error information,
- /// but the value will be set to the default value of the new type.
- ///
+ /// Gets the value if the result is successful, or the default value for the type if the result is a failure.
///
- /// The new type of the value in the returned Result .
- /// A new Result instance representing the failure, with the value type changed.
- public Result ToFailureResult() => new(default, Error);
+ public TValue? ValueOrDefault => value;
///
- /// Retrieves the value from the , throwing an exception if the result is unsuccessful or the value is null.
+ /// Gets the error associated with a failed result.
+ /// Throws an exception if accessed on a successful result.
///
- ///
- /// This method should be used in scenarios where the result's value is critical to the operation, and you expect it to be non-null.
- /// If the result is a failure or the value is null, an is thrown, ensuring that invalid states are not silently handled.
- ///
- /// This is recommended for business-critical logic where you need strict guarantees that the value is present and valid.
- ///
///
- /// Thrown if the result is a failure or if the value is null in a successful result.
+ /// Thrown when trying to access the error of a successful result.
///
- /// The value of the result if successful and non-null.
- public T MustGetValue()
+ public ResultError Error
{
- if (IsFailure)
+ get
{
- throw new InvalidOperationException("Cannot retrieve value from a failed result.");
- }
+ if (IsSuccess)
+ {
+ throw new InvalidOperationException("Cannot retrieve error from a successful result.");
+ }
- if (Value is null)
- {
- throw new InvalidOperationException("Result was successful but the value is null.");
+ return error!;
}
-
- return Value;
}
+
+ ///
+ /// Gets the error if the result is a failure, or null if the result is successful.
+ ///
+ public ResultError? ErrorOrDefault => error;
+
+ ///
+ /// Creates a new Result instance representing the same failure as this result,
+ /// but with the value type cast to a different type.
+ /// The new result will contain the same error, while the value will be set to the default value of the new type.
+ ///
+ /// The new type for the value in the returned Result .
+ /// A new Result instance representing the failure, with the value type changed to .
+ public Result ToFailureResult() => new(default, Error);
}
\ No newline at end of file
diff --git a/src/ResultObject/ResultError.cs b/src/ResultObject/ResultError.cs
index fab3f1c..cb0c5b2 100755
--- a/src/ResultObject/ResultError.cs
+++ b/src/ResultObject/ResultError.cs
@@ -1,6 +1,18 @@
namespace ResultObject;
///
-/// Represents the details of an result error.
+/// Represents the details of a result error, including an error code, a reason for the failure, and a detailed message.
///
-public record ResultError(string Code, string Reason, string Message);
\ No newline at end of file
+public record ResultError(string Code, string Reason, string Message)
+{
+ ///
+ /// Returns a string that represents the current error, providing a summary with the error code, reason, and message.
+ ///
+ ///
+ /// A string that contains the error code, reason, and message for this .
+ ///
+ public override string ToString()
+ {
+ return $"Code: {Code}, Reason: {Reason}, Message: {Message}";
+ }
+}
\ No newline at end of file
diff --git a/src/ResultObject/ResultObject.csproj b/src/ResultObject/ResultObject.csproj
index 837e052..eac5324 100755
--- a/src/ResultObject/ResultObject.csproj
+++ b/src/ResultObject/ResultObject.csproj
@@ -7,7 +7,7 @@
ResultObject
- 1.0.1
+ 1.0.2
Ahmed Kamal
A simple result object for DotNet.
MIT
diff --git a/test/ResultObject.Tests/ResultTests.cs b/test/ResultObject.Tests/ResultTests.cs
index 1063ff1..de23a4e 100755
--- a/test/ResultObject.Tests/ResultTests.cs
+++ b/test/ResultObject.Tests/ResultTests.cs
@@ -3,79 +3,183 @@ namespace ResultObject.Tests;
public class ResultTests
{
[Fact]
- public void Success_ShouldCreateSuccessfulResult()
+ public void SuccessResult_IsSuccess_ShouldBeTrue()
{
- const int value = 42;
-
- var result = Result.Success(value);
+ // Arrange
+ var result = Result.Success("Test Value");
+ // Act & Assert
Assert.True(result.IsSuccess);
Assert.False(result.IsFailure);
- Assert.Equal(value, result.Value);
- Assert.Null(result.Error);
}
[Fact]
- public void Failure_ShouldCreateFailedResult_WithError()
+ public void SuccessResult_Value_ShouldReturnCorrectValue()
{
- var error = new ResultError("HTTP_500", "InternalError", "Something went wrong");
+ // Arrange
+ var result = Result.Success("Test Value");
- var result = Result.Failure(error);
+ // Act
+ var value = result.Value;
- Assert.False(result.IsSuccess);
- Assert.True(result.IsFailure);
- Assert.Null(result.Value);
- Assert.Equal(error, result.Error);
+ // Assert
+ Assert.Equal("Test Value", value);
}
[Fact]
- public void Failure_ShouldCreateFailedResult_WithErrorDetails()
+ public void SuccessResult_ValueOrDefault_ShouldReturnCorrectValue()
{
- const string code = "HTTP_404";
- const string reason = "NotFound";
- const string message = "The item was not found";
+ // Arrange
+ var result = Result.Success("Test Value");
- var result = Result.Failure(code, reason, message);
+ // Act
+ var valueOrDefault = result.ValueOrDefault;
- Assert.False(result.IsSuccess);
+ // Assert
+ Assert.Equal("Test Value", valueOrDefault);
+ }
+
+ [Fact]
+ public void SuccessResult_Error_ShouldThrowInvalidOperationException()
+ {
+ // Arrange
+ var result = Result.Success("Test Value");
+
+ // Act & Assert
+ Assert.Throws(() => result.Error);
+ }
+
+ [Fact]
+ public void SuccessResult_ErrorOrDefault_ShouldReturnNull()
+ {
+ // Arrange
+ var result = Result.Success("Test Value");
+
+ // Act
+ var errorOrDefault = result.ErrorOrDefault;
+
+ // Assert
+ Assert.Null(errorOrDefault);
+ }
+
+ [Fact]
+ public void FailureResult_IsFailure_ShouldBeTrue()
+ {
+ // Arrange
+ var error = new ResultError("404", "NotFound", "The item was not found.");
+ var result = Result.Failure(error);
+
+ // Act & Assert
Assert.True(result.IsFailure);
- Assert.NotNull(result.Error);
- Assert.Equal(default, result.Value);
- Assert.Equal(code, result.Error?.Code);
- Assert.Equal(reason, result.Error?.Reason);
- Assert.Equal(message, result.Error?.Message);
+ Assert.False(result.IsSuccess);
+ }
+
+ [Fact]
+ public void FailureResult_Value_ShouldThrowInvalidOperationException()
+ {
+ // Arrange
+ var error = new ResultError("404", "NotFound", "The item was not found.");
+ var result = Result.Failure(error);
+
+ // Act & Assert
+ Assert.Throws(() => result.Value);
}
[Fact]
- public void ImplicitConversionToValue_ShouldReturnCorrectValue_ForSuccessfulResult()
+ public void FailureResult_ValueOrDefault_ShouldReturnDefaultValue()
{
- const int value = 99;
- var result = Result.Success(value);
+ // Arrange
+ var error = new ResultError("404", "NotFound", "The item was not found.");
+ var result = Result.Failure(error);
- int actualValue = result;
+ // Act
+ var valueOrDefault = result.ValueOrDefault;
- Assert.Equal(value, actualValue);
+ // Assert
+ Assert.Null(valueOrDefault);
}
[Fact]
- public void ImplicitConversionToValue_ShouldReturnDefaultValue_ForFailedResult()
+ public void FailureResult_Error_ShouldReturnCorrectError()
{
- var error = new ResultError("HTTP_500", "InternalError", "Something went wrong");
- int result = Result.Failure(error);
+ // Arrange
+ var error = new ResultError("404", "NotFound", "The item was not found.");
+ var result = Result.Failure(error);
- Assert.Equal(default, result);
+ // Act
+ var resultError = result.Error;
+
+ // Assert
+ Assert.Equal("404", resultError.Code);
+ Assert.Equal("NotFound", resultError.Reason);
+ Assert.Equal("The item was not found.", resultError.Message);
}
[Fact]
- public void ImplicitConversionFromValue_ShouldCreateSuccessfulResult()
+ public void FailureResult_ErrorOrDefault_ShouldReturnCorrectError()
{
- const int value = 77;
+ // Arrange
+ var error = new ResultError("404", "NotFound", "The item was not found.");
+ var result = Result.Failure(error);
- Result result = value;
+ // Act
+ var errorOrDefault = result.ErrorOrDefault;
- Assert.True(result.IsSuccess);
- Assert.False(result.IsFailure);
- Assert.Equal(value, result.Value);
- Assert.Null(result.Error);
+ // Assert
+ Assert.Equal(error, errorOrDefault);
+ }
+
+ [Fact]
+ public void FailureResult_WithErrorCode_ShouldReturnCorrectError()
+ {
+ // Arrange
+ var result = Result.Failure("500", "InternalError", "An unexpected error occurred.");
+
+ // Act
+ var error = result.Error;
+
+ // Assert
+ Assert.Equal("500", error.Code);
+ Assert.Equal("InternalError", error.Reason);
+ Assert.Equal("An unexpected error occurred.", error.Message);
+ }
+
+ [Fact]
+ public void ToFailureResult_ShouldConvertToNewFailureResult()
+ {
+ // Arrange
+ var error = new ResultError("404", "NotFound", "The item was not found.");
+ var result = Result.Failure(error);
+
+ // Act
+ var newResult = result.ToFailureResult();
+
+ // Assert
+ Assert.True(newResult.IsFailure);
+ Assert.Equal(error, newResult.Error);
+ Assert.Equal(default, newResult.ValueOrDefault);
+ }
+
+ [Fact]
+ public void ResultError_ToString_ShouldReturnFormattedString()
+ {
+ // Arrange
+ var error = new ResultError("500", "InternalError", "An unexpected error occurred.");
+
+ // Act
+ var resultString = error.ToString();
+
+ // Assert
+ Assert.Equal("Code: 500, Reason: InternalError, Message: An unexpected error occurred.", resultString);
+ }
+
+ [Fact]
+ public void SuccessResult_WithNullValue_ShouldThrowInvalidOperationException()
+ {
+ // Arrange
+ var result = Result.Success(null);
+
+ // Act & Assert
+ Assert.Throws(() => result.Value);
}
-}
+}
\ No newline at end of file