ForgeSharp.Results
2.0.0
See the version list below for details.
dotnet add package ForgeSharp.Results --version 2.0.0
NuGet\Install-Package ForgeSharp.Results -Version 2.0.0
<PackageReference Include="ForgeSharp.Results" Version="2.0.0" />
<PackageVersion Include="ForgeSharp.Results" Version="2.0.0" />
<PackageReference Include="ForgeSharp.Results" />
paket add ForgeSharp.Results --version 2.0.0
#r "nuget: ForgeSharp.Results, 2.0.0"
#:package ForgeSharp.Results@2.0.0
#addin nuget:?package=ForgeSharp.Results&version=2.0.0
#tool nuget:?package=ForgeSharp.Results&version=2.0.0
ForgeSharp.Results
ForgeSharp.Results is a high-performance, type-safe, and allocation-free result monad for .NET. It provides a robust alternative to exceptions for error handling, enabling explicit, predictable, and maintainable code.
Features
Performance by Design:
All result types are implemented as readonly structs, ensuring zero heap allocations and minimal GC pressure. This makes ForgeSharp.Results ideal for high-throughput and low-latency applications.Explicit Error Handling:
The result pattern replaces exceptions for flow control, making error and success states explicit and easy to reason about.Type Safety & Clarity:
APIs are strongly-typed and expressive, enabling compile-time safety and clear intent in your code.Modern C# Best Practices:
Leverages the latest C# features and .NET standards for maximum compatibility and future-proofing.Composable Pipelines:
Build synchronous and asynchronous pipelines for result-based workflows, with full LINQ support for expressive, query-based composition.Seamless I/O Integration:
Wrap file and directory operations inResulttypes for safe, exception-free I/O workflows with built-in error handling.
Pipelines & LINQ Integration
ForgeSharp.Results introduces Pipelines for composing complex workflows in a functional, type-safe, and allocation-free manner. Pipelines can be synchronous (IPipeline<T>) or asynchronous (IAsyncPipeline<T>), and can be created from delegates or composed from other pipelines.
- LINQ Support: Pipelines can be composed using LINQ query expressions, enabling powerful, readable, and maintainable workflows. LINQ methods like
select,where, andfromare supported for both sync and async pipelines. - Combining Results: Pipelines are ideal for combining multiple result-producing operations, propagating errors automatically, and building robust data flows.
_Example:
var pipeline =
from user in GetUserPipeline()
where user.IsActive
from profile in GetProfilePipeline(user.Id)
select (user, profile);
var result = pipeline.Execute();
if (result.IsSuccess)
Console.WriteLine($"User: {result.Value.user}, Profile: {result.Value.profile}");
Extension Methods
ForgeSharp.Results provides a rich set of extension methods to make working with results functional, expressive, and safe in both synchronous and asynchronous scenarios.
File & Directory Integration
New in this release: ForgeSharp.Results now provides seamless integration with System.IO operations through extension methods that wrap file and directory operations in Result types, enabling safe, exception-free I/O workflows.
File Operations
OpenAsResult / OpenReadAsResult / OpenWriteAsResult
Open files and receive aResult<FileStream>instead of exceptions.
Example:
fileInfo.OpenReadAsResult(useAsync: true)
File.OpenAsResult(path, FileMode.Open, FileAccess.Read, FileShare.Read)DeleteAsResult
Delete files safely with error handling built-in.
Example:
File.DeleteAsResult(path)
Directory Operations
CreateAsResult
Create directories and receive aResultorResult<DirectoryInfo>.
Example:
directoryInfo.CreateAsResult()
Directory.CreateAsResult(path)DeleteAsResult
Delete directories safely with error handling.
Example:
directoryInfo.DeleteAsResult()
Directory.DeleteAsResult(path)
All I/O methods handle UnauthorizedAccessException and other exceptions gracefully, returning failed results with meaningful error messages instead of throwing.
Chaining and Functional Composition
- Map / MapAsync
Chain operations that return results, propagating failures automatically.
Example:
result.Map(x => DoSomething(x))
await result.MapAsync(x => DoSomethingAsync(x))
Value Extraction and Conversion
GetOrDefault / GetOrDefaultAsync
Get the value if successful, or a default value if not.
Example:
result.GetOrDefault(-1)
await resultTask.GetOrDefaultAsync(-1)GetOrThrow / GetOrThrowAsync
Get the value if successful, or throw an exception if not.
Example:
result.GetOrThrow()
await resultTask.GetOrThrowAsync()AsResult / AsResultAsync
Convert aResult<T>to a non-genericResult.
Example:
result.AsResult()
await resultTask.AsResultAsync()
Null Safety
- EnsureNotNull / EnsureNotNullAsync
Ensure the value of a successful result is not null, otherwise return a failed result.
Example:
result.EnsureNotNull()
await resultTask.EnsureNotNullAsync()
Tapping (Side Effects)
- Tap / TapAsync
Execute an action if the result is successful, without altering the result.
Example:
result.Tap(() => Log("Success"))
await result.TapAsync(async () => await LogAsync())
Flattening
- Flatten / FlattenAsync
Flatten nested results or a sequence of results into a single result, propagating the first failure.
Example:
result.Flatten()
await resultTask.FlattenAsync()
Value Transformation
- Select / SelectAsync
Transform the value inside a successful result to a new type.
Example:
result.Select(x => x.ToString())
await resultTask.SelectAsync(x => x.ToString())
Resolving Collections
- ResolveAsync
Asynchronously resolve a collection of result tasks into a collection or async enumerable of results.
Example:
await tasks.ResolveAsync()
Dictionary and Collection Helpers
TryGetValueResult
Attempts to get a value from a dictionary as aResult<T>.
Example:
var valueResult = dict.TryGetValueResult(key);FirstOrResult
Returns the first element in a sequence that matches a predicate as aResult<T>.
Example:
var firstResult = list.FirstOrResult(x => x.IsActive, "No active item found.");
Miscellaneous
Restore / RestoreAsync
Restore a failed result using a provided function, useful for fallback or recovery logic.
Example:
result.Restore(fallbackFunc)
await resultTask.RestoreAsync(fallbackFunc)IsSuccessAsync
Determine whether an awaited result is successful.
Example:
await resultTask.IsSuccessAsync()
Use Cases
- Error Handling Without Exceptions:
Replace exceptions for flow control with explicit, type-safe results.
Result result = DoWork();
if (!result.IsSuccess)
Console.WriteLine(result.Message);
- Functional Pipelines:
Chain operations and propagate errors fluently.
var result = GetUser()
.Map(user => Validate(user))
.Map(validUser => Save(validUser));
- Async Pipelines:
Use async/await with result types for modern, non-blocking code.
var result = await GetUserAsync()
.MapAsync(user => ValidateAsync(user));
- LINQ Pipelines:
Use LINQ query expressions to compose pipelines and combine results.
var pipeline =
from user in GetUserPipeline()
where user.IsActive
from profile in GetProfilePipeline(user.Id)
select (user, profile);
var result = pipeline.Execute();
- Safe File & Directory Operations:
Replace try-catch blocks with explicit result-based I/O workflows.
// Create a directory and chain operations
var result = Directory.CreateAsResult(@"C:\MyApp\Data")
.Map(dir => new FileInfo(Path.Combine(dir.FullName, "config.json")).OpenWriteAsResult());
if (result.IsSuccess)
{
using (var stream = result.Value)
{
// Write configuration file
}
}
else
{
Console.WriteLine($"I/O operation failed: {result.Message}");
}
Quick Start
Basic Usage
Results can be used to represent success or failure in operations, with optional messages and exceptions.
Result DoSomething()
{
// Perform some operation
return Result.Success();
}
Result result = DoSomething();
if (!result.IsSuccess)
Console.WriteLine(result.Message);
Results can also carry values, allowing you to return data alongside success or failure states.
Result<int> GetValue()
{
// Perform some operation that returns an int
return Result.Success(42);
}
Result<int> valueResult = GetValue();
int value = valueResult.IsSuccess ? valueResult.Value : -1;
Capturing Exceptions
Result result = Result.Capture(() => MightThrow());
Result<int> valueResult = Result.Capture(() => MightThrowAndReturnInt());
Result result = await Result.CaptureAsync(async () => await MightThrowAsync());
Result<int> valueResult = await Result.CaptureAsync(async () => await MightThrowAndReturnIntAsync());
API Overview
- Result / Result<T>:
Core result types representing success, validation faults, and exceptions. - IResult / IResult<T>:
Interfaces for result types. - Pipelines:
Synchronous and asynchronous pipelines for composing result-based workflows, with LINQ support. - Functional Extension Methods:
For mapping, chaining, error handling, and async workflows. - Dictionary and Collection Helpers:
Methods likeTryGetValueResultandFirstOrResultfor safer collection access. - Forwarding and Conversion:
Easily convert between generic and non-generic results.
Project Structure
Result.cs- Core result types and logic.Pipeline.cs- Pipeline interfaces and implementations.Monad/- Extension methods for chaining, mapping, flattening, and more.Integration/- I/O integration extensions for safe file and directory operations.
Requirements
- .NET Standard 2.0, .NET Standard 2.1, or .NET 8.0+
Contributing
Contributions are welcome! Please open issues or submit pull requests for bug fixes, improvements, or new features.
License
Acknowledgements
- Inspired by functional programming and modern .NET design.
- Built for developers who care about performance, safety, and maintainability.
ForgeSharp.Results - Fast, type-safe, and allocation-free result handling for .NET.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. 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 was computed. 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 was computed. 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 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. |
| .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 is compatible. |
| .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
- No dependencies.
-
.NETStandard 2.1
- No dependencies.
-
net10.0
- No dependencies.
-
net8.0
- No dependencies.
NuGet packages (1)
Showing the top 1 NuGet packages that depend on ForgeSharp.Results:
| Package | Downloads |
|---|---|
|
ForgeSharp.Results.AspNetCore
AspNetCore Integration for ForgeSharp.Results. |
GitHub repositories
This package is not used by any popular GitHub repositories.