I've been experimenting with functional programming concepts for C# and encountered with the Either
monad, which in F# would be Choice
if I'm not mistaken. C# doesn't have this type natively implemented and I've come with a very naive implementation of it.
// Don't use this code in production, this is just an experiment type
public record Either<T1, T2> where T1: class where T2 : class
{
public static implicit operator Either<T1, T2>(T1 typeOne)
=> (Either<T1, T2>)(object)typeOne;
public static implicit operator Either<T1, T2>(T2 typeTwo)
=> (Either<T1, T2>)(object)typeTwo;
public static implicit operator T1(Either<T1, T2> either)
=> (T1)(object)either;
public static implicit operator T2(Either<T1, T2> either)
=> (T2)(object)either;
}
The compiler accepts any implicit conversion I do with the types defined when constructing the generic.
// Accepted by the compiler
Either<Foo, Bar> someBar = new Bar();
Bar actualBar = someBar;
// Rejected by the compiler as expected
Either<Foo, Bar> wrong = new MyClass();
But it doesn't accept pattern matching the same type with the respective generics
_ = someBar switch
{
// Error: an expression of type 'Either<Foo, Bar>' cannot be handled by a pattern of type 'Foo'
Foo => Console.WriteLine("Foo works!"),
// Error: an expression of type 'Either<Foo, Bar>' cannot be handled by a pattern of type 'Bar'
Bar => Console.WriteLine("Bar works!"),
// Works fine
null => Console.WriteLine("Null works!")
}
I've done some research and the only requirement I found for a type to use pattern matching is having implicit or explicit conversions, not sure if this is right but I found not only in this answer, but in others too.
How am I supposed to design my generic type to work with pattern matching?