Purview.Results
1.0.0-prerelease.2
dotnet add package Purview.Results --version 1.0.0-prerelease.2
NuGet\Install-Package Purview.Results -Version 1.0.0-prerelease.2
<PackageReference Include="Purview.Results" Version="1.0.0-prerelease.2" />
<PackageVersion Include="Purview.Results" Version="1.0.0-prerelease.2" />
<PackageReference Include="Purview.Results" />
paket add Purview.Results --version 1.0.0-prerelease.2
#r "nuget: Purview.Results, 1.0.0-prerelease.2"
#:package Purview.Results@1.0.0-prerelease.2
#addin nuget:?package=Purview.Results&version=1.0.0-prerelease.2&prerelease
#tool nuget:?package=Purview.Results&version=1.0.0-prerelease.2&prerelease
Purview.Results
A small, dependency-light Result<TValue, TError> for .NET that lets expected failures flow through a
value instead of an exception. Exceptional circumstances still throw; states you expect — not found, invalid,
conflict — are values.
Installation
dotnet add package Purview.Results
Quick start
using Purview.Results;
Result<Tenant, TenantError> GetTenant(TenantId tenantId) =>
_tenants.TryGet(tenantId, out var tenant)
? Result<Tenant, TenantError>.Success(tenant)
: Result<Tenant, TenantError>.Failure(new TenantNotFound(tenantId));
var result = GetTenant(tenantId);
if (result.IsSuccess)
Console.WriteLine(result.Value.Name);
var message = result.Match(
tenant => $"Found {tenant.Name}",
error => $"Could not load the tenant: {error}"
);
Both member states are also reachable through implicit conversions, so an error value or a success value can be returned directly from a method whose return type is the result:
Result<int, string> ok = 42;
Result<int, string> failed = "not a number";
API
| Member | Purpose |
|---|---|
Result<TValue, TError>.Success(value) / .Failure(error) |
Create a result |
Result.Success<TValue, TError>(value) / Result.Failure<TValue, TError>(error) |
Create a result without naming the value twice |
IsInitialized |
Whether the result was created at all |
IsSuccess / IsFailure |
Which state the result holds ([MemberNotNullWhen], so nullability flows) |
Value / Error |
The payload; throws InvalidOperationException in the other state |
Match(success, failure) |
Fold both states into one value |
Map(map) |
Transform the successful value, preserving the error |
Bind(bind) |
Chain another operation that can fail, preserving the error type |
MapError(map) |
Transform the error, preserving the value |
ToString() |
Success(value), Failure(error) or Uninitialized |
Result<TValue, TError> is a readonly record struct. default is uninitialized: IsInitialized,
IsSuccess and IsFailure are all false, and Value, Error, Match, Map, Bind and MapError throw
InvalidOperationException rather than silently treating the result as a failure or a success.
IResultValue exposes a non-generic, read-only view (IsInitialized, IsSuccess, SuccessValue,
ErrorValue) for infrastructure that cannot be generic over the value and error types — an ASP.NET Core
endpoint filter, for example. Its accessors never throw: the one that does not describe the current state
returns null.
Union error types
A C# 15 union is a natural TError: the error cases stay strongly typed. Because C# never composes the union
conversion with the result's own conversion, a case value cannot be returned directly — the
Purview.Results.SourceGenerator package
generates a per-case AsFailure<TValue>() helper for [GenerateResult] unions:
Result<Tenant, TenantError> GetTenant(TenantId tenantId) => new TenantNotFound(tenantId).AsFailure<Tenant>();
The generator cannot declare that conversion for you: C# forbids user-defined operators in a static class,
forbids conversion operators in extension members, and permits only one user-defined conversion per conversion
sequence. The
Purview.Results.SourceGenerator package
ships a code fix that offers the rewrite in the IDE when a case value is returned where a result is expected.
If you prefer to avoid the helper entirely, the cast form needs no generated code, because the cast closes the case → union conversion so only the library's union → result conversion remains:
Result<Tenant, TenantError> GetTenant(TenantId tenantId) => (TenantError)new TenantNotFound(tenantId);
Examples
src/examples/Examples.Basic is a
runnable console example over the Tenant* domain this README documents: the three result states, the combinators,
probing, the throw-on-misuse contract and the generated AsFailure<TValue>() helper.
dotnet run --project src/examples/Examples.Basic
The repository README lists the ZodSharp, ASP.NET Core and ASP.NET Core + Zod examples too.
Related packages
| Package | Purpose |
|---|---|
Purview.Results.SourceGenerator |
Generates AsFailure<TValue>() helpers for [GenerateResult] unions |
Purview.Results.AspNetCore |
Maps results onto ASP.NET Core responses, including ProblemDetails |
Purview.Results.ZodSharp |
Bridges ZodSharp ValidationResult<T> into results |
Purview.Results.ZodSharp.AspNetCore |
Maps validation-carrying failures onto HttpValidationProblemDetails |
Agent skills
This package ships the purview-results-core agent skill under .agents/. Repositories that import
Purview.BuildSdk get it mirrored into their own .agents/ folder on the next restore or build, so AI agents
working there receive the guidance automatically.
License
MIT — see LICENSE.md.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net11.0 is compatible. |
-
net11.0
- No dependencies.
NuGet packages (2)
Showing the top 2 NuGet packages that depend on Purview.Results:
| Package | Downloads |
|---|---|
|
Purview.Results.AspNetCore
Maps Purview.Results results onto ASP.NET Core responses, including ProblemDetails for expected failures. |
|
|
Purview.Results.ZodSharp
Bridges ZodSharp ValidationResult<T> values into Purview.Results, so validation outcomes flow through the result pipeline as ordinary error values instead of exceptions. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0-prerelease.2 | 57 | 9/30/2026 |
| 1.0.0-prerelease.1 | 49 | 9/30/2026 |