Is anyone aware of a way to simplify error handling when doing functional programming in C# using the Language-Ext library, similar to the error propagation operator that Rust has?
For example, I want to simplify the error handling in the Create
method below:
using LanguageExt;
using LanguageExt.Common;
using static LanguageExt.Prelude;
public class ProductAggregate
{
public string Name { get; private set; } = string.Empty;
public static Fin<ProductAggregate> Create(string name)
{
var product = new ProductAggregate();
// I find this too verbose and looking to simplify:
if (product.SetName(name) is { IsFail: true } errFin)
{
return (Error)errFin;
}
return product;
}
public Fin<Unit> SetName(string name)
{
if (string.IsNullOrWhiteSpace(name))
{
return Error.New("Product name cannot be null or empty.");
}
Name = name;
return unit;
}
}
Is there any way I can shorten that up? I really love how Rust does this:
fn get_current_date() -> Result<String, reqwest::Error> {
let url = "https://postman-echo.com/time/object";
let res = reqwest::blocking::get(url)?.json::<HashMap<String, i32>>()?;
let date = res["years"].to_string();
Ok(date)
}
The ?
operator above is chained with further steps, but on itself, it basically check if the left member or call return is an error Result and returns that error then and there. Of course it must match the error type of the enclosing function's return type (reqwest::Error
).
Is there a way to achieve something close to as elegant as this, but in C#?
EDIT: Tried to take Mark Seemann's advice about code that should provide a minimal, reproducible example.
You can use LINQ syntax to bind
(see e.g. LanguageExt-Wiki):
var result = from p in ProductAggregate.Create()
from _1 in p.SetName(...)
from _2 in p.SetCategory(...)
select p;
This works with any type that maybe contains a "right" value: Option
, Either
, Try
...
(Added via Edit:) Here's a rewrite of Create
using static LanguageExt.Prelude;
public static Fin<ProductAggregate> Create(string name) =>
from product in FinSucc(new ProductAggregate())
from _1 in product.SetName(name)
select product;