C#类的可选数组参数

15

我知道可以使用null来实现,所以我有一个解决方法,但是我想知道是否有更好的方法可以为类拥有可选的int[]参数?

class PriceLevels
{
    public int[] priceLevels { get; }
    private readonly int[] defaultPriceLevels = { 2, 3, 3, 4, 5, 6 };

    public PriceLevels(int[] newPriceLevels = defaultPriceLevels)
    {
        priceLevels = newPriceLevels;
    }
}

这给了我一个错误,说它是一个无效的表达式defaultPriceLevels必须是常数。我该如何解决?

我能想到的一个解决方法是这样的,但我不太喜欢这个解决方案。

class PriceLevels
{
    public int[] priceLevels { get; }
    private readonly int[] defaultPriceLevels = { 2, 3, 3, 4, 5, 6 };

    public PriceLevels(int[] newPriceLevels = null)
    {
        if(newPriceLevels == null) 
            priceLevels = defaultPriceLevels;
        else 
            priceLevels = newPriceLevels;
    }
}

3
使用重载。 - kurakura88
可能是将空数组作为可选参数的默认值传递的重复问题。 - Ralf Bönning
为什么你的 priceLevels 属性没有设置器? - Salah Akbari
函数输入值的默认值赋值可以与“const”赋值规则相同...因此,直到现在你的默认值不能直接实现。 - xqMogvKW
1
@S.Akbari 你说得可能是对的,然而如果想法是仅在初始化时允许设置 priceLevels(因此默认值作为回退),那么这是有效的。 - Michael McMullin
1
可能是设置C#可选参数的默认值的重复问题。 - hatchet - done with SOverflow
6个回答

17

更好的设计是拥有2个构造函数构造函数重载),其中一个接收 int[],另一个不接受:

class PriceLevels
{
    public int[] priceLevels { get; set; }
    private readonly int[] defaultPriceLevels = { 2, 3, 3, 4, 5, 6 };

    public PriceLevels()
    {
        priceLevels = defaultPriceLevels;
    }

    public PriceLevels(int[] newPriceLevels)
    {
       priceLevels = newPriceLevels;
    }
}

如果不行的话,我不知道是否能称之为“更好”,但您可以使用 params 关键字

class PriceLevels
{
    public int[] priceLevels { get; set; }
    private readonly int[] defaultPriceLevels = { 2, 3, 3, 4, 5, 6 };

    public PriceLevels(params int[] newPriceLevels)
    {
        priceLevels = newPriceLevels.Length == 0 ? defaultPriceLevels : newPriceLevels;
    }
}

此外,根据设计,我并不认为PriceLevels应该负责决定默认值,也许在任何情况下它都应该作为依赖项获取 - 参见SOLID依赖注入。然后你只需要一个构造函数:

class PriceLevels
{
    public int[] priceLevels { get; set; }

    public PriceLevels(int[] newPriceLevels)
    {
       priceLevels = newPriceLevels;
    }
}

priceLevels属性也应该有setter。 - Salah Akbari
空值合并运算符本身使它“更好”! - Michael McMullin
谢谢,我想我可能会采纳你的最终建议并重新思考我的结构。另外,我对这个setter的事情很好奇...如果我所做的只是在类初始化时设置该值,那么为什么需要有一个setter(即使它是私有的)呢? - Adjit
@Adjit - Cubicle.Jockey在下面评论了有关setter的内容。 - Gilad Green
@Gilad,我认为第一部分使用params不起作用 - 如果您在没有参数的情况下调用它,您仍然会收到空数组,而不是null - Ivan Stoev
@IvanStoev - 没错。已测试,你是正确的。我漏掉了它。问题已解决。谢谢 :) - Gilad Green

9

您可以重载构造函数。

class PriceLevels
{
    public int[] priceLevels { get; private set; }
    private readonly int[] defaultPriceLevels = { 2, 3, 3, 4, 5, 6 };

    public PriceLevels()
    {
        priceLevels = defaultPriceLevels;
    }

    public PriceLevels(int[] newPriceLevels)
    {
       priceLevels = newPriceLevels;
    }
}

1
同时,priceLevels属性应该有一个setter方法。 - Salah Akbari
添加了一个私有的setter。谢谢。 - jegtugado
2
如果在C# 6.0中,只有在构造函数中设置值时,private set是不必要的。 - Cubicle.Jockey

7
你可以创建另一个无参构造函数,只需将默认价格级别变量传递给你已经有的构造函数即可?你还需要将该变量更改为静态的。
例如:
class PriceLevels
{
    public int[] priceLevels { get; }
    private static int[] defaultPriceLevels = { 2, 3, 3, 4, 5, 6 };

    public PriceLevels(int[] newPriceLevels = null)
    {
        if (newPriceLevels == null) priceLevels = defaultPriceLevels;
        else priceLevels = newPriceLevels;
    }

    public PriceLevels() : this(defaultPriceLevels)
    { }
}

@DongWei,你肯定能做到。在LinqPad中试一试吧。 - Mathew
抱歉,我应该将我对原帖的回复粘贴到你的位置,而不是你。 :) - xqMogvKW
1
喜欢这个解决方案,但你不应该在其中一个构造函数中将 newPriceLevels 设为可选项,我认为这没有任何好处。+1 - Mrinal Kamboj

7
在 Crowd 中,另一个选项与您的原始代码最接近。
class PriceLevels
{
  public int[] priceLevels { get; set; }

  private readonly int[] defaultPriceLevels = { 2, 3, 3, 4, 5, 6 };

  public PriceLevels(int[] newPriceLevels = null)
  {
     priceLevels = newPriceLevels ?? defaultPriceLevels;
  }
}

4

只需创建构造函数的重载!它可以通过一行代码轻松完成!

public PriceLevels() : this(defaultPriceLevels) { }

接下来,从原始构造函数中删除默认参数值:

public PriceLevels(int[] newPriceLevels)

实际上,你还需要将defaultPriceLevels声明为static。希望你不介意。


3
C#中不支持可选数组参数。来自MSDN
每个可选参数都有一个默认值作为其定义的一部分。如果没有为该参数发送任何参数,则使用默认值。默认值必须是以下类型之一的表达式:
  • 常量表达式;
  • 形式为new ValType()的表达式,其中ValType是值类型,例如枚举或结构体;
  • 形式为default(ValType)的表达式,其中ValType是值类型。
因此,必须使用“解决方法”。要么检查null(如您建议的那样),要么使用默认构造函数。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接