Ametrin.Optional 0.3.2

There is a newer version of this package available.
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
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Ametrin.Optional" Version="0.3.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Ametrin.Optional" Version="0.3.2" />
                    
Directory.Packages.props
<PackageReference Include="Ametrin.Optional" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Ametrin.Optional --version 0.3.2
                    
#r "nuget: Ametrin.Optional, 0.3.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Ametrin.Optional@0.3.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Ametrin.Optional&version=0.3.2
                    
Install as a Cake Addin
#tool nuget:?package=Ametrin.Optional&version=0.3.2
                    
Install as a Cake Tool

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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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
Loading failed