为什么使用params关键字?

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

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

参数:

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;
}
198057 次浏览

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

它允许您在调用中添加任意数量的基类型参数。

addTwoEach(10, 2, 4, 6)

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

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

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 });。在需要传递单个值而不是整个数组的场景中,可以用于简化。它仍然在方法中以相同的方式处理,但为这种方式调用提供了一些糖果。

使用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到无穷大时,可以使用参数;当参数的数量从1到无穷大时,可以使用数组。

添加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 })

但是当你删除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);

params关键字的一个危险是,如果对方法的调用已经被编码,

    某人不小心/故意从方法签名中删除一个/多个要求参数, 和李< / >
  1. 签名更改之前的params参数之前的一个/多个要求参数与params参数类型兼容,

这些调用将继续使用先前用于要求参数的一个/多个表达式进行编译,这些表达式被视为可选的params参数。我刚刚遇到了最糟糕的情况:params形参的类型是object[]

这是值得注意的,因为开发人员已经习惯了编译器用更常见的场景来拍手腕,其中参数从一个方法中删除所有要求参数(因为预期的参数#会改变)。

对我来说,不值得抄近路。没有params(Type)[]将使用0到无穷大#参数,而不需要重写。最坏的情况是你将不得不在不适用的调用中添加, new (Type) [] {}

顺便说一句,恕我直言,最安全(也是最易读的做法)的做法是:

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

    1.1. 这是只有方式,担保防止在参数顺序、Compatible-Type和/或计数更改后传递给参数的非预期值,

    1.2. 它减少了参数含义改变后的机会,因为反映新含义的可能的新标识符名称就在传递给它的值旁边,

    1.3. 它避免了必须数逗号和跳回&从调用到签名,以查看为什么参数传递了什么表达式,以及

    1.3.1. 顺便说一下,这个原因应该是很多(就避免频繁的容易出错的违反DRY原则而言,只是为了代码,更不用说修改它),但如果有一个/多个表达式被传递,它们本身包含逗号,即多维数组引用或多参数函数调用,这个原因可能是指数级的更重要。在这种情况下,你甚至不能使用(即使你可以,仍然会添加一个额外的步骤参数方法调用)在编辑器中查找所有出现在选择中的特性来自动为你计数逗号。

    1.4. 如果你必须使用可选参数(params或不是),它允许你搜索特定的可选参数被传递的调用(因此,很可能不是或至少有可能不是默认值),

(注:原因1.2.;和1.3。可以减轻和减少错误的机会,甚至在编码初始调用时,更不用说当调用必须读取和/或更改时。))

而且

  1. 这样做ONE - PARAMETER - PER - LINE更好的可读性(因为:

    2.1. 它不那么杂乱,而且

    2.2. 它避免了必须向右滚动。左后(并且必须每一行这样做,因为大多数人不能阅读多行的左边部分,向右滚动并阅读右边部分))。

    2.3. 这与“最佳实践”是一致的;我们已经发展到赋值语句,因为传递的每个参数本质上都是赋值语句(将值或引用分配给局部变量)。就像那些遵循最新的“最佳实践”的人一样;在“编码风格”中不会梦想每行编码多个赋值语句,我们可能不应该(也不会一次);追上了到我的“天才”;;P)在传递参数时这样做。

笔记:

  1. 在以下情况下,传入名称与参数相同的变量没有帮助:

    1.1. 你传递的是字面常量(即简单的0/1,false/true或null,即使是“最佳实践”;可能不需要你使用命名常量,而且它们的目的不能轻易地从方法名推断出来),

    1.2. 方法明显比调用者更低级/更通用,这样你就不会想要/能够将你的变量命名为与参数相同/相似的(反之亦然),或者

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

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

VS应该有一个选项,生成带有命名参数的方法调用片段(当然每行一个;P)和一个编译器选项需要命名参数(在概念上类似于VB中的显式选项,顺便说一下,这个要求可能曾经被认为同样离谱,但现在可能是要求 by "'最佳实践'")事实上,“back In 我的 day”;;),在1991年,在我进入职业生涯的几个月,甚至在我使用(或甚至看到)带有命名参数的语言之前,我就有了反羊群/“只是因为你可以,不意味着你应该”;/不要盲目地“切断烤面包的末端”;有足够的感觉来模拟它(使用内联注释),而没有看到任何人这样做。不必使用命名参数(以及save "'precious'"源代码击键)是穿孔卡时代的遗物,当时大多数这些语法开始。对于现代硬件和IDE以及更复杂的软件来说,可读性是非常非常重要的,这是没有理由的。“代码读的比写的多”。只要您没有复制非自动更新的代码,当有人(甚至是您自己)稍后试图读取时,保存的每一次击键都有可能成倍增加成本。

还有一件重要的事情需要强调。最好使用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[] {});
可能听起来很蠢, 但是Params不允许多维数组。 而你可以将多维数组传递给函数

另一个例子

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


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

它增强了代码的简洁性。既然可以简洁明了,为什么还要冗长呢?

using System;


namespace testingParams
{
class Program
{
private void lengthy(int[] myArr)
{
foreach (var item in myArr)
{
//...
}
}
private void concise(params int[] myArr) {
foreach (var item in myArr)
{
//...
}
}


static void Main(string[] args)
{
Program p = new Program();
//Why be lengthy...:
int[] myArr = new int[] { 1, 2, 3, 4, 5 };
p.lengthy(myArr);
//When you can be concise...:
p.concise(1, 2, 3, 4, 5);
}
}
}

如果删除关键字params,调用者代码将不能正常工作。