如何区分省略的参数和参数默认值

时间:2016-12-19 21:21:34

标签: c#

我正在编写一种方法(让我们称之为' Bar'),它接受许多参数。为方便起见,我设置了一个默认值,因此开发人员不必指定一堆“空”'在调用我的方法时。换句话说,我的方法的签名如下所示:

public void Bar(string paramA = null, string paramB = null, ... many more parameters omitted...)

我的方法中的代码检查空值并在这种情况下忽略参数。但是,在某些情况下,我需要区分默认情况' null值和开发人员故意设置的空值。

这是两个示例调用,用于说明我正在谈论的内容。第一个省略所有参数(因此C#编译器将在编译时用null替换它们)和开发人员决定指定的第二个样本' null'对于第一个参数。

Bar();
Bar(null);

我找到了几篇关于使用" Option / Some / None"图案。在我看来,最好的是here

但我正在努力弄清楚我仍然可以提供一个'默认'开发商的价值'方便。从概念上讲,我想写这样的东西:

public void Bar(Option<string> paramA = Option.None)

但是C#编译器抱怨&#39; Option.None&#39;不是编译时常量。

4 个答案:

答案 0 :(得分:2)

C#具有“重载”的概念,它是具有相同名称但具有不同参数的C#方法。

private void MethodA(string param1) {

}

private void MethodA(string param1, string param2) {

}

如果这不是您想要的,您还可以使用构建器模式。如果你担心这种事情,Builder可能是一个减少内存分配的结构。

var result = new Builder()
  .SetParam1(value)
  .SetParam2(value)
  .Build();

答案 1 :(得分:2)

不,没有办法区分它们。事实上,&#34;默认&#34;值被编译器烘焙到调用中,所以

Bar();

Bar(null);

导致等效的IL。

通常我会建议重载而不是默认值,但由于你有几个参数,重载次数会呈指数级增长。

如果您需要区分null和&#34;默认&#34;那么你需要使用其他东西作为默认值。

另一种选择是创建一个可以存储所有参数值的类型。然后你可以判断一个&#34;参数&#34;是设置为null而默认为null,因为您可以挂钩到属性设置器。

答案 2 :(得分:1)

这基本上就是Nul​​lable的用途。虽然它用于结构体,但您可以创建自己的包装类来执行相同的操作(使用强制转换操作符等)。

例如,您可以创建Argument&lt; T&gt;看起来像T一样,但有一个名为Set的属性返回一个bool。

然后你可以定义你的方法:

public void Bar(Argument<string> paramA = null, ...)

这是一个完整的例子,但我不得不承认我对它不满意。当作为参数传递时,我似乎无法获得隐式强制转换操作符。我曾经认为C#在几年前加入了这种强制,当时他们做了协变和逆变的演员。也许我错了。所以它仍然需要一个演员(我正在通过扩展方法)。

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Calling Foo(default(string).ToArg())...");
        Foo(default(string).ToArg());

        Console.WriteLine("Calling Foo(((string)null).ToArg())...");
        Foo(((string)null).ToArg());

        Console.WriteLine("Calling Foo(\"test\".ToArg())...");
        Foo("test".ToArg());

        Console.WriteLine("Calling Foo()...");
        Foo();
        Console.ReadLine();
    }

    public static void Foo(Argument<string> arg1 = null)
    {
        Console.WriteLine("arg1 is {0}null", arg1 == null ? "" : "not ");
        Console.WriteLine("arg1.IsSet={0}", arg1?.IsSet ?? false);
        Console.WriteLine("arg1.Value={0}", arg1?.Value ?? "(null)");
    }

}

public class Argument<T>
{
    public Argument()
    {
        IsSet = false;
    }

    public Argument(T t)
    {
        _t = t;
        IsSet = true;
    }

    private T _t;

    public T Value { get { return _t; } set { _t = value; IsSet = true; } }
    public bool IsSet { get; private set; }
    public static implicit operator T(Argument<T> t) { return t._t; }

}

public static class Extensions
{
    public static Argument<string> ToArg(this string s) { return new Argument<string>(s); }

}

答案 3 :(得分:-2)

根据类型,您可以执行以下操作:

public static void Bar(string a = "", int b = 0) {

因为它们都没有价值,但仍然可以选择为空。 对于布尔值,我只是默认为false,因为布尔值是不可为空的。 这样:

public static void Bar(string a = "", int b = 0) {
if (a == "") {
// if there is no parameter
}
else {
// stuff
}
if (b == 0) {
// no param
}
else {
// stuff
}

希望我帮忙!