Waystone.Monads
5.5.0
dotnet add package Waystone.Monads --version 5.5.0
NuGet\Install-Package Waystone.Monads -Version 5.5.0
<PackageReference Include="Waystone.Monads" Version="5.5.0" />
<PackageVersion Include="Waystone.Monads" Version="5.5.0" />
<PackageReference Include="Waystone.Monads" />
paket add Waystone.Monads --version 5.5.0
#r "nuget: Waystone.Monads, 5.5.0"
#:package Waystone.Monads@5.5.0
#addin nuget:?package=Waystone.Monads&version=5.5.0
#tool nuget:?package=Waystone.Monads&version=5.5.0
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 theOptiontype. - A
Some<T>record describes theSometype. - A
None<T>record describes theNonetype.
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 theResulttype. - An
Ok<TOk,TErr>record describes theOktype. - An
Err<TOk,TErr>record describes theErrtype.
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
MonadOptionsclass 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 | Versions 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. |
-
.NETStandard 2.0
- System.Threading.Tasks.Extensions (>= 4.6.3)
- System.ValueTuple (>= 4.6.1)
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 |