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

为什么使用它?如果编写使用该函数的函数或方法,则将其删除时,代码仍将正常运行,如无此代码,则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;
}


评论

该方法本身的代码仍然可以正常使用...调用代码可能不会...

params关键字表示可以传递给方法或不传递给方法的可选参数。没有参数关键字的数组意味着您必须将数组参数传递给方法。

Python语言很好地实现了相同的概念,就像这里提到的那样带有星号(*)前缀参数。

#1 楼

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


评论


@Ken:您可能需要导入System.Linq命名空间:)

–Ranhiru Jude Cooray
2011-09-28 8:31



或返回args.Sum(i => i + 2);

–bornfromanegg
15年2月19日在11:44

但是,委托的总和确实增加了已编译代码的复杂性,这可能会降低性能。在这种特殊情况下,这并不重要,因为它不会导致任何关闭,但是值得知道编译器为做出最佳选择实际上在做什么。

–小艾伦·克拉克·科普兰(Allen Clark Copeland Jr)
15年11月28日在22:15



您也可以使用return args.Select(x => x + 2).Sum();

– bbvg
17年8月22日在21:07



添加参数时,您无需添加其他方法参数,而不会破坏调用程序或方法解析。

–杨先生
19年12月3日,0:09

#2 楼

使用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到无穷大时使用一个数组。

评论


实际上,数组可以为空。新的int [0]。希望这可以帮助! :)

– vidstige
2013年12月21日在14:28

#3 楼

它允许您根据需要在调用中添加尽可能多的基本类型参​​数。

addTwoEach(10, 2, 4, 6)


而第二种形式则必须使用数组作为参数

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


#4 楼

params关键字的一种危险是,如果在对方法的调用进行编码后,


有人意外/有意从方法签名中删除了一个/多个必需的参数,

需要一个/多个params之前的参数与params的参数类型兼容,

那些调用将继续使用以前打算用于的一个/多个表达式进行编译必需参数被视为可选的params参数。我只是遇到了最糟糕的情况:params参数的类型为object[]

这是值得注意的,因为开发人员已经习惯了编译器以很多更常见的情况使用参数从具有所有必需参数的方法中删除(因为预期的参数数量会发生变化)。

对我来说,这不值得捷径不带(Type)[]params可以使用0到无穷大数量的参数,而无需覆盖。最糟糕的情况是,您必须在不适用的Calls上添加, new (Type) [] {}

,恕我直言,最安全(也是最易读的做法)是:



通过命名参数传递(即使在C#中,我们现在也可以在VB; P中使用它二十年左右)(因为:

1.1。这是唯一的方法可以确保防止在参数顺序后传递给参数的意外值,在对调用进行编码后对Compatible-Type和/或计数进行更改,

1.2。减少了在参数含义改变后发生这些可能性,因为反映新含义的新标识符名称紧邻传递给它的值,

1.3。它避免了必须计算逗号并从Call to Signature来回跳转以查看传递了什么Expression。表示什么参数,

1.3.1。顺便说一句,仅是这个原因就足够了(就避免经常发生容易出错的DRY原则的违反而言,只是为了阅读代码,更不用说对其进行修改了),但是如果存在一个/更多传递的表达式本身包含逗号,即多维数组引用或多参数函数调用。在这种情况下,您甚至无法使用(即使可能,每个方法调用的每个参数仍要添加一个额外的步骤)在编辑器中的“选择”功能中查找所有事件以自动进行逗号计数。

1.4。如果必须使用可选参数(是否为params),则它允许您搜索传递了特定可选参数的呼叫(因此,很可能不是或至少有可能不是默认值),


(注意:原因1.2。和1.3。甚至可以简化并减少出错的可能性,即使在对初始Call进行编码时,更不用说在必须读取和/或更改Call的情况下了。))





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

2.1。


2.2。它避免了向右和向左滚动(并且必须这样做),因为大多数凡人不能读取多行的左侧部分,因此可以向右滚动并读取右部分))。

2.3。它与我们已经为赋值语句演变成的“最佳实践”相一致,因为传递的每个参数本质上都是一个赋值语句(分配值或对局部变量的引用)。就像那些遵循最新的“最佳实践”编码风格的人不会梦想每行编码多个赋值语句一样,我们可能不应该(而且“最佳实践”不会赶上我的“天才”; P )在传递参数时执行此操作。


注释:





1.1。传递名称与参数相匹配的变量无济于事。您传入的是文字常量(即简单的0/1,false / true或null,即使“'最佳实践'”可能也不需要您使用命名常量,并且无法从方法名称中轻松推断出它们的用途) ),

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

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

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

VS应该有一个选项,该选项生成带有命名参数的方法调用代码段(每行一个; P),以及一个需要命名参数的编译器选项(概念上类似于VB中的Option Explicit,顺便说一句,对需求的要求很容易想到)同样令人发指,但现在“最佳做法”确实要求这样做)。实际上,“回到今天”;),在我职业生涯的前几个月,即1991年,甚至在我使用(或什至没有看到)一种名为“命名参数”的语言之前,我就有了反sheeple /“只要你能,并不意味着您应该” /不要盲目地“削减烤肉的末端”的感觉,以模拟它(使用内联注释),而没有看到任何人这样做。当大多数语法开始时,不必使用命名参数(以及其他保存“'precious'”源代码击键的语法),这是打孔卡时代的遗物。对于现代的硬件和IDE以及更复杂的软件而言,这没有任何借口,因为可读性非常重要。 “代码被读取的次数要多于被写入的次数”。只要您不复制非自动更新的代码,当有人(甚至您自己)稍后尝试阅读它时,保存的每个击键都可能成倍增加成本。

评论


我不明白您为什么不能仅仅强制至少有一个?即使没有参数,也没有什么可以阻止您传递null或new object [0]作为参数。

–卡西
15-10-28在13:38

在可选参数之前没有必需参数可能太危险了(以防在对调用进行编码后删除了这些必需参数中的一个或多个)。这可能就是为什么我从未在任何有关可选参数的文档的示例代码中的可选参数之前看到必需参数的原因。顺便说一句,恕我直言,最安全(也是最易读的做法)是通过命名参数传递(即使在C#中,我们现在也可以在VB中使用它约二十年了)。 VS应该有一个选项可以生成带有命名参数的方法调用代码片段(并且每行1个参数)。

–汤姆
17 Mar 7'7 at 2:41

我不太确定你的意思。拥有必需参数和可选参数的唯一方法是首先指定所有必需参数。

–卡西
17 Mar 8 '17 at 3:55

例如我将myMethod声明为void myMethod(int requiredInt,params int [] optionalInts)。我/其他人对一个/多个调用进行了编码,即myMethod(1),myMethod(1、21),myMethod(1、21、22)。我将myMethod更改为无效的myMethod(params int [] optionalInts)。即使显然不打算将它们的第一个参数(“ 1”)作为OptionalInts参数的第一个元素传递,所有这些调用仍将编译没有错误。

–汤姆
17 Mar 9 '17 at 5:11



哦。好吧,在特定情况下,建议不要这样做。如果您需要一个字符串和0对多整数或任何其他值,我认为没有任何理由避免使用它。

–卡西
17 Mar 9 '17 at 17:52

#5 楼

无需创建重载方法,只需使用带有参数的单个方法,如下所示

// 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);


评论


感谢您的输入,但我认为这些重载根本不是解决方案,因为无论有无参数,我们都只能传递一个集合类型以涵盖任何数量的集合。

–MasterMastic
2014年4月1日在6:54

您在某种程度上是对的,但使它酷的是没有输入参数的重载,例如int sum1 = addTwoEach();。

– Electricalalbah
2014年4月1日9:20



#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 });。在需要传递单个值而不是整个数组的情况下,对于速记很有用。它仍然在方法中以相同的方式处理,但是为以这种方式调用提供了一些便利。

#7 楼

添加params关键字本身表明您可以在调用该方法的同时传递多个参数,如果不使用它则无法实现。更具体地说:

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

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

    return sum;
}


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


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

但是,当您删除params关键字时,只有上述方法的第三种方法可以正常工作。对于第一种情况和第二种情况,您会收到错误消息。

#8 楼

还需要强调一件事。最好使用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[] {});


#9 楼

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

#10 楼

另一个例子

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

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