| Dry Run in Program :👈 | 👉:API Gateway |
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:
- File not found
- Unauthorized access
- Invalid format
- 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}");
| Dry Run in Program :👈 | 👉:API Gateway |
Comments and Discussion