Previous IaC (Infrastructure as Code) Authentication protocols NTLM, Kerberos Next

Result Pattern or Result Object Pattern or Error Handling with Result

๐Ÿ“˜ What is the Result Pattern?

The Result Pattern (also known as Result Object Pattern or Error Handling with Result) is a design pattern often used to handle success and failure outcomes without throwing exceptions unnecessarily.

Instead of returning only a value (or throwing an exception if something goes wrong), you return a Result object that clearly indicates Success or Failure, along with additional information (like error messages).

๐Ÿงฉ Why Use the Result Pattern?

  • โœ… Avoids excessive try-catch usage.
  • โœ… Makes code more predictable (no "hidden" exceptions).
  • โœ… Provides structured feedback (success + error details).
  • โœ… Improves readability and testability.

โš™๏ธ Structure of Result Pattern

Usually, the Result type has:

  • IsSuccess โ†’ Boolean indicating success/failure.
  • Error โ†’ Error message (if failure).
  • Value โ†’ The actual return value (if success).

๐Ÿ”น C# Example โ€“ Result Pattern

using System;

public class Result<T>
{
    public bool IsSuccess { get; }
    public string Error { get; }
    public T Value { get; }

    // Private constructor (only static methods create instances)
    private Result(bool isSuccess, T value, string error)
    {
        IsSuccess = isSuccess;
        Value = value;
        Error = error;
    }

    // Factory methods
    public static Result<T> Success(T value) => new Result<T>(true, value, null);
    public static Result<T> Failure(string error) => new Result<T>(false, default, error);
}

// Example usage
public class Calculator
{
    public Result<int> Divide(int numerator, int denominator)
    {
        if (denominator == 0)
        {
            return Result<int>.Failure("โŒ Division by zero is not allowed.");
        }
        return Result<int>.Success(numerator / denominator);
    }
}

class Program
{
    static void Main()
    {
        var calc = new Calculator();

        var result1 = calc.Divide(10, 2);
        if (result1.IsSuccess)
            Console.WriteLine($"โœ… Result: {result1.Value}");
        else
            Console.WriteLine(result1.Error);

        var result2 = calc.Divide(10, 0);
        if (result2.IsSuccess)
            Console.WriteLine($"โœ… Result: {result2.Value}");
        else
            Console.WriteLine(result2.Error);
    }
}

๐Ÿ–ฅ๏ธ Output

โœ… Result: 5
โŒ Division by zero is not allowed.

๐Ÿ”‘ Benefits in This Example

  • No try-catch needed for normal errors.
  • Avoids exception-driven control flow
  • Makes error handling explicit and predictable
  • Clear success/failure state.
  • Easier to test and compose
  • Easy to extend (e.g., add error codes, multiple error messages, logging).

โœ… In real-world applications, this pattern is widely used in APIs, domain-driven design (DDD), and functional programming to return structured results.

Another example: ๐ŸŽฏ Scenario: File Processing Service

We'll simulate a method that reads a file, parses its content, and performs some logic. It can fail in four ways:

  1. File not found
  2. Unauthorized access
  3. Invalid format
  4. Unexpected error

๐Ÿงฑ 1. Traditional Try-Catch Version

public string ProcessFileTraditional(string filePath)
{
    try
    {
        if (!File.Exists(filePath))
            throw new FileNotFoundException();

        var content = File.ReadAllText(filePath);

        if (string.IsNullOrWhiteSpace(content))
            throw new FormatException("File is empty or invalid format.");

        if (content.Contains("restricted"))
            throw new UnauthorizedAccessException("Restricted content detected.");

        // Simulate processing
        return "File processed successfully.";
    }
    catch (FileNotFoundException)
    {
        return "Error: File not found.";
    }
    catch (UnauthorizedAccessException)
    {
        return "Error: Unauthorized access.";
    }
    catch (FormatException ex)
    {
        return $"Error: {ex.Message}";
    }
    catch (Exception)
    {
        return "Error: Unexpected failure.";
    }
}

โœ… 2. Result Pattern Version

public class Result
{
    public bool IsSuccess { get; }
    public string Message { get; }

    private Result(bool isSuccess, string message)
    {
        IsSuccess = isSuccess;
        Message = message;
    }

    public static Result Success(string message) => new Result(true, message);
    public static Result Failure(string message) => new Result(false, message);
}

public Result ProcessFileWithResult(string filePath)
{
    if (!File.Exists(filePath))
        return Result.Failure("File not found.");

    string content;
    try
    {
        content = File.ReadAllText(filePath);
    }
    catch (UnauthorizedAccessException)
    {
        return Result.Failure("Unauthorized access.");
    }
    catch (Exception)
    {
        return Result.Failure("Unexpected error while reading file.");
    }

    if (string.IsNullOrWhiteSpace(content))
        return Result.Failure("Invalid file format.");

    if (content.Contains("restricted"))
        return Result.Failure("Restricted content detected.");

    return Result.Success("File processed successfully.");
}

๐Ÿงช Example Usage

var result = ProcessFileWithResult("data.txt");

if (result.IsSuccess)
    Console.WriteLine(result.Message);
else
    Console.WriteLine($"Failed: {result.Message}");
Back to Index
Previous IaC (Infrastructure as Code) Authentication protocols NTLM, Kerberos Next
*