这听起来像你真正想要的是和类型。虽然C#没有内置这些内容,但函数式编程还有一个技巧可以使用,称为Church编码来实现这一点。它完全是类型安全的,不涉及任何类型的转换,但是由于类型推断的局限性,在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);
}
}
参考文献:
谢谢!这正是我所期待的。 – Vladislav
@Vladislav这与类似于理查尔的答案(基本上这个想法是使用元组类型来保存异类数据),但我想你可以结合两者的想法使它更短(我说这是因为你喜欢它不详细)。 – nawfal