RustlikeValues.Result
2.0.0
See the version list below for details.
dotnet add package RustlikeValues.Result --version 2.0.0
NuGet\Install-Package RustlikeValues.Result -Version 2.0.0
<PackageReference Include="RustlikeValues.Result" Version="2.0.0" />
<PackageVersion Include="RustlikeValues.Result" Version="2.0.0" />
<PackageReference Include="RustlikeValues.Result" />
paket add RustlikeValues.Result --version 2.0.0
#r "nuget: RustlikeValues.Result, 2.0.0"
#:package RustlikeValues.Result@2.0.0
#addin nuget:?package=RustlikeValues.Result&version=2.0.0
#tool nuget:?package=RustlikeValues.Result&version=2.0.0
RustLike Result<T, E> for C#
A robust implementation of Rust's Result type for C#, providing elegant error handling without exceptions.
Installation
dotnet add package RustLikeValues.Result
Overview
The Result<T, E>
type represents either success (Ok
) containing a value of type T
, or failure (Err
) containing an error of type E
. This pattern enables explicit error handling, making your code more predictable and easier to reason about.
Key Features
- Explicit Error Handling: Makes error cases visible in method signatures
- Chainable Operations: Supports functional programming patterns with
Map
,AndThen
, etc. - Pattern Matching: Use C# pattern matching or built-in
Match
methods - JSON Serialization: Built-in support for System.Text.Json
- Zero Overhead: Struct-based implementation for optimal performance
- Async Support: Full async/await compatibility
Quick Start
using RustLikeValues.RustLikeResult;
// Creating Results
var success = Result.Ok(42);
var failure = Result.Err("Something went wrong");
// Using explicit types when needed
var typedResult = Result<int, string>.Ok(42);
// Pattern matching
var message = result.Match(
Ok: value => $"Success: {value}",
Err: error => $"Error: {error}"
);
// Chaining operations
var final = await GetUserAsync(id)
.MapAsync(user => enrichUserDataAsync(user))
.AndThen(user => ValidateUser(user))
.MapErr(err => $"Failed to process user: {err}")
.UnwrapOr(DefaultUser);
Core Methods
Creation
Result.Ok<T>(value)
- Creates a success resultResult.Err<E>(error)
- Creates an error resultResult<T,E>.Ok(value)
- Type-specific successResult<T,E>.Err(error)
- Type-specific error
Checking State
IsOk
- Returns true if the result is OkIsErr
- Returns true if the result is Err
Extracting Values
Unwrap()
- Gets the Ok value or throwsUnwrapOr(defaultValue)
- Gets the Ok value or returns defaultUnwrapOrElse(Func<E, T>)
- Gets the Ok value or computes from errorUnwrapErr()
- Gets the Err value or throws
Transforming
Map<U>(Func<T, U>)
- Transform Ok valueMapErr<F>(Func<E, F>)
- Transform Err valueAndThen<U>(Func<T, Result<U, E>>)
- Chain operations that return Result
Pattern Matching
Match<U>(Func<T, U> Ok, Func<E, U> Err)
- Transform to a single typeMatch(Action<T> Ok, Action<E> Err)
- Execute side effects
Common Patterns
Error Propagation
public Result<Order, string> ProcessOrder(int orderId)
{
return GetOrder(orderId)
.AndThen(order => ValidateOrder(order))
.AndThen(order => CalculateTotal(order))
.Map(order => ApplyDiscounts(order));
}
Try-Catch Replacement
public Result<Data, Exception> LoadData(string path)
{
try
{
var data = File.ReadAllText(path);
return Result.Ok(JsonSerializer.Deserialize<Data>(data));
}
catch (Exception ex)
{
return Result.Err(ex);
}
}
Async Operations
public async Task<Result<User, ApiError>> GetUserAsync(int id)
{
var response = await httpClient.GetAsync($"/users/{id}");
if (!response.IsSuccessStatusCode)
return Result.Err(new ApiError(response.StatusCode));
var user = await response.Content.ReadFromJsonAsync<User>();
return Result.Ok(user);
}
Validation Chain
public Result<User, ValidationError> ValidateUser(User user)
{
return ValidateName(user.Name)
.AndThen(_ => ValidateEmail(user.Email))
.AndThen(_ => ValidateAge(user.Age))
.Map(_ => user);
}
Advanced Features
Implicit Conversions
// Use OkValue and ErrValue for cleaner syntax
Result<int, string> result = Result.Ok(42); // Implicitly converts
Result<int, string> error = Result.Err("failed"); // Implicitly converts
Deconstruction
var (isOk, value, error) = result;
if (isOk)
Console.WriteLine($"Value: {value}");
else
Console.WriteLine($"Error: {error}");
JSON Serialization
var result = Result.Ok<int, string>(42);
var json = JsonSerializer.Serialize(result);
// Output: {"$type":"ok","value":42}
var error = Result.Err<int, string>("failed");
var errorJson = JsonSerializer.Serialize(error);
// Output: {"$type":"err","error":"failed"}
Converting to Option
Option<int> option = result.Ok(); // Some(value) if Ok, None if Err
Option<string> error = result.Err(); // Some(error) if Err, None if Ok
Best Practices
Use descriptive error types instead of just strings
public enum ParseError { InvalidFormat, OutOfRange, NullInput } Result<int, ParseError> Parse(string input) { ... }
Prefer Result over exceptions for expected errors
// Good: Expected errors as Result Result<User, NotFoundError> GetUser(int id); // Exceptions for unexpected errors only throw new InvalidOperationException("Database connection lost");
Chain operations instead of nested if-statements
// Instead of multiple if-checks var result = GetData() .AndThen(Process) .AndThen(Validate) .Map(Transform);
Use Match for exhaustive handling
return result.Match( Ok: value => HandleSuccess(value), Err: error => HandleError(error) );
Performance Considerations
Result<T, E>
is a value type (struct) with minimal overhead- Methods are aggressively inlined where appropriate
- No heap allocations for the Result itself
- Suitable for high-performance scenarios
Migration from Exceptions
// Before: Exception-based
public User GetUser(int id)
{
var user = database.Find(id);
if (user == null)
throw new NotFoundException($"User {id} not found");
return user;
}
// After: Result-based
public Result<User, string> GetUser(int id)
{
var user = database.Find(id);
return user != null
? Result.Ok(user)
: Result.Err($"User {id} not found");
}
License
MIT License - see LICENSE file for details
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | 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. |
-
net9.0
- RustlikeValues.Option (>= 2.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.