這聽起來像你真正想要的是和類型。雖然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