c# - 也许是类和可选参数

标签 c# optional-parameters option-type compile-time-constant

我有一个 Maybe/Option 类的 C# 实现。基本实现是

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# 可选参数 必须是完全搞砸的编译时间常数 这个模式。

任何人都可以提出一个修复方案来保持其意图 此处不引入可空值或空值的模式?

无论如何我可以创建一个编译时间常数来 这里代表没有一个可以与我的上面一起使用 Maybe 的实现?

最佳答案

不,你在这里无能为力。您的参数类型是引用类型,这意味着唯一可用的常量值为 null和字符串文字。 (显然,字符串文字在您的情况下没有用;我只是将它们称为唯一类型的非空引用类型常量。)

一种选择是制作 Maybe<T>结构体而不是接口(interface),默认值为“none”值。这基本上与 Nullable<T> 相同。但没有 T 的限制必须是不可为 null 的值类型。然后您可以使用:

void DoSomeCalc(Maybe<double> x = default(Maybe<double>),
                Maybe<double> y = default(Maybe<double>))

显示所有这些的示例代码:

using System;

struct Maybe<T>
{
    private readonly bool hasValue;
    public bool HasValue { get { return hasValue; } }

    private readonly T value;
    public T Value
    {
        get
        {
            if (!hasValue)
            {
                throw new InvalidOperationException();
            }
            return value;
        }
    }

    public Maybe(T value)
    {
        this.hasValue = true;
        this.value = value;
    }

    public static implicit operator Maybe<T>(T value)
    {
        return new Maybe<T>(value);
    }
}

class Test
{
    static void DoSomeCalc(Maybe<double> x = default(Maybe<double>),
                           Maybe<double> y = default(Maybe<double>))
    {
        Console.WriteLine(x.HasValue ? "x = " + x.Value : "No x");
        Console.WriteLine(y.HasValue ? "y = " + y.Value : "No y");
    }

    static void Main()
    {
        Console.WriteLine("First call");
        DoSomeCalc(x: 10);

        Console.WriteLine("Second call");
        DoSomeCalc(y: 20);
    }
}

显然您希望向 Maybe<T> 添加更多功能,例如覆盖 ToStringEquals ,但您已经了解了总体思路。您仍然可以拥有非通用 Maybe当然,类也带有工厂方法。

关于c# - 也许是类和可选参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16293374/

相关文章:

c# - 从 ListView 中检索数据

swift - 带感叹号的类属性仍作为可选返回

haskell - Snap 框架 - 重复也许整理

c# - UWP 中的 Xamarin Forms 切换文本

c# - 需要签名 DLL Microsoft.WindowsAPICodePack.Shell

C# 为所有可选参数提供值

C# - 如何跳过具有默认值的参数?

Java 可选 - 对存储为 Nullable 对象属性的 Nullable 列表进行排序

c# - F# 错误类型 'X' 与类型 'X' 不兼容

c++ - 提供 optional 参数的现代 C++ 方法