For simplicity, I'm presenting a use-case that isn't really realistic (eg role-checking could be done differently, etc), but I'm trying not to confuse the question, so please bear with me.
Suppose I want to write a method that accepts an int
, and needs to...
- Check the authed used is in the appropriate role to make the request
- Check the Id corresponds to a customer in the database
- Check if the customer is active
If we get through all that lot, we return the customer, if not we return an error message.
If I use an Either
-returning method for step 2, I can do something like this...
static Either<string, int> CheckUser(int n) {
// Check the authed user is in the right role, etc
// For simplicity, we'll decide based on the Id
if (n < 0) {
return "Not authorised to access customer data";
}
return n;
}
static Either<string, Customer> Exists(int n) =>
// This would check the database
n < 10 ? "Unknown customer" : new Customer(n, "Jim Spriggs");
static Either<string, Customer> IsActive(Customer c) {
// This would check the customer, we just use a simple check on the Id for simplicity
if (c.Id % 2 == 0) {
return "Inactive";
}
return c;
}
record Customer(int Id, string Name);
I can then bind this together as follows...
CheckUser(36)
.Bind(Exists)
.Bind(IsActive)
.Match(n => Console.WriteLine($"Success: {n}"), ex => Console.WriteLine($"Ex: {ex}"));
This works, but I can't help but feel that the Exists
method should return an Option<Customer>
rather than an Either<string, Customer>
, eg (again simplified for clarity)...
static Option<Customer> Exists(int n) =>
n < 10 ? Option<Customer>.None : new Customer(n, "Jim Spriggs");
However, I'm struggling to work out how to bind this between the other two methods. I thought that I could use Map
to convert, but couldn't work out how to do this.
Anyone able to advise? Is it OK to use Either
, or should I be using Option
? If the latter, how do I fix my code?
Thanks
CodePudding user response:
Use ToEither:
[Fact]
public void Answer()
{
var actual = CheckUser(36)
.Bind(i => Exists(i).ToEither("Inactive"))
.Bind(IsActive)
.Match(n => $"Success: {n}", ex => $"Ex: {ex}");
Assert.Equal("Ex: Inactive", actual);
}
The above test passes.