Waystone.Monads 5.5.0

dotnet add package Waystone.Monads --version 5.5.0
                    
NuGet\Install-Package Waystone.Monads -Version 5.5.0
                    
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="Waystone.Monads" Version="5.5.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Waystone.Monads" Version="5.5.0" />
                    
Directory.Packages.props
<PackageReference Include="Waystone.Monads" />
                    
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 Waystone.Monads --version 5.5.0
                    
#r "nuget: Waystone.Monads, 5.5.0"
                    
#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 Waystone.Monads@5.5.0
                    
#: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=Waystone.Monads&version=5.5.0
                    
Install as a Cake Addin
#tool nuget:?package=Waystone.Monads&version=5.5.0
                    
Install as a Cake Tool

Waystone.Monads

A .NET implementation of the std::option and std::result modules from the Rust Standard Library.

Option

The Option type represents an optional value: every Option is either Some and contains a value, or None, and does not. It provides similar functionality to the built in nullable reference types offered in C#, but provides a more rigid structure for handling the "null" scenario.

Implemented Types

  • An Option<T> abstract record describes the Option type.
  • A Some<T> record describes the Some type.
  • A None<T> record describes the None type.

Result

The Result type is a type used for returning and propagating errors. Every Result is either Ok, representing success and containing a value, or Err, representing an error and containing an error value.

Implemented Types

  • An Result<TOk,TErr> abstract record describes the Result type.
  • An Ok<TOk,TErr> record describes the Ok type.
  • An Err<TOk,TErr> record describes the Err type.

Each concrete result type requires the other's generic type parameters in order to correlate correctly with each other.

Creating Results

Supply both type parameters when you provide your own error type:

Result<int, string> result = Result.Ok<int, string>(1);
Result<int, string> error = Result.Err<int, string>("something went wrong");

If you are happy with the built in Error type, use the single type parameter overloads instead. These default TErr to Error:

Result<int, Error> result = Result.Ok<int>(1);
Result<int, Error> error = Result.Err<int>(new Error("MyCode", "something went wrong"));

An Error code can be derived from an enum value, which keeps the code stable across occurrences of the same error type:

enum UserErrors
{
    NotFound,
}

// code becomes "UserErrors.NotFound"
Result<User, Error> error = Result.Err<User>(UserErrors.NotFound, "the user was not found");

// or, when you need the error on its own
Error err = Error.FromEnum(UserErrors.NotFound, "the user was not found");

Use Try to capture the value of a factory that may throw. The single type parameter overload converts the exception using Error.FromException:

Result<int, string> custom = Result.Try(() => int.Parse(input), ex => ex.Message);
Result<int, Error> parsed = Result.Try<int>(() => int.Parse(input));

Async

Both monads provide TryAsync for factories that return a Task:

Result<User, Error> result = await Result.TryAsync<User>(() => FetchUserAsync(id));
Option<User> option = await Option.TryAsync(() => FetchUserAsync(id));

The Try overloads that accept an async factory are obsolete and will be removed in v6. Call TryAsync instead.

The terminal operations are also available on Task and ValueTask receivers, so you do not have to await the monad before unwrapping it:

User user = await FetchUserAsync(id).UnwrapAsync();
User userOrGuest = await FetchUserAsync(id).UnwrapOrAsync(Guest);
User expected = await FetchUserAsync(id).ExpectAsync("the user must exist");
Error error = await FetchUserAsync(id).UnwrapErrAsync();

Result provides UnwrapAsync, UnwrapErrAsync, UnwrapOrAsync, UnwrapOrDefaultAsync, ExpectAsync and ExpectErrAsync. Option provides UnwrapAsync, UnwrapOrAsync, UnwrapOrDefaultAsync and ExpectAsync.

Configuration

You can configure an action to be invoked when an exception is caught and handled by the library. Invoke the UseExceptionLogger function once during the lifetime of your app:

MonadOptions.Configure(options => options.UseExceptionLogger((exception, callerInfo) =>
{
    Log.Error(exception, "Exception when creating monad"); // use Serilog/NLog/Etc
}));

There may be times where you want to generate an ErrorCode from an Enum or an Exception. You can configure the formatting of the generated error codes using the UseErrorCodeFactory.

class MyErrorCodeFactory : ErrorCodeFactory
{
  // override as needed
}

MonadOptions.Configure(options => options.UseErrorCodeFactory(new MyErrorCodeFactory()));

![NOTE] The MonadOptions class acts like a singleton, so you should only configure it once in your application's life-cycle.

Scoped Configuration

When you need different options for one region of code - a single request, a test, or a block you are debugging - create a scope instead of reconfiguring the whole application:

using (MonadOptions.BeginScope(options => options.UseFallbackErrorCode("Debug")))
{
    // reads inside here, including after an await, see "Debug"
    var result = Result.Try<int>(() => int.Parse(input));
}

// the global configuration is unchanged out here

Options you do not set are inherited from the configuration in effect when the scope is created, and the scope is a snapshot, so a later Configure call does not change an open scope. Scopes nest, and disposing one restores the scope around it.

Scopes accept the same configuration methods as Configure, so an override can change any option:

using (MonadOptions.BeginScope(options => options
    .UseErrorCodeFactory(new MyErrorCodeFactory())
    .UseFallbackErrorMessage("Something went wrong while debugging.")))
{
    // ...
}

Because a scope applies to the current asynchronous flow, concurrent flows each see their own options. This makes scopes safe to use in parallel tests.

A scope affects work started inside it. It does not affect work that was already running when the scope was created.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  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 was computed.  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. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (2)

Showing the top 2 NuGet packages that depend on Waystone.Monads:

Package Downloads
Waystone.Monads.FluentValidation

An interop package for using FluentValidation with Waystone.Monads, allowing easy conversion between ValidationResult and Result types.

Waystone.WideLogEvents

A core library for managing "wide" log events in .NET applications. Provides foundational infrastructure for capturing and managing properties throughout a logical scope.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
5.5.0 0 8/19/2026
5.4.0 43 8/18/2026
5.3.0 76 8/17/2026
5.2.0 75 8/17/2026
5.1.1 2,680 2/6/2026
5.1.0 277 2/6/2026
5.1.0-wide-events.5 374 2/4/2026
5.1.0-wide-events.4 94 2/4/2026
5.1.0-wide-events.3 86 2/2/2026
5.1.0-wide-events.2 86 2/2/2026
5.1.0-wide-events.1 87 2/1/2026
5.0.0 6,272 11/29/2025
5.0.0-iter-attempt-5.1 275 8/7/2025
4.3.0 275 10/21/2025
4.2.0 645 7/28/2025
4.1.0 189 7/5/2025
4.0.0 268 7/3/2025
3.2.0 248 6/15/2025
3.1.0 345 6/13/2025
3.0.0 351 6/9/2025
Loading failed