Zentient Results Api Reference Inspection Querying - ulfbou/Zentient.Results GitHub Wiki

🔍 Inspection & Querying


After an operation returns an IResult or IResult<T>, you'll need to inspect its state to determine whether it was successful or a failure, access its value (if successful), or retrieve error details (if failed). Zentient.Results provides straightforward properties and utility methods for this purpose, allowing you to query the result's state and data effectively.

Basic State Checks

These properties provide the fundamental way to determine the outcome of an operation.

IsSuccess

  • Signature: bool IsSuccess { get; } (on IResult and IResult<T>)
  • Purpose: Indicates whether the operation completed successfully. This is the primary way to check for a positive outcome.
  • Example:
    using Zentient.Results;
    
    IResult<int> divisionResult = Divide(10, 2);
    
    if (divisionResult.IsSuccess)
    {
        Console.WriteLine($"Division was successful: {divisionResult.Value}");
    }
    else
    {
        Console.WriteLine($"Division failed.");
    }

IsFailure

  • Signature: bool IsFailure { get; } (on IResult and IResult<T>)
  • Purpose: Indicates whether the operation failed. This is the logical opposite of IsSuccess.
  • Example:
    using Zentient.Results;
    
    IResult saveResult = SaveData("invalid data");
    
    if (saveResult.IsFailure)
    {
        Console.WriteLine($"Data save failed: {saveResult.Error}");
    }
    else
    {
        Console.WriteLine($"Data saved successfully.");
    }

Value Access

When dealing with IResult<T>, you'll need to access the encapsulated value. Zentient.Results offers several ways to do this, ranging from direct (but potentially unsafe) property access to robust methods that handle failure scenarios gracefully.

Value

  • Signature: T? Value { get; } (on IResult<T>)
  • Purpose: Retrieves the successful value of type T.
  • Important: This property will return default(T) (e.g., null for reference types, 0 for int) if IsFailure is true. Always check IsSuccess before accessing Value to avoid unexpected null references or default values in failure scenarios.
  • Example:
    using Zentient.Results;
    
    IResult<User> userResult = GetUserById(123);
    
    if (userResult.IsSuccess)
    {
        User user = userResult.Value; // Safe access after checking IsSuccess
        Console.WriteLine($"User Name: {user.Name}");
    }
    else
    {
        Console.WriteLine($"Could not retrieve user.");
    }

GetValueOrDefault()

  • Signature:
    • public T GetValueOrDefault(T fallback) (on IResult<T>)
    • public T GetValueOrDefault() (on IResult<T>, returns default(T) on failure)
  • Purpose: Provides a safe way to get the successful value or return a specified fallback value if the result is a failure.
  • Parameters:
    • fallback: The value to return if the result is a failure.
  • Example:
    using Zentient.Results;
    
    IResult<int> parseResult = ParseNumber("abc"); // Assume this fails
    
    int parsedNumber = parseResult.GetValueOrDefault(-1); // Returns -1 if parseResult is a failure
    Console.WriteLine($"Parsed number: {parsedNumber}"); // Output: -1
    
    IResult<string> nameResult = GetUserName(456); // Assume this succeeds
    string userName = nameResult.GetValueOrDefault("Guest"); // Returns "Alice" if successful, "Guest" if failed
    Console.WriteLine($"User name: {userName}");

GetValueOrThrow()

  • Signature:
    • public T GetValueOrThrow() (on IResult<T>)
    • public T GetValueOrThrow(string message) (on IResult<T>)
    • public T GetValueOrThrow(Func<Exception> exceptionFactory) (on IResult<T>)
  • Purpose: Retrieves the value if the result is successful, otherwise throws an exception. This is useful in contexts where a failure at this point indicates a critical error that should halt execution, or when you've already handled the failure path and expect success.
  • Throws:
    • InvalidOperationException if IsFailure is true.
    • A custom exception type if exceptionFactory is provided.
  • Example:
    using Zentient.Results;
    
    public User GetUserOrThrow(int userId)
    {
        IResult<User> userResult = GetUserById(userId);
        return userResult.GetValueOrThrow($"Failed to get user with ID {userId}"); // Throws InvalidOperationException on failure
    }
    
    try
    {
        User user = GetUserOrThrow(999); // Assume this fails
        Console.WriteLine($"User: {user.Name}");
    }
    catch (InvalidOperationException ex)
    {
        Console.WriteLine($"Error: {ex.Message}"); // Output: Error: Failed to get user with ID 999
    }

Error Access

When an IResult or IResult<T> is a failure, you'll need to retrieve the details about what went wrong.

Errors

  • Signature: IReadOnlyList<ErrorInfo> Errors { get; } (on IResult and IResult<T>)
  • Purpose: Provides access to a collection of structured error information. This list will be empty if IsSuccess is true.
  • See Also: ErrorInfo Struct
  • Example:
    using Zentient.Results;
    using System.Linq;
    
    IResult registrationResult = RegisterUser("test", "bad_password"); // Assume this returns multiple validation errors
    
    if (registrationResult.IsFailure)
    {
        Console.WriteLine("Registration Errors:");
        foreach (var error in registrationResult.Errors)
        {
            Console.WriteLine($"- {error.Code}: {error.Message}");
        }
    }

Error

  • Signature: string? Error { get; } (on IResult and IResult<T>)
  • Purpose: A convenience property that returns the Message of the first ErrorInfo in the Errors list. If the Errors list is empty, it returns null.
  • Example:
    using Zentient.Results;
    
    IResult loginResult = Authenticate("user", "wrong_pass"); // Assume this fails with one error
    
    if (loginResult.IsFailure)
    {
        Console.WriteLine($"Login failed: {loginResult.Error}"); // Output: Login failed: Invalid credentials.
    }

Status Access

The Status property provides a standardized way to understand the overall semantic outcome of the operation, often mapping to HTTP status codes.

Status

  • Signature: IResultStatus Status { get; } (on IResult and IResult<T>)
  • Purpose: Represents the overall semantic status of the operation (e.g., Ok, NotFound, BadRequest).
  • See Also: IResultStatus Interface, ResultStatuses Static Class
  • Example:
    using Zentient.Results;
    
    IResult deleteResult = DeleteResource("nonexistent-id"); // Assume this returns NotFound
    
    if (deleteResult.Status == ResultStatuses.NotFound)
    {
        Console.WriteLine("Resource was not found for deletion.");
    }
    else if (deleteResult.Status.IsSuccess)
    {
        Console.WriteLine("Resource deleted successfully.");
    }
    else
    {
        Console.WriteLine($"Operation failed with status: {deleteResult.Status.Code} ({deleteResult.Status.Description})");
    }

Utility Methods (Review)

While Map, Bind, Then, OnSuccess, OnFailure, and Match are powerful inspection and transformation tools, they are primarily covered in the Functional Utilities section due to their role in chaining and composition. However, their purpose often involves inspecting the result's state and acting upon it.

  • Map<T, U>(...): If IsSuccess, transforms Value to a new type U.
  • Bind<T, U>(...): If IsSuccess, passes Value to a function that returns a new IResult<U>.
  • Then<T>(...): If IsSuccess, passes Value (or just proceeds for non-generic) to a function returning a non-generic IResult.
  • OnSuccess(...) / Tap(...): If IsSuccess, performs a side-effecting action with Value.
  • OnFailure(...): If IsFailure, performs a side-effecting action with Errors.
  • Match(...): Forces handling of both IsSuccess and IsFailure paths, producing a unified output.

These methods embody robust inspection and conditional execution, making your code cleaner and more resilient.

⚠️ **GitHub.com Fallback** ⚠️