Created
March 7, 2024 14:31
-
-
Save AlexeyRaga/9180b7d9f18c3ecd01fc401f1f648d88 to your computer and use it in GitHub Desktop.
Either in C#
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public abstract record Either<TLeft, TRight> | |
{ | |
// there can be no more cases defined! | |
private Either() {} | |
public sealed record Left(TLeft Value) : Either<TLeft, TRight>; | |
public sealed record Right(TRight Value) : Either<TLeft, TRight>; | |
} | |
public static class Either | |
{ | |
public static Either<TLeft, TRight> Left<TLeft, TRight>(TLeft value) => new Either<TLeft, TRight>.Left(value); | |
public static Either<TLeft, TRight> Right<TLeft, TRight>(TRight value) => new Either<TLeft, TRight>.Right(value); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static class EitherExtensions | |
{ | |
public static bool IsLeft<TLeft, TRight>(this Either<TLeft, TRight> either) => either is Either<TLeft, TRight>.Left; | |
public static bool IsRight<TLeft, TRight>(this Either<TLeft, TRight> either) => either is Either<TLeft, TRight>.Right; | |
public static Either<TLeft, TResult> Select<TLeft, TRight, TResult>(this Either<TLeft, TRight> either, Func<TRight, TResult> selector) => | |
either switch | |
{ | |
Either<TLeft, TRight>.Left left => Either.Left<TLeft, TResult>(left.Value), | |
Either<TLeft, TRight>.Right right => Either.Right<TLeft, TResult>(selector(right.Value)), | |
_ => throw new InvalidOperationException("Invalid state") | |
}; | |
public static Either<TLeft, TResult> SelectMany<TLeft, TRight, TResult>(this Either<TLeft, TRight> either, Func<TRight, Either<TLeft, TResult>> selector) => | |
either switch | |
{ | |
Either<TLeft, TRight>.Left left => Either.Left<TLeft, TResult>(left.Value), | |
Either<TLeft, TRight>.Right right => selector(right.Value), | |
_ => throw new InvalidOperationException("Invalid state") | |
}; | |
public static Either<TLeft, TResult> SelectMany<TLeft, TRight, TCollection, TResult>(this Either<TLeft, TRight> either, Func<TRight, Either<TLeft, TCollection>> collectionSelector, Func<TRight, TCollection, TResult> resultSelector) => | |
either switch | |
{ | |
Either<TLeft, TRight>.Left left => Either.Left<TLeft, TResult>(left.Value), | |
Either<TLeft, TRight>.Right right => collectionSelector(right.Value).SelectMany(collection => Either.Right<TLeft, TResult>(resultSelector(right.Value, collection))), | |
_ => throw new InvalidOperationException("Invalid state") | |
}; | |
public static Either<TResult, TRight> SelectLeft<TResult, TLeft, TRight>(this Either<TLeft, TRight> either, Func<TLeft, TResult> selector) => | |
either switch | |
{ | |
Either<TLeft, TRight>.Left left => Either.Left<TResult, TRight>(selector(left.Value)), | |
Either<TLeft, TRight>.Right right => Either.Right<TResult, TRight>(right.Value), | |
_ => throw new InvalidOperationException("Invalid state") | |
}; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// setup some types | |
var name = Either.Right<string, string>("Alexey"); | |
var height = Either.Right<string, int>(188); | |
var error = Either.Left<string, string>("Boom!"); | |
// use LINQ expression | |
var linked = name.SelectMany(x => height.Select(y => (x, y))); | |
Console.WriteLine(linked); // Right { Value = (Alexey, 188) } | |
// use LINQ syntax | |
var result = | |
from n in error | |
from h in height | |
select (n, h); | |
Console.WriteLine(result); // Left { Value = Boom! } | |
// use pattern matching | |
var patternMatched = error switch | |
{ | |
Either<string, string>.Left(var value) => $"It's Left: {value}", | |
Either<string, string>.Right(var value) => $"It's Right: {value}", | |
_ => "Unknown type" // It's a good practice to include a fallback case, though it's not strictly necessary here. | |
}; | |
Console.WriteLine(patternMatched); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment