|
| 1 | +# Optional |
| 2 | + |
| 3 | +A lightweight, type-safe implementation of the Option pattern for .NET. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +`Option<T>` represents an optional value that can be in one of two states: |
| 8 | + |
| 9 | +- **Some**: Contains a value (which can be `null` if `T` is nullable). |
| 10 | +- **None**: Contains no value. |
| 11 | + |
| 12 | +This distinction is particularly useful when you need to differentiate between a value that was never specified (None) and a value that was explicitly set to null (Some(null)). |
| 13 | + |
| 14 | +## Quickstart |
| 15 | + |
| 16 | +```csharp |
| 17 | +using EHonda.Optional.Core; |
| 18 | + |
| 19 | +// Create options |
| 20 | +Option<string> some = Option.Some("hello"); |
| 21 | +Option<string> none = Option.None<string>(); |
| 22 | +Option<string> implicitSome = "hello"; |
| 23 | +Option<string> defaultNone = default; |
| 24 | + |
| 25 | +// Check state |
| 26 | +if (some.HasValue) |
| 27 | +{ |
| 28 | + Console.WriteLine(some.Value); |
| 29 | +} |
| 30 | + |
| 31 | +// Retrieve values with fallbacks |
| 32 | +string v1 = some.Or("fallback"); // returns "hello" |
| 33 | +string v2 = none.Or("fallback"); // returns "fallback" |
| 34 | +``` |
| 35 | + |
| 36 | +## Motivation: The "Explicit Null" Use Case |
| 37 | + |
| 38 | +This library was built to solve a specific problem in test infrastructure: distinguishing between "use the default value" and "use null". |
| 39 | + |
| 40 | +Consider a helper method for creating a service in a test. You want parameters to be optional so tests only specify what's relevant. |
| 41 | + |
| 42 | +Without `Option<T>`, using a nullable parameter makes it impossible to distinguish "unspecified" from "explicit null": |
| 43 | + |
| 44 | +```csharp |
| 45 | +// Problem: Can't distinguish between default (null) and explicit null |
| 46 | +IService CreateService(IDependency? dependency = null) |
| 47 | + => new(dependency ?? CreateDependency()); |
| 48 | + |
| 49 | +// Both calls look the same to the method: |
| 50 | +CreateService(); // Intention: Use default dependency |
| 51 | +CreateService(null); // Intention: Use null dependency (e.g. for null guard tests) |
| 52 | +``` |
| 53 | + |
| 54 | +With `Option<T>`, `None` is distinct from `null`: |
| 55 | + |
| 56 | +```csharp |
| 57 | +// Solution: Option<T> distinguishes between None and Some(null) |
| 58 | +IService CreateService(Option<IDependency> dependency = default) |
| 59 | + => new(dependency.Or(CreateDependency())); |
| 60 | + |
| 61 | +// Now the behavior is clear: |
| 62 | +CreateService(); // dependency is None -> uses CreateDependency() |
| 63 | +CreateService(null); // dependency is Some(null) -> uses null |
| 64 | +``` |
0 commit comments