类的 C# 可选数组参数

C# Optional Array Parameter for Class

提问人:Adjit 提问时间:10/11/2016 最后编辑:Gilad GreenAdjit 更新时间:9/21/2017 访问量:4542

问:

我知道这可以使用,所以我有一个解决方法,但我想知道是否有更好的方法可以为类提供可选参数?nullint[]

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;
    }
}
C# optional-parameters

评论

3赞 kurakura88 10/11/2016
使用重载
0赞 Ralf Bönning 10/11/2016
可能重复 传递空数组作为可选参数的默认值
0赞 Salah Akbari 10/11/2016
为什么您的财产没有二传手?priceLevels
1赞 Michael McMullin 10/11/2016
@S.Akbari:你可能是对的。但是,如果这个想法是只允许在初始化时设置(因此默认值作为回退),那么它是有效的。priceLevels
1赞 hatchet - done with SOverflow 10/12/2016
设置 C# 可选参数的默认值可能重复

答:

17赞 Gilad Green 10/11/2016 #1

一个更好的设计是有 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;
    }
}

此外,根据设计,我不相信决定默认值是什么是责任,也许它应该在任何情况下将其作为依赖项 - 请参阅 SOLID依赖项注入。那么你只有 1 个构造函数:PriceLevels

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

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

评论

0赞 Salah Akbari 10/11/2016
此外,该物业应该有二传手。priceLevels
0赞 Michael McMullin 10/11/2016
null 合并运算符本身使它“更好”!
0赞 Adjit 10/11/2016
谢谢,我想我可能会接受你的最后建议并重新考虑我的结构。另外,对这个二传手的东西感到好奇......如果我所做的只是在类初始化时设置该值,为什么我必须有一个 setter(即使它是私有的)?
0赞 Gilad Green 10/11/2016
@Adjit - Cubicle.Jockey 在下面评论二传手。
0赞 Ivan Stoev 10/11/2016
@Gilad,我不认为第一部分有效 - 如果您称它为无参数,您仍然会收到空数组,而不是.paramsnull
9赞 jegtugado 10/11/2016 #2

您可以重载构造函数。

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赞 Salah Akbari 10/11/2016
此外,priceLevels 属性应具有 setter。
0赞 jegtugado 10/11/2016
添加了一个私人二传手。谢谢。
2赞 Cubicle.Jockey 10/11/2016
如果是 C# 6.0,则仅在构造函数中设置值时,私有集是不必要的。
7赞 Mathew 10/11/2016 #3

您可以创建另一个没有参数的构造函数,该构造函数只会将 defaultPriceLevels 变量传递给您已有的构造函数?您还必须将变量更改为 static。

例如:

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)
    { }
}

评论

0赞 Mathew 10/11/2016
@DongWei 你肯定能做到。在 linqpad 中试用。
0赞 xqMogvKW 10/11/2016
:对不起,我应该把我说的话贴给OP而不是你:)
1赞 Mrinal Kamboj 10/11/2016
喜欢这个解决方案,但你不应该在其中一个构造函数中使可选,在我看来,这没有好处+1newPriceLevels
4赞 Sweeper 10/11/2016 #4

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

public PriceLevels() : this(defaultPriceLevels) { }

然后,从原始构造函数中删除默认参数值:

public PriceLevels(int[] newPriceLevels)

实际上,您还需要声明为 .希望你不介意。defaultPriceLevelsstatic

3赞 Ralf Bönning 10/11/2016 #5

可选的数组参数在 C# 中是不可实现的。来自 MSDN

每个可选参数都有一个默认值作为其定义的一部分。 如果未为该参数发送参数,则使用默认值。 默认值必须是以下类型的表达式之一:

  • 一个恒定的表达式;
  • 形式为 new ValType() 的表达式,其中 ValType 是一种值类型,例如枚举或结构;
  • 表达式 窗体 default(ValType),其中 ValType 是值类型。

因此,必须使用“解决方法”。检查 null(如您建议的那样),也可以使用默认构造函数。

7赞 Mrinal Kamboj 10/11/2016 #6

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;
  }
}