Null Object Pattern & Functional `Option<T>` / `Result<T>` Types
1Concept
The Null Object Pattern replaces null returns with neutral do-nothing objects. Functional `Option<T>` (Some vs None) and `Result<T>` make absence or failure an explicit return type in domain modeling.
2Architecture Diagram
Service Query
│
Found?
├── YES ──> Result.Success(User)
└── NO ──> Result.Failure("User not found in partition")3Code Example
C# 13 & .NET 9
using System;
public readonly record struct Result<T>
{
public bool IsSuccess { get; }
public T Value { get; }
public string Error { get; }
private Result(T value) { IsSuccess = true; Value = value; Error = string.Empty; }
private Result(string error) { IsSuccess = false; Value = default!; Error = error; }
public static Result<T> Success(T value) => new(value);
public static Result<T> Failure(string error) => new(error);
}
public class ResultPatternDemo
{
public static Result<string> FetchApiKey(int tenantId)
{
if (tenantId == 100) return Result<string>.Success("SEC-KEY-998877");
return Result<string>.Failure("Tenant not provisioned.");
}
public static void Main()
{
var res = FetchApiKey(100);
if (res.IsSuccess)
{
Console.WriteLine($"API Key: {res.Value}");
}
else
{
Console.WriteLine($"Error: {res.Error}");
}
}
}4Expected Output
API Key: SEC-KEY-998877
5Key Takeaways
- ✓The `Result<T>` pattern avoids costly exception throwing for normal business validation flows.
- ✓Struct-based `Result<T>` creates zero GC heap allocation overhead.
- ✓Cleanly interoperates with C# 13 pattern matching.