Darp.Results 1.2.0

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

Darp.Results

Darp.Results Downloads License

A Result type implementation for C# that provides a safe way to handle operations that can succeed or fail, inspired by Rust's Result<T, E> type.

Packages

Quick Start

using Darp.Results;

// Create Results
Result<int, string> success = new Result.Ok<int, string>(42);
Result<int, string> failure = new Result.Err<int, string>("Something went wrong");

// Implicit conversions
Result<int, string> implicitSuccess = 42;
Result<int, string> implicitFailure = "error";

// Extract values safely
if (result.TryGetValue(out int value)) { /* use value */ }
if (result.TryGetError(out string error)) { /* handle error */ }

// Switch on result
return result switch 
{
    Result.Ok<int, string>(var value) => value,
    Result.Err<int, string>(var error) => error,
}

Why another results library?

  • Get values through switching
  • API heavily inspired by Rust's Result<T, E>
  • Ability to attach metadata to results
  • Immutability
  • Any object should be a possible error type (e.g., enums)
  • Analyzers/CodeFixers
  • Designed to benefit from the discriminated unions proposal

Existing projects did not fit all the requirements. However, these projects were an inspiration:

Core API Reference

Creation

Constructors / Implicit Conversions
// Value to Result
Result<int, string> result = 42; // Creates Ok(42)
Result<int, string> result = new Result.Ok<int, string>(42);
Result<int, string> result = new Result.Ok<int, string>(42, metadata: new Dictionary<string, object>());

// Error to Result  
Result<int, string> result = "error"; // Creates Err("error")
Result<int, string> result = new Result.Err<int, string>("error");
Result<int, string> result = new Result.Err<int, string>("error", metadata: new Dictionary<string, object>());
Factory Methods
// Try-catch wrapper
Result<TValue, Exception> Result.Try<TValue>(Func<TValue> func)

// TryParse wrapper
Result<TValue, StandardError> Result.From<T, TValue>(T input, TryParseFunc<T, TValue> tryParse)

State Checking

bool IsOk { get; }  // True if result is success
bool IsErr { get; } // True if result is error

Value Extraction

Safe Extraction
// Extract value
bool TryGetValue(out TValue value)
bool TryGetValue(out TValue value, out Result.Err<TNewValue, TError> error)
bool TryGetValue<TNewValue>(out TValue value, out Result.Err<TNewValue, TError> error)

// Extract error
bool TryGetError(out TError error)
bool TryGetError(out TError error, out Result.Ok<TValue, TNewError> success)
bool TryGetError<TNewError>(out TError error, out Result.Ok<TValue, TNewError> success)

// Extract with a default value
TValue Unwrap(TValue defaultValue)           // Returns value or default
TValue Unwrap(Func<TValue> valueProvider)    // Returns value or computed default
TValue? UnwrapOrDefault()                    // Returns value or default(TValue)
Unsafe Extraction (throws on wrong state)
TValue Unwrap()                    // Throws if error
TValue Expect(string message)      // Throws with custom message if error
TError UnwrapError()               // Throws if success
TError ExpectError(string message) // Throws with custom message if success

Transformations

Map Operations
// Transform success value
Result<TNewValue, TError> Map<TNewValue>(Func<TValue, TNewValue> func)

// Transform error
Result<TValue, TNewError> MapError<TNewError>(Func<TError, TNewError> func)
Logical Combinators
// And operations
Result<TNewValue, TError> And<TNewValue>(Result<TNewValue, TError> result)
Result<TValue, TError> And(Func<TValue, Result<TValue, TError>> resultProvider)
Result<TNewValue, TError> And<TNewValue>(Func<TValue, Result<TNewValue, TError>> resultProvider)

// Or operations  
Result<TValue, TError> Or(Result<TValue, TError> result)
Result<TValue, TError> Or(Func<TError, Result<TValue, TError>> resultProvider)
Result<TValue, TNewError> Or<TNewError>(Func<TError, Result<TValue, TNewError>> resultProvider)

Utility Operations

Flattening
// Flatten nested Results
Result<TValue, TError> Flatten<TValue, TError>(Result<Result<TValue, TError>, TError> result)
Iteration
// Enumerate success values (yields single value for Ok, empty for Err)
IEnumerable<TValue> AsEnumerable()
IEnumerator<TValue> GetEnumerator() // Enables foreach

Metadata

// Add metadata
Result<TValue, TError> WithMetadata(string key, object value)
Result<TValue, TError> WithMetadata(ICollection<KeyValuePair<string, object>> metadata)

// Access metadata
IReadOnlyDictionary<string, object> Metadata { get; }

Testing with Shouldly

using Darp.Results.Shouldly;

// Assert success
result.ShouldBeSuccess();
result.ShouldHaveValue(expectedValue);
result.ShouldHaveValue(value => value.ShouldBeGreaterThan(0));

// Assert error
result.ShouldBeError();
result.ShouldHaveError(expectedError);
result.ShouldHaveError(error => error.ShouldNotBeNull());

Examples

Basic Usage

Divide two numbers, return a result and attempt to get the value

public Result<int, string> Divide(int a, int b)
{
    if (b == 0)
        return "Cannot divide by zero";
    return a / b;
}

var result = Divide(10, 2);
if (result.TryGetValue(out int value))
{
    Console.WriteLine($"Result: {value}");
}

Early returns

To achieve early returns, rust provides the ? operator. Due to shortcomings of c#, we'll use the TryGet pattern to get the error

public Result<string, StandardError> WorkWithResult(Result<int, StandardError> result)
{
    if (!result.TryGetValue(out int value, out Result.Err<string, StandardError>? err))
        return err;
    // ...
    return value.ToString();
}

Chaining Operations

var result = Result.Ok<int, string>(10)
    .Map(x => x * 2)
    .And(x => x > 15 ? new Result.Ok<string, string>($"Big: {x}") : new Result.Err<string, string>("Too small"))
    .Map(s => s.ToUpper());

result.ShouldHaveValue("BIG: 20");

Switching

Use switch expressions to easily access value/error

public Result<string, StandardError> SwitchOnResult(Result<int, StandardError> result)
{
    return result switch
    {
        Result.Ok<int, StandardError>(var value, var metadata) => value.ToString(),
        Result.Err<int, StandardError>(var error, var metadata) => error,
    };
}

With Metadata

var result = Result.Ok<int, string>(42)
    .WithMetadata("operation", "calculation")
    .WithMetadata("timestamp", DateTime.UtcNow);

// Metadata is preserved through transformations
var transformed = result.Map(x => x.ToString());
// transformed.Metadata still contains the original metadata

License

This project is licensed under the Apache License 2.0.

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 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 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.
  • net9.0

    • No dependencies.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Darp.Results:

Package Downloads
Darp.Results.Shouldly

A set of extension methods to simplify testing Darp.Results.Result.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.2.0 109 9/25/2025
1.1.1 538 9/8/2025
1.0.0 113 9/5/2025