SimpleResultMonad 1.1.1

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

SimpleResultMonad

A simple, extensible, and type-safe Result monad for C#/.NET, supporting functional error handling, monadic chaining, and pattern matching.

Features

  • Type-safe success and failure results
  • Extensible error codes (define your own)
  • Monadic chaining with .Then(...)
  • Pattern matching made easy

Installation

dotnet add package SimpleResultMonad

API Overview

(That's it, 4 Types and 1 Function!)

  • ResultSuccess<T>(T data, string? message = null)
  • ResultFailure<T>(string? message, ResultErrorCode errorCode, Exception? exception = null)
  • Result<T> (base type)
  • ResultErrorCode (extensible error code type)
  • .Then(...) extension method for chaining

Example: Full Flow

public static class MyErrorCodes
{
  public static readonly ResultErrorCode EmployeeAlreadyExists = new("EmployeeAlreadyExists");
  public static readonly ResultErrorCode InvalidEmployeeData = new("InvalidEmployeeData"); }

  var employee = new Employee { Name = "Alice", Email = "alice@example.com" };

  var result = ValidateEmployee(employee)
                .Then(emp => CheckEmployeeDoesNotExist(emp))
                .Then(emp => SaveEmployee(emp))
                .Then(emp => SendWelcomeEmail(emp));
  switch (result)
  {
    case ResultSuccess<Employee> s: Console.WriteLine($"Employee onboarded: {s.Data.Name}"); break;
    case ResultFailure<Employee> f when f.ErrorCode == MyErrorCodes.EmployeeAlreadyExists: Console.WriteLine("Employee already exists."); break;
    case ResultFailure<Employee> f when f.ErrorCode == MyErrorCodes.InvalidEmployeeData: Console.WriteLine("Invalid employee data."); break;
    case ResultFailure<Employee> f: Console.WriteLine($"Other error: {f.ErrorCode.Code} - {f.Message}"); break;
  }

Async Chaining

You can chain asynchronous operations using the async overloads of .Then. To transition a sync chain into async, use .ToAsync(). Once, you've had 1 async call, all subsequent steps can be either synchronous or asynchronous.

Example: Chaining async functions

// Starting sync, chaining into later async calls
    var result = await ValidateEmployee(employee) // sync
    .ToAsync() // now async or sync call follow
    .Then(async emp => await CheckEmployeeDoesNotExistAsync(emp)) 
    .Then(emp => NormalizeEmployeeData(emp))
    .Then(async emp => await SaveEmployeeToDbAsync(emp))
    .Then(emp => new ResultSuccess<string>($"Employee {emp.Name} onboarded successfully!"));

1. Define Your Own Error Codes

You can define custom error codes in your application for domain-specific errors:

public static class MyErrorCodes
{
  public static readonly ResultErrorCode EmployeeAlreadyExists = new("EmployeeAlreadyExists");
  public static readonly ResultErrorCode InvalidEmployeeData = new("InvalidEmployeeData");
}

2. Chain Operations with .Then

Chain together multiple operations, each returning a Result<T>. If any step fails, the chain short-circuits and returns the failure. All behavior contained to 2 types, no exception side-effects.

var employee = new Employee { Name = "Alice", Email = "alice@example.com" };
var result = ValidateEmployee(employee)
  .Then(emp => CheckEmployeeDoesNotExist(emp))
  .Then(emp => SaveEmployee(emp))
  .Then(emp => SendWelcomeEmail(emp));

3. Pattern Match on the Result

Handle each outcome explicitly using pattern matching on the ResultFailure.ErrorCode: Define what to do on success, and then how to handle various ErrorCode scenarios (if needed).

switch (result)
{
  case ResultSuccess<Employee> s: Console.WriteLine($"Employee onboarded: {s.Data.Name}"); break;
  case ResultFailure<Employee> f when f.ErrorCode == MyErrorCodes.EmployeeAlreadyExists: Console.WriteLine("Employee already exists."); break;
  case ResultFailure<Employee> f when f.ErrorCode == MyErrorCodes.InvalidEmployeeData: Console.WriteLine("Invalid employee data."); break;
  case ResultFailure<Employee> f: Console.WriteLine($"Other error: {f.ErrorCode.Code} - {f.Message}"); break;
}

License

MIT


ResultMonad makes functional error handling in C# easy, robust, and extensible.
Define your own error codes, chain operations, and handle results with confidence!

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net8.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.1.1 115 8/11/2025
1.1.0 122 8/8/2025
1.0.0 96 7/31/2025