Wrap.Either.Testing
2.0.0-beta.3
dotnet add package Wrap.Either.Testing --version 2.0.0-beta.3
NuGet\Install-Package Wrap.Either.Testing -Version 2.0.0-beta.3
<PackageReference Include="Wrap.Either.Testing" Version="2.0.0-beta.3" />
<PackageVersion Include="Wrap.Either.Testing" Version="2.0.0-beta.3" />
<PackageReference Include="Wrap.Either.Testing" />
paket add Wrap.Either.Testing --version 2.0.0-beta.3
#r "nuget: Wrap.Either.Testing, 2.0.0-beta.3"
#:package Wrap.Either.Testing@2.0.0-beta.3
#addin nuget:?package=Wrap.Either.Testing&version=2.0.0-beta.3&prerelease
#tool nuget:?package=Wrap.Either.Testing&version=2.0.0-beta.3&prerelease
Wrap: Functional Monads for .NET
Functional monads for C#, to handle null values and failures without exceptions. Chain operations with method calls or LINQ query syntax (railway-oriented programming), with async support throughout.
Types
Maybe<T>: eitherSome<T>orNone. Use it instead ofnull.Result<T>: eitherOk<T>orFailure. Use it instead of throwing exceptions.Either<TLeft, TRight>: eitherLeft<TLeft>orRight<TRight>.Id<TId, TValue>: strongly typed IDs backed byint,uint,long,ulongorGuid.
Maybe<T>, Result<T> and Either<TLeft, TRight> are C# 15 union types. Each is a struct, so:
switchandispatterns work on the cases, and the compiler checks that aswitchcovers them all.- Wrapping a value in
Some<T>orOk<T>does not allocate. - They are never
null.default(Maybe<T>)isNone, anddefault(Result<T>)is aFailure.
Example
using Wrap;
using Wrap.Extensions;
static Result<int> ParseAge(string input) =>
int.TryParse(input, out var age) && age >= 0
? age
: R.Fail("Age must be a whole number of 0 or more.");
static string Describe(Result<int> age) =>
age.Map(x => x + 1) switch
{
Ok<int>(var next) => $"Next year you'll be {next}.",
Failure f => f.Message
};
static string Greet(string? name) =>
M.Wrap(name) // null becomes None
.Map(x => $"Hello, {x}!")
.Match(fNone: () => "Hello, stranger!", fSome: x => x);
View the Wiki for full documentation.
Packages
| Package | Contents |
|---|---|
Wrap |
Everything: the types plus all extension methods (Bind, Map, Match, LINQ, async, JSON converters). Start here. |
Wrap.Mvc |
ASP.NET Core MVC model binding for Wrap types. |
Wrap.Caching |
Thread-safe caching that uses Wrap types. |
Wrap.Id.Dapper |
Dapper type handlers for strongly typed IDs. |
Wrap.Testing |
Helpers for unit tests (AssertSome, AssertOk, AssertFailure, value generators). |
The core types are also published on their own: Wrap.Common, Wrap.Maybe, Wrap.Result, Wrap.Either and Wrap.Id, each with a matching .Testing package.
Requirements
Wrap 2 targets .NET 11 and needs C# 15, which comes with the .NET 11 SDK.
Wrap 1.x supports .NET 8, 9, 10 and 11, so you can stay on it without union types. It is in maintenance and gets fixes only.
History
Wrap brings together projects I have been working on since 2019. It started with a Result<T> implementation, which became Maybe (v10 in November 2025), and I decided it was best to have both.
At the same time I was maintaining StrongId (v8.5 in November 2024) so entity IDs didn't have to be primitives. I realised how much Result<T>, Maybe<T> and Id<T> had in common and brought them together in one library: Wrap.
Version 2 rebuilds the core types on the union types introduced in C# 15.
Licence
Copyright
Copyright (c) 2019-2026 bfren (unless otherwise stated)
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net11.0 is compatible. |
-
net11.0
- Wrap.Either (>= 2.0.0-beta.3)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Wrap.Either.Testing:
| Package | Downloads |
|---|---|
|
Wrap.Testing
All.Testing library |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.0.0-beta.3 | 0 | 11/13/2026 |
| 2.0.0-beta.1 | 0 | 11/13/2026 |