Skip to content

Commit

Permalink
Drop implicit operators
Browse files Browse the repository at this point in the history
  • Loading branch information
ahmedkamalio committed Oct 9, 2024
1 parent 3a9cdd1 commit 531e982
Show file tree
Hide file tree
Showing 6 changed files with 229 additions and 134 deletions.
36 changes: 15 additions & 21 deletions src/ResultObject/Result.Constructor.cs
Original file line number Diff line number Diff line change
@@ -1,40 +1,34 @@
namespace ResultObject;

/// <summary>
/// Helper class to create <see cref="Result{T}"/> instances with type inference.
/// Helper class to create <see cref="Result{TValue}"/> instances with type inference.
/// </summary>
public static class Result
{
/// <summary>
/// Creates a successful result with a default value of <see cref="object"/>.
/// </summary>
/// <returns>A successful <see cref="Result{T}"/> instance with a value of <c>null</c>.</returns>
public static Result<object> Success() => new(default, null);

/// <summary>
/// Creates a successful result with the specified value.
/// </summary>
/// <typeparam name="T">The type of the result value.</typeparam>
/// <param name="value">The value of the successful result.</param>
/// <returns>A successful <see cref="Result{T}"/> instance containing the provided value.</returns>
public static Result<T> Success<T>(T value) => new(value, null);
/// <typeparam name="TValue">The type of the result value.</typeparam>
/// <param name="value">The value associated with a successful result.</param>
/// <returns>A successful <see cref="Result{TValue}"/> instance containing the provided value.</returns>
public static Result<TValue> Success<TValue>(TValue value) => new(value, null);

/// <summary>
/// Creates a failed result with the specified error information.
/// </summary>
/// <typeparam name="T">The type of the result value.</typeparam>
/// <param name="error">A <see cref="ResultError"/> that contains detailed information about the failure.</param>
/// <returns>A failed <see cref="Result{T}"/> instance with no value and the provided error.</returns>
public static Result<T> Failure<T>(ResultError error) => new(default, error);
/// <typeparam name="TValue">The type of the result value, which will be <c>null</c> in case of failure.</typeparam>
/// <param name="error">A <see cref="ResultError"/> containing detailed information about the failure.</param>
/// <returns>A failed <see cref="Result{TValue}"/> instance with no value and the provided error.</returns>
public static Result<TValue> Failure<TValue>(ResultError error) => new(default, error);

/// <summary>
/// Creates a failed result with the specified error code, reason, and message.
/// </summary>
/// <typeparam name="T">The type of the result value.</typeparam>
/// <param name="code">The error code representing the type of failure.</param>
/// <param name="reason">A short description of the failure reason.</param>
/// <param name="message">A detailed message explaining the error.</param>
/// <returns>A failed <see cref="Result{T}"/> instance with no value and the provided error information.</returns>
public static Result<T> Failure<T>(string code, string reason, string message) =>
/// <typeparam name="TValue">The type of the result value, which will be <c>null</c> in case of failure.</typeparam>
/// <param name="code">A code representing the type of failure.</param>
/// <param name="reason">A brief description of the failure reason.</param>
/// <param name="message">A detailed message explaining the failure.</param>
/// <returns>A failed <see cref="Result{TValue}"/> instance with no value and an error containing the specified details.</returns>
public static Result<TValue> Failure<TValue>(string code, string reason, string message) =>
new(default, new ResultError(code, reason, message));
}
27 changes: 0 additions & 27 deletions src/ResultObject/Result.Operator.cs

This file was deleted.

96 changes: 54 additions & 42 deletions src/ResultObject/Result.cs
Original file line number Diff line number Diff line change
@@ -1,70 +1,82 @@
namespace ResultObject;

/// <summary>
/// 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.
/// </summary>
/// <typeparam name="T">The type of the value in case of a successful result.</typeparam>
public partial class Result<T>(T? value, ResultError? error)
/// <typeparam name="TValue">The type of the value associated with a successful result.</typeparam>
public class Result<TValue>(TValue? value, ResultError? error)
{
/// <summary>
/// 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).
/// </summary>
public bool IsSuccess => Error is null;
public bool IsSuccess { get; } = error == null;

/// <summary>
/// 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).
/// </summary>
public bool IsFailure => Error is not null;
public bool IsFailure { get; } = error != null;

/// <summary>
/// Gets the value associated with a successful result, or <c>null</c> 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.
/// </summary>
public T? Value { get; } = value;
/// <exception cref="InvalidOperationException">
/// Thrown when trying to access the value of a failed result, or when the result is successful but the value is null.
/// </exception>
public TValue Value
{
get
{
if (IsFailure)
{
throw new InvalidOperationException("Cannot retrieve value from a failed result.");
}

/// <summary>
/// Gets the error details associated with a failed result, or <c>null</c> if the result is successful.
/// </summary>
public ResultError? Error { get; } = error;
if (value == null)
{
throw new InvalidOperationException("Value is null despite the operation being successful.");
}

return value;
}
}

/// <summary>
/// <para>
/// Creates a new <c>Result</c> instance representing the same failure as this result,
/// but with the value type cast to a different type.
/// </para>
/// <para>
/// The new result will contain the same error information,
/// but the value will be set to the default value of the new type.
/// </para>
/// Gets the value if the result is successful, or the default value for the type <typeparamref name="TValue"/> if the result is a failure.
/// </summary>
/// <typeparam name="TValue">The new type of the value in the returned <c>Result</c>.</typeparam>
/// <returns>A new <c>Result</c> instance representing the failure, with the value type changed.</returns>
public Result<TValue> ToFailureResult<TValue>() => new(default, Error);
public TValue? ValueOrDefault => value;

/// <summary>
/// Retrieves the value from the <see cref="Result{T}"/>, 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.
/// </summary>
/// <remarks>
/// 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 <see cref="InvalidOperationException"/> is thrown, ensuring that invalid states are not silently handled.
/// <br />
/// This is recommended for business-critical logic where you need strict guarantees that the value is present and valid.
/// </remarks>
/// <exception cref="InvalidOperationException">
/// 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.
/// </exception>
/// <returns>The value of the result if successful and non-null.</returns>
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;
}

/// <summary>
/// Gets the error if the result is a failure, or null if the result is successful.
/// </summary>
public ResultError? ErrorOrDefault => error;

/// <summary>
/// Creates a new <c>Result</c> 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.
/// </summary>
/// <typeparam name="T">The new type for the value in the returned <c>Result</c>.</typeparam>
/// <returns>A new <c>Result</c> instance representing the failure, with the value type changed to <typeparamref name="T"/>.</returns>
public Result<T> ToFailureResult<T>() => new(default, Error);
}
16 changes: 14 additions & 2 deletions src/ResultObject/ResultError.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
namespace ResultObject;

/// <summary>
/// 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.
/// </summary>
public record ResultError(string Code, string Reason, string Message);
public record ResultError(string Code, string Reason, string Message)
{
/// <summary>
/// Returns a string that represents the current error, providing a summary with the error code, reason, and message.
/// </summary>
/// <returns>
/// A string that contains the error code, reason, and message for this <see cref="ResultError"/>.
/// </returns>
public override string ToString()
{
return $"Code: {Code}, Reason: {Reason}, Message: {Message}";
}
}
2 changes: 1 addition & 1 deletion src/ResultObject/ResultObject.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

<!-- NuGet Package Metadata -->
<PackageId>ResultObject</PackageId>
<Version>1.0.1</Version>
<Version>1.0.2</Version>
<Authors>Ahmed Kamal</Authors>
<Description>A simple result object for DotNet.</Description>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
Expand Down
Loading

0 comments on commit 531e982

Please sign in to comment.