using System; using System.Collections.Generic; public struct Either { readonly TLeft left; readonly TRight right; readonly bool isRight; Either(TLeft left, TRight right, bool isRight) { this.left = left; this.right = right; this.isRight = isRight; } public bool IsLeft => !isRight; public bool IsRight => isRight; public TLeft Left { get { if (IsRight) throw new InvalidOperationException("No Left value present."); return left; } } public TRight Right { get { if (IsLeft) throw new InvalidOperationException("No Right value present."); return right; } } public static Either FromLeft(TLeft left) => new (left, default, false); public static Either FromRight(TRight right) => new (default, right, true); public TResult Match(Func leftFunc, Func rightFunc) { return IsRight ? rightFunc(right) : leftFunc(left); } public Either Select(Func map) { return IsRight ? Either.FromRight(map(right)) : Either.FromLeft(left); } public Either SelectMany(Func> bind) { return IsRight ? bind(right) : Either.FromLeft(left); } public static implicit operator Either(TLeft left) => FromLeft(left); public static implicit operator Either(TRight right) => FromRight(right); public override string ToString() => IsRight ? $"Right({right})" : $"Left({left})"; }