Avig.Result
1.0.2
dotnet add package Avig.Result --version 1.0.2
NuGet\Install-Package Avig.Result -Version 1.0.2
<PackageReference Include="Avig.Result" Version="1.0.2" />
<PackageVersion Include="Avig.Result" Version="1.0.2" />
<PackageReference Include="Avig.Result" />
paket add Avig.Result --version 1.0.2
#r "nuget: Avig.Result, 1.0.2"
#:package Avig.Result@1.0.2
#addin nuget:?package=Avig.Result&version=1.0.2
#tool nuget:?package=Avig.Result&version=1.0.2
Avig.Result
Outcomes as return values instead of exceptions. No dependencies.
using Avig;
Result<User> result = await _users.Find(id);
if (result.IsFailure(out string? error, out ResultStatus status))
{
return Result<Profile>.Failure(error, status);
}
Installation
dotnet add package Avig.Result
The package has no dependencies and targets net10.0.
Why
Throwing for an expected outcome — "not found", "wrong password", "that name is taken" — does
two things at once: it cuts the call chain short, and it hides the possibility in a catch
somewhere else. Result makes the outcome part of the signature instead, so the type says
what can go wrong and the compiler reminds you to handle it.
Exceptions remain for what they are good at: the things nobody expected.
The Try pattern
IsSuccess and IsFailure hand out the value and the error respectively:
if (result.IsSuccess(out User? user))
{
// user is not null here — [NotNullWhen] tells the compiler so
Console.WriteLine(user.Name);
}
That is why the type does not offer Data as the ordinary way to reach the value. A Data
property has to be nullable to work on failure, and then every call site grows a ! or a null
check the compiler cannot help with. With the out form, the compiler knows the value is there
in the branch where it is there.
Status
ResultStatus tells the failures apart so the caller can translate them — typically into an
HTTP status — without parsing error messages as text:
| Status | Means |
|---|---|
Ok |
succeeded |
NotFound |
did not exist |
Invalid |
input rejected by validation |
Unauthorized |
not signed in |
Forbidden |
signed in but not allowed |
Conflict |
clashes with existing state |
Unavailable |
a dependency did not answer |
Error |
anything else |
Every status has its own factory method: Result<T>.NotFound(), Result.Forbidden() and so
on. There is also an implicit conversion from the value, so return user; is enough where the
return type is Result<User>.
Building and releasing
dotnet test Avig.Result.slnx # 12 tests
./publish.ps1 # tests, packs, shape-checks, copies to the local feed
./release.ps1 -DryRun # says which version a release would produce
./release.ps1 -Push # bumps, tags and publishes to nuget.org
publish.ps1 fails if the package picks up a dependency. That is deliberate: the type sits at
the bottom of every call chain in every project that uses it, so a dependency that sneaks in
lands on all of them with no way to opt out.
The tag is what publishes — release.ps1 pushes vX.Y.Z, which runs
.github/workflows/publish.yml. That builds the package again on a runner and pushes it to
nuget.org through Trusted Publishing. No API key is stored anywhere.
License
MIT. See LICENSE.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. 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. |
-
net10.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.0.2 | 109 | 9/22/2026 |
First public release. Result and Result<T> moved out of the Medusa solution into a repository and package of their own, since the type has nothing to do with Medusa. The code is unchanged; what is new is the licence, SourceLink and a symbol package.