Похоже, что вы действительно хотите, это сумма типа. Хотя в C # они не встроены, в функциональном программировании есть хитрость, которую вы можете использовать под названием церковное кодирование для достижения этой цели. Он полностью безопасен для типов, без приведения типов, однако его использование в C # немного странно, в основном из-за ограничений вывода типов.
Основная хитрость заключается в том, что вместо использования свойств и проверок для извлечения одной из двух альтернатив мы имеем функцию более высокого порядка Map
, которая принимает две функции в качестве аргументов и вызывает соответствующую функцию в зависимости от того, какая альтернатива присутствовала. Вот как вы бы это использовали:
var stack = new Stack<IEither<Operator, Parenthesis>>();
stack.Push(new Left<Operator, Parenthesis>(new Operator()));
stack.Push(new Right<Operator, Parenthesis>(new Parenthesis()));
while (stack.Count > 0)
{
stack.Pop().Map(op => Console.WriteLine("Found an operator: " + op),
par => Console.WriteLine("Found a parenthesis: " + par));
}
Вот реализация IEither
, Left
и Right
. Они полностью универсальны и могут использоваться в любом месте, где вам нужен тип суммы.
public interface IEither<TLeft, TRight>
{
TResult Map<TResult>(Func<TLeft, TResult> onLeft, Func<TRight, TResult> onRight);
void Map(Action<TLeft> onLeft, Action<TRight> onRight);
}
public sealed class Left<TLeft, TRight> : IEither<TLeft, TRight>
{
private readonly TLeft value;
public Left(TLeft value)
{
this.value = value;
}
public TResult Map<TResult>(Func<TLeft, TResult> onLeft, Func<TRight, TResult> onRight)
{
return onLeft(value);
}
public void Map(Action<TLeft> onLeft, Action<TRight> onRight)
{
onLeft(value);
}
}
public sealed class Right<TLeft, TRight> : IEither<TLeft, TRight>
{
private readonly TRight value;
public Right(TRight value)
{
this.value = value;
}
public TResult Map<TResult>(Func<TLeft, TResult> onLeft, Func<TRight, TResult> onRight)
{
return onRight(value);
}
public void Map(Action<TLeft> onLeft, Action<TRight> onRight)
{
onRight(value);
}
}
Ссылки: