C#4.0新特性(2):Named and Optional Arguments 命名参数和可选参数
为什么需要开放命名参数和可选参数呢?
•这是出于动态语言运行时兼容性的要求。动态语言中存在动态绑定的参数列表,有时候并不是所有的参数值都需要指定(有些语言可能没有重载决策);
•另外,在一些 COM 互操作时,往往 COM Invoke 的方法参数列表非常的长(例如 ExcelApplication.Save,可能需要 12 个参数),但 COM 暴露的参数的实际值往往为 null,只有很少一部分参数需要指定植,如 ExcelApplication.Save(),可能不需要指定任何参数值,或者仅仅一个值,例如 fileType。为了精简书写的代码,就有着这个特性。
命名参数和可选参数是两个截然不同的功能,但通常一起使用。在进行成员调用时,可以忽略可选参数;而命名参数的方式可以通过名称来提供一个参数,而无需依赖它在参数列表中出现的位置。
有些API——尤其是COM接口——如Office自动化API——确实本身就是通过命名参数和可选参数编写的。之前在C#中调用这些API非常痛苦,尤其有的时候需要多达30几个参数都必须显式传递,而其中大多数都具有合理的默认值,是可以忽略的。
即便是编写.NET中的API,你也会发现很多时候你在易做图为不同的参数组合方式编写一个方法的大量重载形式,以便给调用者提供最高的可用性。在这种情况下,可选参数就会成为一种非常有用的替代方式。
Named parameters 命名参数
有了命名实参,您将不再需要记住或查找形参在所调用方法的形参列表中的顺序。 可以按形参名称指定每个实参的形参。 例如,可以采用标准方式调用计算身体质量指数 (BMI) 的函数,方法是依照该函数定义的顺序按位置发送体重和身高的实参。
CalculateBMI(123, 64);
如果不记得形参的顺序,但却知道其名称,您可以按任意顺序(先发送体重或先发送身高)发送实参。
CalculateBMI(weight: 123, height: 64);
CalculateBMI(height: 64, weight: 123);
命名实参还可以标识每个实参所表示的含义,从而改进代码的可读性。
命名实参可以放在位置实参后面,如此处所示。
CalculateBMI(123, height: 64);
但是,位置实参不能放在命名实参后面。 下面的语句会导致编译器错误。
//CalculateBMI(weight: 123, 64);
01 class NamedExample
02 {
03 static void Main(string[] args)
04 {
05 // The method can be called in the normal way, by using positional arguments.
06 Console.WriteLine(CalculateBMI(123, 64));
07
08 // Named arguments can be supplied for the parameters in either order.
09 Console.WriteLine(CalculateBMI(weight: 123, height: 64));
10 Console.WriteLine(CalculateBMI(height: 64, weight: 123));
11
12 // Positional arguments cannot follow named arguments.
13 // The following statement causes a compiler error.
14 //Console.WriteLine(CalculateBMI(weight: 123, 64));
15
16 // Named arguments can follow positional arguments.
17 Console.WriteLine(CalculateBMI(123, height: 64));
18 }
19
20 static int CalculateBMI(int weight, int height)
21 {
22 return (weight * 703) / (height * height);
23 }
24 }
Named Parameters 的实质就是:
命名参数,无非是变相告知参数键值而已,最终编译结果还是按照原有的规则和顺序生成方法调用。这只不过是中语法糖而已。
Optional parameters 可选参数
为一个参数提供默认值就可以将其声明为可选的——
1 public void M(int x, int y = 5, int z = 7);
这里的y和z就是可选参数,在调用时可以忽略——
1 M(1, 2, 3); // ordinary call of M
2 M(1, 2); // omitting z – equivalent to M(1, 2, 7)
3 M(1); // omitting both y and z – equivalent to M(1, 5, 7)
方法、构造函数、索引器或委托的定义可以指定其形参为必需还是可选。 任何调用都必须为所有必需的形参提供实参,但可以为可选的形参省略实参。
每个可选形参都具有默认值作为其定义的一部分。 如果没有为该形参发送实参,则使用默认值。 默认值必须是一个表达式的以下类型之一:
•常数表达式;
•窗体 new ValType()的表达式, ValType 是值类型,例如 枚举 或 结构;
•窗体 默认 (ValType)的表达式, ValType 是值类型。
可选形参在形参列表的末尾定义,位于任何必需的形参之后。 如果调用方为一系列可选形参中的任意一个形参提供了实参,则它必须为前面的所有可选形参提供实参。 实参列表中不支持使用逗号分隔的间隔。 例如,在以下代码中,使用一个必选形参和两个可选形参定义实例方法 ExampleMethod。
1 public void ExampleMethod(int required, string optionalstr = "default string", int optionalint = 10)
下面对 ExampleMethod 的调用导致编译器错误,原因是为第三个形参而不是为第二个形参提供了实参。
1 //anExample.ExampleMethod(3, ,4);
但是,如果您知道第三个形参的名称,则可以使用命名实参来完成任务。
1 anExample.ExampleMethod(3, optionalint: 4);
IntelliSense 使用括号指示可选形参,如下图所示。
还可以通过使用 .NET OptionalAttribute 类来声明可选形参。 OptionalAttribute 形参不需要默认值。
在下面的示例中,ExampleClass 的构造函数具有一个形参,该形参是可选的。 实例方法 ExampleMethod具有一个必需的形参:required,以及两个可选形参:optionalstr 和 optionalint。 Main 中的代码演示了可用于调用构造函数和方法的不同方式。
01 namespace OptionalNamespace
02 {
03 class OptionalExample
04 {
05 static void Main(string[] args)
06 {
07 // Instance anExample does not send an argument for the constructor's
08 // optional parameter.
09 ExampleClass anExample = new ExampleClass();
10 anExample.ExampleMethod(1, "One", 1);
11 anExample.ExampleMethod(2, "Two");
12 anExample.ExampleMethod(3);
13
14 // Instance anotherExample sends an argument for the constructor's
15 // optional parameter.
16 ExampleClass anotherExample = new ExampleClass("Provided name");
17 anotherExample.ExampleMethod(1, "One", 1);
18 anotherExample.ExampleMethod(2, "Two");
19 anotherExample.ExampleMethod(3);
20
21 // The following statements produce compiler errors.
22
23 // An argument must be supplied for the first parameter, and it
24 // must be an integer.
25 //a
补充:软件开发 , C# ,