Ametrin.Optional
0.3.2
See the version list below for details.
dotnet add package Ametrin.Optional --version 0.3.2
NuGet\Install-Package Ametrin.Optional -Version 0.3.2
<PackageReference Include="Ametrin.Optional" Version="0.3.2" />
<PackageVersion Include="Ametrin.Optional" Version="0.3.2" />
<PackageReference Include="Ametrin.Optional" />
paket add Ametrin.Optional --version 0.3.2
#r "nuget: Ametrin.Optional, 0.3.2"
#:package Ametrin.Optional@0.3.2
#addin nuget:?package=Ametrin.Optional&version=0.3.2
#tool nuget:?package=Ametrin.Optional&version=0.3.2
Ametrin.Optional
A modern, allocation-free library providing robust optional types for .NET, offering a flexible and efficient way to handle nullable values, errors, and exceptions with a fluent, monadic API.
Options vs. Exceptions
Exceptions are relatively expensive and are best reserved for unexpected failures and programmer mistakes.
For expected errors (like invalid user input or parse failures), it's often better to return a lightweight value the caller must handle.
This makes error handling explicit, cheap, and hard to ignore without using exceptions for normal control flow.
dotnet add package Ametrin.Optional
Features
- Maximum Performance - A zero cost abstraction (mostly)
- Monadic API - Fluent interface for transformations and error handling of all kind
- Integration - Seamless integration with existing C# code
- Variety - Different types for various use cases
- Async Support - First-class support for async operations
Core Types
Option<T>
Represents a value of type T or nothing (error state).
// Creating Options
Option<T> b = Option.Success(someT); // explicit success creation (throws if someT is null)
Option<T> c = Option.Error<T>(); // explicit error creation
Option<T> a = Option.Of(someT); // returns Option.Error<T>() if someT is null
Option<T> a = someT; // implicit conversion from T -> Option.Of(someT)
Option<T> d = default; // default results in an error state -> Option.Error<T>()
Result<T> and Result<T, E>
Like Option<T> but with error information.
Result<T> uses an Exception as error type (easy to integrate)
Result<T, E> uses a custom error type (recommended for performance)
Result<T> b = Result.Success(someT); // explicit success creation (throws if someT is null)
Result<T> c = Result.Error<T>(new Exception()); // explicit error creation
Result<T> a = Result.Of(someT); // returns Result.Error<T>(new NullReferenceException()) if someT is null
Result<T> a = someT; // implicit conversion from T -> Result.Of(someT)
Result<T> a = new Exception(); // implicit conversion from Exception -> Result.Error<T>(new Exception())
// same concept for Result<T, E>
ErrorState and ErrorState<E>
Represents a success state or an error value
ErrorState uses an Exception as error type
ErrorState<E> uses a custom error type
ErrorState success = default; // ErrorState.Success()
ErrorState error = new Exception(); // ErrorState.Error(new Exception())
// same applies for ErrorState<E> (with generic arguments)
Option
Represents a success state or error state. Holds no value.
Option success = true; // Option.Success();
Option error = false; // Option.Error();
Core API
// common operations
option.Map(value => value * 2); // transform value if present
option.Require(value => value > 0); // filter based on predicate
option.Reject(value => value > 0); // inverse of Require
option.Or(defaultValue); // return value or defaultValue
option.OrThrow(); // return value or throw if error
option.Match( // reduce to a value (equivalent to .Map(success).Or(error) but supports ref structs)
success: value => value,
error: error => defaultValue
);
option.Consume( // handle success and error
success: value => { },
error: error => { }
);
// all operations have an overload that allows you to pass an argument into the delegate an avoid the closure
Advanced Features
Tuple Operations
// Combine multiple options
(optionA, optionB).Map((a, b) => a + b);
(optionA, optionB).Consume(
success: (a, b) => Console.WriteLine($"{a} + {b} = {a + b}"),
error: () => Console.WriteLine("One of the values was missing")
);
Async Support
// Async operations with full option support
var text = await new FileInfo("file.txt")
.RequireExists()
.MapAsync(f => File.ReadAllTextAsync(f.FullName))
.MapAsync(s => s.ToLower());
await text.ConsumeAsync(text => File.WriteAllTextAsync("output.txt", text));
RefOption<T>
A reduced version of Option<T> that can hold a ref struct as value
Edge Cases
For edge cases, high-performance scenarios where delegates cannot be static or when you absolutly need to modify the control flow use Branch:
if(result.Branch(out var value, out var error))
{
// success
}
else
{
// error
}
If there is no way around it you can get low-level access to all option types through OptionsMarshall.
Testing
For testing code using Ametrin.Optional types, use the Ametrin.Optional.Testing.TUnit extensions:
await Assert.That(option).IsSuccess(expectedValue);
await Assert.That(option).IsError();
Contributing
Contributions are welcome! Feel free to:
- Create issues for bugs or feature requests
- Submit pull requests (discuss design first)
- Add extensions for more testing frameworks
Performance
The library is designed with performance in mind and has minimal to no overhead thanks to the jit.
Example benchmark for parsing a DateTime:
| Method | Mean | Error | StdDev | Allocated |
|---------------- |---------:|---------:|---------:|----------:|
| Default_Success | 87.31 ns | 1.696 ns | 1.666 ns | - |
| Option_Success | 89.95 ns | 1.821 ns | 2.492 ns | - |
| Default_Error | 73.27 ns | 1.462 ns | 2.361 ns | - | // using TryParse
| Option_Error | 74.05 ns | 1.464 ns | 1.504 ns | - |
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Ametrin.Optional.Analyzer (>= 0.3.2)
-
net9.0
- Ametrin.Optional.Analyzer (>= 0.3.2)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Ametrin.Optional:
| Package | Downloads |
|---|---|
|
Ametrin.Optional.Testing.TUnit
Package Description |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.4.3 | 121 | 6/25/2026 |
| 0.4.2 | 118 | 6/21/2026 |
| 0.4.1 | 139 | 4/13/2026 |
| 0.4.0 | 121 | 4/1/2026 |
| 0.3.2 | 145 | 3/9/2026 |
| 0.3.1 | 733 | 12/3/2025 |
| 0.3.0 | 347 | 11/11/2025 |
| 0.2.9 | 251 | 11/5/2025 |
| 0.2.8 | 233 | 11/5/2025 |
| 0.2.7 | 196 | 10/17/2025 |
| 0.2.6 | 283 | 9/2/2025 |
| 0.2.5 | 186 | 7/29/2025 |
| 0.2.4 | 238 | 6/4/2025 |
| 0.2.3 | 343 | 5/14/2025 |
| 0.2.2 | 270 | 3/12/2025 |
| 0.2.1 | 233 | 2/11/2025 |
| 0.2.0 | 221 | 2/10/2025 |
| 0.1.3 | 256 | 1/29/2025 |
| 0.1.2 | 222 | 1/17/2025 |
| 0.0.1 | 196 | 1/29/2025 |