为什么要使用params关键字?

时间:2011-09-28 08:23:06

标签: c# parameter-passing params variadic-functions variadic

我知道这是一个基本问题,但我找不到答案。

为什么要用它?如果你编写一个函数或一个使用它的方法,当你删除它时代码仍然可以完美地工作,100%没有它。 E.g:

使用params:

static public int addTwoEach(params int[] args)
{
    int sum = 0;
    foreach (var item in args)
        sum += item + 2;
    return sum;
}

没有参数:

static public int addTwoEach(int[] args)
{
    int sum = 0;
    foreach (var item in args)
       sum += item + 2;
    return sum;
}

11 个答案:

答案 0 :(得分:457)

使用params ,您可以像这样调用您的方法:

addTwoEach(1, 2, 3, 4, 5);

没有params,你就不能。

此外,您可以在两种情况下使用数组作为参数调用该方法

addTwoEach(new int[] { 1, 2, 3, 4, 5 });

也就是说,params允许您在调用方法时使用快捷方式。

无关,你可以大大缩短你的方法:

public static int addTwoEach(params int[] args)
{
    return args.Sum() + 2 * args.Length;
}

答案 1 :(得分:87)

使用params允许您在没有参数的情况下调用该函数。没有params

static public int addTwoEach(int[] args)
{
    int sum = 0;

    foreach (var item in args)
    {
        sum += item + 2;
    }

    return sum;
}

addtwoEach(); // throws an error

params比较:

static public int addTwoEach(params int[] args)
{
    int sum = 0;

    foreach (var item in args)
    {
        sum += item + 2;
    }

    return sum;
}

addtwoEach(); // returns 0

通常,当参数的数量从0到无穷大时,你可以使用params,当参数的数量从1到无穷大时,你可以使用数组。

答案 2 :(得分:20)

它允许您根据需要在通话中添加任意数量的基本类型参​​数。

addTwoEach(10, 2, 4, 6)

而对于第二种形式,您必须使用数组作为参数

addTwoEach(new int[] {10,2,4,6})

答案 3 :(得分:14)

params关键字存在一个危险,如果调用方法之后已编码,

  1. 某人意外/故意从方法签名中删除一个/多个必需的参数, 和
  2. 一个/多个必需签名更改前params参数之前的参数与params参数类型兼容,
  3. 这些调用将继续使用之前用于 required 的一个或多个表达式进行编译。参数被视为可选的params参数。我遇到了最糟糕的情况:params参数属于object[]类型。

    这是值得注意的,因为开发人员习惯于编译器拍摄他们的手腕,其中更常见的情况是从具有所有必需参数的方法中删除参数(因为预期的参数数量将是变化)。

    对我而言,它不值得捷径。没有(Type)[]的{​​{1}}将使用0到无穷大的参数#而无需覆盖。最糟糕的情况是,您必须在不适用的情况下向params添加{。}}。

    顺便说一下,imho,最安全(也是最可读的做法)是:

    1. 通过命名参数传递(我们现在可以在C#~2 几十年甚至在我们可以在VB之后执行; P)(因为:

      1.1。它是唯一的方式,保证防止在参数顺序,兼容类型和/或计数调用后编号更改后传递给参数的非预期值,< / p>

      1.2。在参数意义改变之后减少那些机会,因为反映新含义的新标识符名称就在传递给它的值的旁边,

      1.3。它避免了必须计算逗号并跳回来&amp;从Call to Signature中查看表达式的参数和

      1.3.1。顺便说一句,这个理由应该很多(就避免频繁出错的违反DRY原则而言只是为了读取代码而不仅仅是修改它),但如果有一个或多个表达式传递本身包含逗号,即多维数组引用或多参数函数调用,则此原因可能指数更重要。在这种情况下,您甚至无法使用(即使您可以,仍然会添加额外的步骤参数方法调用)a Find All Occurrences在编辑器的“选择”功能中,可以自动为您计算逗号。

      1.4。如果你必须使用可选参数(, new (Type) [] {}或不使用),它允许你搜索特定可选参数被传递的呼叫(因此,很可能不是或至少有可能不是默认值),

    2. (注意:原因1.2。和1.3。即使在编写初始呼叫时也可以减轻和减少错误的可能性,更不用说何时必须读取和/或更改呼叫。)

      1. 这样做一个参数 - 每个线路以获得更好的可读性(因为:

        2.1。它不那么混乱了,

        2.2。它避免了向右滚动和放大后左(并且必须这样做PER - LINE,因为大多数凡人都无法读取多行的左侧部分,向右滚动并阅读右侧部分)。

        2.3。它符合&#34;最佳实践&#34;我们已经演变为分配语句,因为每个传递的参数本质上是一个赋值语句(为本地变量赋值或引用)。就像那些关注最新&#34;最佳实践&#34;在编码风格中我们不会梦想每行编码多个作业语句,我们可能不应该(并且一次赢得#34;最佳实践&#34; 赶上我的&#34;天才&#34;; P)在传递参数时这样做。

      2. 注意

        1. 传入名称与参数相对应的变量&#39;在以下情况下没有帮助:

          1.1。您传入了文字常量(即简单的0/1,false / true或null,即使&#34;&#39;最佳实践&#39;&#34;可能不需要您使用命名常量并且可以从方法名称中轻松推断出它们的目的,

          1.2。该方法比调用者显着更低级别/更通用,因此您不希望/能够将您的变量命名为与参数相同/相似(反之亦然),或

          1.3。您重新排序/替换签名中可能导致先前调用仍在编译的参数,因为类型发生仍然兼容。

        2. 拥有像VS这样的自动换行功能只能消除上面给出的8个原因中的一个(#2.2)。在VS 2015之前,它没有自动缩进(!?!真的,MS?!?),这增加了理由#2.1的严重性。

        3. VS应该有一个选项,可以生成带有命名参数的方法调用片段(当然每行一个; P)和需要命名参数的编译器选项(概念类似于VB中的Option Explicit) ,顺便说一句,这个要求曾经被认为是同样令人发指的,但现在已经超过要求&#34;&#39;最佳实践&#39;&#34;)。事实上,&#34;回到我的日&#34; ;),1991年,在我职业生涯的几个月里,甚至在我使用(或者甚至看过)一种带有命名参数的语言之前,我就有了反对她/&#34;只是因为你能做到,不要吝啬你应该&#34; /不要盲目地削减烤肉的末端&#34;感觉足够模拟它(使用内嵌评论),而没有看到任何人这样做。不必使用命名参数(以及保存&#34;&#39;宝贝&#39;&#34;源代码击键)的其他语法是大多数这些语法开始时Punch Card时代的遗留物。对于现代硬件和IDE以及更复杂的软件而言,没有任何借口可读性很多,很多, MUCH 更重要。 &#34;代码的读取频率比写入的频率高得多。只要您不复制非自动更新的代码,当有人(甚至是您自己)稍后尝试阅读时,保存的每次击键都可能成倍增加。

答案 4 :(得分:9)

无需创建重载方法,只需使用一个带params的方法,如下所示

// Call params method with one to four integer constant parameters.
//
int sum0 = addTwoEach();
int sum1 = addTwoEach(1);
int sum2 = addTwoEach(1, 2);
int sum3 = addTwoEach(3, 3, 3);
int sum4 = addTwoEach(2, 2, 2, 2);

答案 5 :(得分:4)

params还允许您使用单个参数调用该方法。

private static int Foo(params int[] args) {
    int retVal = 0;
    Array.ForEach(args, (i) => retVal += i);
    return retVal;
}

即。 Foo(1);代替Foo(new int[] { 1 });。在您可能需要传入单个值而不是整个数组的情况下,对于速记有用。它仍然在方法中以相同的方式处理,但为这种方式调用提供了一些糖果。

答案 6 :(得分:4)

添加params关键字本身表明您可以在调用该方法时传递多个参数,而不使用它是不可能的。更具体一点:

static public int addTwoEach(params int[] args)
{
    int sum = 0;

    foreach (var item in args)
    {
        sum += item + 2;
    }

    return sum;
}

当您调用上述方法时,您可以通过以下任何一种方式调用它:

  1. addTwoEach()
  2. addTwoEach(1)
  3. addTwoEach(new int[]{ 1, 2, 3, 4 })
  4. 但是当你删除params关键字时,只有上面给出的第三种方式才能正常工作。对于第一和第二种情况,您将收到错误。

答案 7 :(得分:0)

还有一件重要的事情需要强调。最好使用params,因为它可以提高性能。当您使用params参数调用方法并没有传递任何参数时:

public void ExampleMethod(params string[] args)
{
// do some stuff
}

致电:

ExampleMethod();

然后,.Net Framework的新版本执行此操作(来自.Net Framework 4.6):

ExampleMethod(Array.Empty<string>());

Array.Empty对象可以在以后由框架重用,因此无需进行冗余分配。当您像这样调用此方法时,将发生这些分配:

 ExampleMethod(new string[] {});

答案 8 :(得分:0)

可能听起来很愚蠢, 但是Params不允许多维数组。 而您可以将多维数组传递给函数。

答案 9 :(得分:0)

另一个例子

public IEnumerable<string> Tokenize(params string[] words)
{
  ...
}

var items = Tokenize(product.Name, product.FullName, product.Xyz)

答案 10 :(得分:0)

它增强了简洁。当你可以很快的时候,为什么要传统?

{{1}}