我在 c# 中有一个 Maybe / Option 类的实现。基本实现是
public delegate Maybe<TOutput> Converter<in TInput, out TOutput>(TInput input);
public delegate TOutput ElseDelegate<out TOutput>();
public delegate Maybe<TOutput> ElseDelegate2<out TOutput>();
public interface Maybe<out TResult> : IEnumerable<TResult>
{
Maybe<B> Bind<B>(Converter<TResult, B> f);
TResult Value();
bool IsSome();
}
public static class Maybe
{
public static Maybe<T> None<T>()
{
return new None<T>();
}
}
public interface INone<out TResult> : Maybe<TResult>
{
}
public interface ISome<out TResult> : Maybe<TResult>
{
}
public struct None<TResult> : INone<TResult>
{
public IEnumerator<TResult> GetEnumerator()
{ yield break; }
IEnumerator IEnumerable.GetEnumerator()
{ yield break; }
public bool IsSome() { return false; }
public Maybe<TOutput> Bind<TOutput>(Converter<TResult, TOutput> f)
{
return new None<TOutput>();
}
public TResult Value()
{
throw new IndexOutOfRangeException("None has no value");
}
}
public struct Some<TResult> : Maybe<TResult>
{
private TResult _Value;
public Some(TResult value)
{
_Value = value;
}
public IEnumerator<TResult> GetEnumerator()
{ yield return _Value; }
IEnumerator IEnumerable.GetEnumerator()
{ yield return _Value; }
public bool IsSome() { return true; }
public Maybe<TOutput> Bind<TOutput>(Converter<TResult, TOutput> f)
{
return f(_Value);
}
public TResult Value()
{
return this._Value;
}
}
#endregion
有一堆我在这里没有包括的扩展方法。这一切都很好。然而,我想实现的标准模式如下,使用 Maybe 来实现可选参数默认值,如 F#
void DoSomeCalc
( Maybe<double> x = Maybe.None<double>()
, Maybe<double> y = Maybe.None<double>()
)
{
this.X = x.Else( ()=> CalculateDefaultX() );
this.Y = y.Else( ()=> CalculateDefaultY() );
}
所以我可以
DoSomeCalc(x:10)
或者
DoSomeCalc(y:20)
如果 None 可用,则 Else 提供一个值。然而,这在理论上都很好,但是 C# 可选参数必须是编译时常量,这完全破坏了这种模式。
任何人都可以提出一个修复方案来保持模式的意图而不在这里引入可空值或空值吗?
无论如何我可以创建一个编译时间常量来代表 None ,这将与我上面的 Maybe 实现一起工作?