LightResults 9.0.0-preview.15
Prefix Reserveddotnet add package LightResults --version 9.0.0-preview.15
NuGet\Install-Package LightResults -Version 9.0.0-preview.15
<PackageReference Include="LightResults" Version="9.0.0-preview.15" />
paket add LightResults --version 9.0.0-preview.15
#r "nuget: LightResults, 9.0.0-preview.15"
// Install LightResults as a Cake Addin #addin nuget:?package=LightResults&version=9.0.0-preview.15&prerelease // Install LightResults as a Cake Tool #tool nuget:?package=LightResults&version=9.0.0-preview.15&prerelease
LightResults - Operation Result Patterns for .NET
LightResults is an extremely light and modern .NET library that provides a simple and flexible implementation of the Result Pattern. The Result Pattern is a way of representing the outcome of an operation, whether it's successful or has encountered an error, in a more explicit and structured manner. This project is heavily inspired by Michael Altmann's excellent work with FluentResults.
References
This library targets .NET Standard 2.0, .NET 6.0, .NET 7.0, and .NET 8.0.
Dependencies
This library has no dependencies.
Advantages of this library
- ๐ชถ Lightweight โ Only contains what's necessary to implement the Result Pattern.
- โ๏ธ Extensible โ Simple interfaces and base classes make it easy to adapt.
- ๐งฑ Immutable โ Results and errors are immutable and cannot be changed after being created.
- ๐งต Thread-safe โ The Error list and Metadata dictionary use Immutable classes for thread-safety.
- โจ Modern โ Built against the latest version of .NET using the most recent best practices.
- ๐งช Native โ Written, compiled, and tested against the latest versions of .NET.
- โค๏ธ Compatible โ Available for dozens of versions of .NET as a .NET Standard 2.0 library.
- ๐ช Trimmable โ Compatible with ahead-of-time compilation (AOT) as of .NET 7.0.
- ๐ Performant โ Heavily optimized and benchmarked to aim for the highest possible performance.
Extensions
Several extensions are available to simplify implementation that use LightResults.
Documentation
Make sure to read the docs for the full API.
Getting Started
LightResults consists of only three classes Result
, Result<TValue>
, and Error
.
- The
Result
class represents a generic result indicating success or failure. - The
Result<TValue>
class represents a result with a value. - The
Error
class represents an error with a message and associated metadata.
Creating a successful result
Successful results can be created using the Ok
method.
var successResult = Result.Ok();
var successResultWithValue = Result.Ok(349.4);
Creating a failed result
Failed results can be created using the Fail
method.
var failedResult = Result.Fail();
var failedResultWithMessage = Result.Fail("Operation failed!");
var failedResultWithMessageAndMetadata = Result.Fail("Operation failed!", ("Exception", ex));
Checking the state of a result
There are two properties for results, IsSuccess
and IsFailed
. Both are mutually exclusive.
if (result.IsSuccess)
{
// The result is successful therefore IsFailed will be false.
}
if (result.IsFailed)
{
// The result is failed therefore IsSuccess will be false.
if (result.Error.Message.Length > 0)
Console.WriteLine(result.Error.Message);
else
Console.WriteLine("An unknown error occured!");
}
Getting the value
The value from a successful result can be retrieved through the Value
property.
if (result.IsSuccess)
{
var value = result.Value;
}
Creating errors
Errors can be created with or without a message.
var errorWithoutMessage = new Error();
var errorWithMessage = new Error("Something went wrong!");
With metadata.
var errorWithMetadataTuple = new Error(("Key", "Value"));
var metadata = new Dictionary<string, object> { { "Key", "Value" } };
var errorWithMetadataDictionary = new Error(metadata);
Or with a message and metadata.
var errorWithMetadataTuple = new Error("Something went wrong!", ("Key", "Value"));
var metadata = new Dictionary<string, object> { { "Key", "Value" } };
var errorWithMetadataDictionary = new Error("Something went wrong!", metadata);
Custom errors
The best way to represent specific errors is to make custom error classes that inherit from Error
and define the error message as a base constructor parameter.
public sealed class NotFoundError : Error
{
public NotFoundError()
: base("The resource cannot be found.")
{
}
}
var notFoundError = new NotFoundError();
var notFoundResult = Result.Fail(notFoundError);
Then the result can be checked against that error type.
if (result.IsFailed && result.HasError<NotFound>())
{
// Looks like the resource was not found, we better do something about that!
}
This can be especially useful when combined with metadata to handle exceptions.
public sealed class UnhandledExceptionError : Error
{
public UnhandledExceptionError(Exception ex)
: base("An unhandled exception occured.", ("Exception", ex))
{
}
}
Which allows us to continue using try-catch blocks in our code but return from them with a result instead of throwing an exception.
public Result DoSomeWork()
{
try
{
// We must not throw an exception in this method!
}
catch(Exception ex)
{
var unhandledExceptionError = new UnhandledExceptionError(ex);
return Result.Fail(unhandledExceptionError);
}
return Result.Ok();
}
We can further simplify creating errors by creating an error factory.
public static AppError
{
public Result NotFound()
{
var notFoundError = new NotFoundError();
return Result.Fail(notFoundError);
}
public Result UnhandledException(Exception ex)
{
var unhandledExceptionError = new UnhandledExceptionError(ex)
return Result.Fail(unhandledExceptionError);
}
}
Which clearly and explicitly describes the results.
public Result GetPerson(int id)
{
var person = _database.GetPerson(id);
if (person is null)
return AppError.NotFound();
return Result.Ok();
}
Static abstract members in interfaces
Note: Applies to .NET 7.0 (C# 11.0) or higher only!
Thanks to the static abstract members in interfaces introduced in .NET 7.0 (C# 11.0), it is possible to use generics to obtain access to the methods of the generic variant of the result. As such the error factory can be enhanced to take advantage of that.
public static AppError
{
public Result NotFound()
{
var notFoundError = new NotFoundError();
return Result.Failt(notFoundError);
}
public TResult NotFound<TResult>()
{
var notFoundError = new NotFoundError();
return TResult.Fail(notFoundError);
}
}
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. 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. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Microsoft.Bcl.HashCode (>= 1.1.1)
- System.Collections.Immutable (>= 8.0.0)
- System.Threading.Tasks.Extensions (>= 4.5.4)
-
net6.0
- No dependencies.
-
net7.0
- No dependencies.
-
net8.0
- No dependencies.
-
net9.0
- No dependencies.
NuGet packages (6)
Showing the top 5 NuGet packages that depend on LightResults:
Package | Downloads |
---|---|
LightResults.Extensions.ExceptionHandling
Exception handling for LightResults. |
|
McdaToolkit
Package Description |
|
LightResults.Extensions.Json
System.Text.Json converters for LightResults. |
|
LightResults.Extensions.ValueObjects
Value Objects using LightResults. |
|
LightResults.Extensions.EntityFrameworkCore
EntityFrameworkCore with LightResults. |
GitHub repositories (1)
Showing the top 1 popular GitHub repositories that depend on LightResults:
Repository | Stars |
---|---|
jscarle/LightResults
An extremely light and modern Operation Result Pattern library for .NET.
|
Version | Downloads | Last updated |
---|---|---|
9.0.0-preview.15 | 8,820 | 7/5/2024 |
9.0.0-preview.14 | 47 | 7/5/2024 |
9.0.0-preview.13 | 45 | 7/5/2024 |
9.0.0-preview.12 | 37 | 7/5/2024 |
9.0.0-preview.11 | 127 | 6/26/2024 |
9.0.0-preview.10 | 144 | 4/5/2024 |
9.0.0-preview.9 | 61 | 4/4/2024 |
9.0.0-preview.8 | 72 | 3/30/2024 |
9.0.0-preview.7 | 96 | 3/20/2024 |
9.0.0-preview.6 | 280 | 3/20/2024 |
9.0.0-preview.5 | 61 | 3/20/2024 |
9.0.0-preview.4 | 70 | 3/19/2024 |
9.0.0-preview.3 | 59 | 3/19/2024 |
9.0.0-preview.2 | 70 | 3/17/2024 |
9.0.0-preview.1 | 65 | 3/5/2024 |
8.0.11 | 1,543 | 9/14/2024 |
8.0.10 | 4,185 | 6/26/2024 |
8.0.9 | 8,555 | 2/27/2024 |
8.0.8 | 169 | 2/20/2024 |
8.0.7 | 119 | 2/20/2024 |
8.0.6 | 141 | 2/18/2024 |
8.0.5 | 116 | 2/15/2024 |
8.0.4 | 122 | 2/14/2024 |
8.0.3 | 259 | 1/19/2024 |
8.0.2 | 133 | 1/19/2024 |
8.0.1 | 128 | 1/17/2024 |
8.0.0 | 143 | 1/17/2024 |