MonadicSharp 1.2.0
See the version list below for details.
dotnet add package MonadicSharp --version 1.2.0
NuGet\Install-Package MonadicSharp -Version 1.2.0
<PackageReference Include="MonadicSharp" Version="1.2.0" />
<PackageVersion Include="MonadicSharp" Version="1.2.0" />
<PackageReference Include="MonadicSharp" />
paket add MonadicSharp --version 1.2.0
#r "nuget: MonadicSharp, 1.2.0"
#addin nuget:?package=MonadicSharp&version=1.2.0
#tool nuget:?package=MonadicSharp&version=1.2.0
MonadicSharp
๐ Created by Danny4897 (aka Klexir on NuGet) | ๐ฆ Available on NuGet.org
A modern functional programming library for C# featuring Result<T>, Option<T>, Railway-Oriented Programming, and fluent pipeline composition. Build robust applications with elegant error handling and monadic patterns.
โจ Features
- ๐ฆ Result<T> - Railway-oriented programming for error handling
- ๐ฏ Option<T> - Null-safe operations and optional values
- ๐ Fluent Pipelines - Chain operations with elegant syntax
- โก Async Support - Full async/await compatibility
- ๐ก๏ธ Type Safety - Leverage C#'s type system for bulletproof code
- ๐ฆ Zero Dependencies - Lightweight and self-contained
๐ Quick Start
Installation
dotnet add package MonadicSharp
Basic Usage
using MonadicSharp;
using MonadicSharp.Extensions;
// Result<T> for error handling
var result = Result.Success(42)
.Map(x => x * 2)
.Bind(x => x > 50 ? Result.Success(x) : Result.Failure("Too small"))
.Map(x => $"Final value: {x}");
result.Match(
onSuccess: value => Console.WriteLine(value),
onFailure: error => Console.WriteLine($"Error: {error}")
);
// Option<T> for null-safe operations
var user = GetUser()
.Map(u => u.Email)
.Filter(email => email.Contains("@"))
.GetValueOrDefault("no-email@example.com");
๐ง Core Types
Result<T>
Railway-oriented programming for elegant error handling:
// Success path
var success = Result.Success("Hello World");
// Failure path
var failure = Result.Failure<string>("Something went wrong");
// Chaining operations
var result = GetUser(id)
.Bind(ValidateUser)
.Bind(SaveUser)
.Map(u => u.Id);
Option<T>
Null-safe operations without null reference exceptions:
// Some value
var some = Option.Some(42);
// No value
var none = Option.None<int>();
// Safe operations
var result = GetUser()
.Map(u => u.Name)
.Filter(name => name.Length > 0)
.GetValueOrDefault("Anonymous");
๐ Pipeline Composition
Build complex data processing pipelines:
var pipeline = Pipeline
.Start<string>()
.Then(ParseNumber)
.Then(ValidateRange)
.Then(FormatOutput);
var result = await pipeline.ExecuteAsync("42");
๐ฏ Error Handling Patterns
Traditional Approach (Problematic)
public User GetUser(int id)
{
var user = database.Find(id);
if (user == null)
throw new UserNotFoundException();
if (!user.IsActive)
throw new UserInactiveException();
return user;
}
MonadicSharp Approach (Clean)
public Result<User> GetUser(int id)
{
return database.Find(id)
.ToResult("User not found")
.Bind(ValidateUserActive);
}
private Result<User> ValidateUserActive(User user)
{
return user.IsActive
? Result.Success(user)
: Result.Failure("User is inactive");
}
๐ API Reference
Result<T> Methods
Success<T>(T value)
- Create a successful resultFailure<T>(string error)
- Create a failed resultMap<TResult>(Func<T, TResult> func)
- Transform the success valueBind<TResult>(Func<T, Result<TResult>> func)
- Chain operationsMatch<TResult>(Func<T, TResult> onSuccess, Func<string, TResult> onFailure)
- Pattern matchIsSuccess
- Check if result is successfulIsFailure
- Check if result has failedValue
- Get the success value (throws if failed)Error
- Get the error message (empty if successful)
Option<T> Methods
Some<T>(T value)
- Create an option with valueNone<T>()
- Create an empty optionMap<TResult>(Func<T, TResult> func)
- Transform the value if presentBind<TResult>(Func<T, Option<TResult>> func)
- Chain operationsFilter(Func<T, bool> predicate)
- Filter based on conditionMatch<TResult>(Func<T, TResult> onSome, Func<TResult> onNone)
- Pattern matchGetValueOrDefault(T defaultValue)
- Get value or defaultHasValue
- Check if option has a valueValue
- Get the value (throws if empty)
Extension Methods
// Convert nullable to Option
string? nullable = GetNullableString();
var option = nullable.ToOption();
// Convert to Result
var result = option.ToResult("Value was null");
// Async operations
var asyncResult = await GetUserAsync(id)
.MapAsync(user => user.Email)
.BindAsync(ValidateEmailAsync);
๐๏ธ Requirements
- .NET 8.0 or later
- C# 10.0 or later
๐ License
This project is licensed under the MIT License - see the LICENSE file for details.
๐ค Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
๐ Learn More
Made with โค๏ธ by Danny4897
FunctionalSharp
Una libreria .NET che fornisce implementazioni di tipi monadici e funzionali per C#.
Caratteristiche
- Implementazione di
Option<T>
per gestire valori opzionali - Implementazione di
Result<T>
per gestire operazioni che possono fallire - Supporto per operazioni asincrone con
Task
- Integrazione con Entity Framework Core
- Pipeline funzionali concise
Installazione
dotnet add package MonadicSharp
Esempi di Utilizzo
Gestione di Valori Opzionali
// Creazione di un Option
var someValue = Option<int>.Some(42);
var noneValue = Option<int>.None;
// Pattern matching
var result = someValue.Match(
some: value => $"Il valore รจ {value}",
none: () => "Nessun valore"
);
// Map e Bind
var doubled = someValue.Map(x => x * 2);
var maybeString = someValue.Bind(x => x > 0 ? Option<string>.Some(x.ToString()) : Option<string>.None);
Gestione di Operazioni che Possono Fallire
// Creazione di un Result
var success = Result<int>.Success(42);
var failure = Result<int>.Failure(Error.Create("Operazione fallita"));
// Pattern matching
var result = success.Match(
success: value => $"Operazione riuscita: {value}",
failure: error => $"Errore: {error.Message}"
);
// Map e Bind
var doubled = success.Map(x => x * 2);
var maybeString = success.Bind(x => x > 0 ? Result<string>.Success(x.ToString()) : Result<string>.Failure(Error.Create("Valore non valido")));
Pipeline Funzionali Con Entity Framework
// Creazione di un utente con validazione
public async Task<Result<User>> CreateUserAsync(UserDto userDto)
{
return await Result<UserDto>.Success(userDto)
.Map(ValidateUserDto)
.Bind(MapToUser)
.Bind(user => _userRepository.Users.AddAsync(user))
.BindAsync(SaveChangesAsync)
.Success(user => Result<User>.Success(user))
.Failure(error => Result<User>.Failure(error));
}
// Recupero di un utente con gestione errori
public async Task<Result<User>> GetUserByIdAsync(int id)
{
return await Result<int>.Success(id)
.Bind(id => _userRepository.Users.FindAsync(id))
.BindAsync(user => user.ToResult("Utente non trovato"))
.Success(user => Result<User>.Success(user))
.Failure(error => Result<User>.Failure(error));
}
// Aggiornamento di un utente con validazione
public async Task<Result<User>> UpdateUserAsync(int id, UserDto userDto)
{
return await Result<(int id, UserDto dto)>.Success((id, userDto))
.Map(tuple => (tuple.id, ValidateUserDto(tuple.dto)))
.Bind(tuple => _userRepository.Users.FindAsync(tuple.id)
.BindAsync(user => user.ToResult("Utente non trovato"))
.Bind(user => MapToUser(tuple.dto).Map(dto => (user, dto))))
.Bind(tuple => _userRepository.Users.Update(tuple.user))
.BindAsync(SaveChangesAsync)
.Success(user => Result<User>.Success(user))
.Failure(error => Result<User>.Failure(error));
}
Operazioni Asincrone
// Combinazione di operazioni asincrone
public async Task<Result<User>> GetUserWithDetailsAsync(int userId)
{
return await Result<int>.Success(userId)
.BindAsync(async id =>
{
var user = await _userRepository.Users.FindAsync(id);
var roles = await _userRepository.Roles.WhereAsync(r => r.UserId == id);
return (user, roles);
})
.BindAsync(async tuple =>
{
var user = await tuple.user.ToResult("Utente non trovato");
var roles = await tuple.roles;
return Result<User>.Success(user with { Roles = roles });
});
}
Contribuire
Le contribuzioni sono benvenute! Per favore, apri una issue per discutere i cambiamenti che vorresti fare.
Licenza
Questo progetto รจ licenziato sotto la licenza MIT - vedi il file LICENSE per i dettagli.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | 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 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. |
-
net8.0
- Microsoft.EntityFrameworkCore (>= 8.0.2)
- System.Text.Json (>= 8.0.5)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
v1.2.0: Changed namespace from FunctionalSharp to MonadicSharp to match NuGet package name
v1.1.0: Added Either<TLeft, TRight> type for representing two alternative types