C#4.0新增功能02 命名实参和可选实参
C# 4 介绍命名实参和可选实参。 通过命名实参,你可以为特定形参指定实参,方法是将实参与该形参的名称关联,而不是与形参在形参列表中的位置关联。 通过可选参数,你可以为某些形参省略实参。 这两种技术都可与方法、索引器、构造函数和委托一起使用。
使用命名参数和可选参数时,将按实参出现在实参列表(而不是形参列表)中的顺序计算这些实参。
命名形参和可选形参一起使用时,你可以只为可选形参列表中的少数形参提供实参。 此功能极大地方便了对 COM 接口(例如 Microsoft Office 自动化 API)的调用。
有了命名实参,你将不再需要记住或查找形参在所调用方法的形参列表中的顺序。 每个实参的形参都可按形参名称进行指定。 例如,通过以函数定义的顺序按位置发送实参,可以采用标准方式调用打印订单详细信息(例如卖家姓名、订单号和产品名称)的函数。
PrintOrderDetails("Gift Shop", 31, "Red Mug");
如果不记得形参的顺序,但却知道其名称,则可以按任意顺序发送实参。
PrintOrderDetails(orderNum: 31, productName: "Red Mug", sellerName: "Gift Shop");
PrintOrderDetails(productName: "Red Mug", sellerName: "Gift Shop", orderNum: 31);
命名实参还可以标识每个实参所表示的含义,从而改进代码的可读性。 在下面的示例方法中,sellerName
不得为 NULL 或空白符。 由于 sellerName
和 productName
都是字符串类型,所以使用命名实参而不是按位置发送实参是有意义的,可以区分这两种类型并减少代码阅读者的困惑。
当命名实参与位置实参一起使用时,只要
- 没有后接任何位置实参或
PrintOrderDetails("Gift Shop", 31, productName: "Red Mug");
- 以 C# 7.2 开头,则它们就有效并用在正确位置 。 在以下示例中,形参
orderNum
位于正确的位置,但未显式命名。
PrintOrderDetails(sellerName: "Gift Shop", 31, productName: "Red Mug");
但是,如果其后接位置实参,则无序命名实参无效。
// 出现 CS1738 警告: 命名参数规范必须出现在指定了所有固定参数之后。
PrintOrderDetails(productName: "Red Mug", , "Gift Shop");
示例
以下代码执行本节以及某些其他节中的示例。
class NamedExample
{
static void Main(string[] args)
{
// 使用位置参数以常规方式调用方法。
PrintOrderDetails("Gift Shop", , "Red Mug"); // 可以按任意顺序为参数提供命名参数。
PrintOrderDetails(orderNum: , productName: "Red Mug", sellerName: "Gift Shop");
PrintOrderDetails(productName: "Red Mug", sellerName: "Gift Shop", orderNum: ); // 与位置参数混合的命名参数只要在正确的位置使用就有效
PrintOrderDetails("Gift Shop", , productName: "Red Mug");
PrintOrderDetails(sellerName: "Gift Shop", , productName: "Red Mug"); // C# 7.2 onwards
PrintOrderDetails("Gift Shop", orderNum: , "Red Mug"); // C# 7.2 onwards // 但是,如果使用顺序不对,则混合参数无效。
// 下列声明会引起编译错误
// PrintOrderDetails(productName: "Red Mug", 31, "Gift Shop");
// PrintOrderDetails(31, sellerName: "Gift Shop", "Red Mug");
// PrintOrderDetails(31, "Red Mug", sellerName: "Gift Shop");
} static void PrintOrderDetails(string sellerName, int orderNum, string productName)
{
if (string.IsNullOrWhiteSpace(sellerName))
{
throw new ArgumentException(message: "Seller name cannot be null or empty.", paramName: nameof(sellerName));
} Console.WriteLine($"Seller: {sellerName}, Order #: {orderNum}, Product: {productName}");
}
}
方法、构造函数、索引器或委托的定义可以指定其形参为必需还是可选。 任何调用都必须为所有必需的形参提供实参,但可以为可选的形参省略实参。
每个可选形参都有一个默认值作为其定义的一部分。 如果没有为该形参发送实参,则使用默认值。 默认值必须是以下类型的表达式之一:
常量表达式;
default(ValType) 形式的表达式,其中
ValType
是值类型。
可选参数定义于参数列表的末尾和必需参数之后。 如果调用方为一系列可选形参中的任意一个形参提供了实参,则它必须为前面的所有可选形参提供实参。 实参列表中不支持使用逗号分隔的间隔。 例如,在以下代码中,使用一个必选形参和两个可选形参定义实例方法 ExampleMethod
。
public void ExampleMethod(int required, string optionalstr = "default string",int optionalint = )
下面对 ExampleMethod
的调用会导致编译器错误,原因是为第三个形参而不是为第二个形参提供了实参。
//anExample.ExampleMethod(3, ,4);
但是,如果知道第三个形参的名称,则可以使用命名实参来完成此任务。
anExample.ExampleMethod(3, optionalint: 4);
IntelliSense 使用括号表示可选形参,如下图所示:
还可通过使用 .NET OptionalAttribute 类声明可选参数。 OptionalAttribute 形参不需要默认值。
ExampleClass
的构造函数具有一个可选形参。 实例方法 ExampleMethod
具有一个必选形参(required
)和两个可选形参(optionalstr
和 optionalint
)。 Main
中的代码演示了可用于调用构造函数和方法的不同方式。namespace OptionalNamespace
{
class OptionalExample
{
static void Main(string[] args)
{
// 实例 anexample 不发送构造函数可选参数的参数。
ExampleClass anExample = new ExampleClass();
anExample.ExampleMethod(, "One", );
anExample.ExampleMethod(, "Two");
anExample.ExampleMethod(); // 实例anoThereExample为构造函数的可选参数发送参数。
ExampleClass anotherExample = new ExampleClass("Provided name");
anotherExample.ExampleMethod(, "One", );
anotherExample.ExampleMethod(, "Two");
anotherExample.ExampleMethod(); // 以下语句产生编译器错误。 // 必须为第一个参数提供参数,并且该参数必须是整数。
//anExample.ExampleMethod("One", 1);
//anExample.ExampleMethod(); // 您不能在提供的参数中留下空白。
//anExample.ExampleMethod(3, ,4);
//anExample.ExampleMethod(3, 4); // 可以使用命名参数使前一条语句工作。
anExample.ExampleMethod(, optionalint: );
}
} class ExampleClass
{
private string _name; // 因为构造函数name的参数有一个指定给它的默认值,所以是可选的
public ExampleClass(string name = "Default name")
{
_name = name;
} // 第一个参数(必需)没有指定默认值。因此,它不是可选的。OptionalStr和OptionalInt都有分配给它们的默认值。它们是可选的。
public void ExampleMethod(int required, string optionalstr = "default string",
int optionalint = )
{
Console.WriteLine("{0}: {1}, {2}, and {3}.", _name, required, optionalstr,
optionalint);
}
} // 输出:
// Default name: 1, One, and 1.
// Default name: 2, Two, and 10.
// Default name: 3, default string, and 10.
// Provided name: 1, One, and 1.
// Provided name: 2, Two, and 10.
// Provided name: 3, default string, and 10.
// Default name: 3, default string, and 4. }
命名实参和可选实参,以及对动态对象的支持和其他增强功能大大提高了与 COM API(例如 Office Automation API)的互操作性。
例如,Microsoft Office Excel 的 Range 接口中的 AutoFormat 方法有七个可选形参。 这些形参如下图所示:
在 C# 3.0 以及早期版本中,每个形参都需要一个实参,如下例所示。
var excelApp = new Microsoft.Office.Interop.Excel.Application();
excelApp.Workbooks.Add();
excelApp.Visible = true; var myFormat = Microsoft.Office.Interop.Excel.XlRangeAutoFormat.xlRangeAutoFormatAccounting1;
excelApp.get_Range("A1", "B4").AutoFormat(myFormat, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
但是,可以通过使用 C# 4.0 中引入的命名实参和可选实参来大大简化对 AutoFormat
的调用。 如果不希望更改形参的默认值,则可以通过使用命名实参和可选实参来为可选形参省略实参。 在下面的调用中,仅为 7 个形参中的其中一个指定了值。
excelApp.Range["A1", "B4"].AutoFormat( Format: myFormat );
有关详细信息和示例,请参阅操作说明:在 Office 编程中使用命名参数和可选参数和操作说明:使用 Visual C# 功能访问 Office 互操作对象。
使用命名实参和可选实参将在以下方面对重载决策产生影响:
如果方法、索引器或构造函数的每个参数是可选的,或按名称或位置对应于调用语句中的单个自变量,且该自变量可转换为参数的类型,则方法、索引器或构造函数为执行的候选项。
如果找到多个候选项,则会将用于首选转换的重载决策规则应用于显式指定的自变量。 将忽略可选形参已省略的实参。
如果两个候选项不相上下,则会将没有可选形参的候选项作为首选项,对于这些可选形参,已在调用中为其省略了实参。 这是重载决策中的常规引用的结果,该引用用于参数较少的候选项。
C#4.0新增功能02 命名实参和可选实参的更多相关文章
- C#3.0新增功能02 匿名类型
连载目录 [已更新最新开发文章,点击查看详细] 匿名类型提供了一种方便的方法,可用来将一组只读属性封装到单个对象中,而无需首先显式定义一个类型. 类型名由编译器生成,并且不能在源代码级使用. 每 ...
- C#2.0新增功能02 泛型
连载目录 [已更新最新开发文章,点击查看详细] C# 语言和公共语言运行时 (CLR) 的 2.0 版本中添加了泛型. 泛型将类型参数的概念引入 .NET Framework,这样就可以设计具有 ...
- C#5.0新增功能02 调用方信息
连载目录 [已更新最新开发文章,点击查看详细] 通过使用调用方信息特性,可获取有关方法的调用方的信息. 可以获取源代码的文件路径.源代码中的行号和调用方的成员名称. 此信息有助于跟踪.调试和创建 ...
- C#基础拾遗系列之二:使用ILSpy探索C#7.0新增功能点
C#基础拾遗系列之二:使用ILSpy探索C#7.0新增功能点 第一部分: C#是一种通用的,类型安全的,面向对象的编程语言.有如下特点: (1)面向对象:c# 是面向对象的范例的一个丰富实现, 它 ...
- C#2.0新增功能06 协变和逆变
连载目录 [已更新最新开发文章,点击查看详细] 在 C# 中,协变和逆变能够实现数组类型.委托类型和泛型类型参数的隐式引用转换. 协变保留分配兼容性,逆变则与之相反. 以下代码演示分配兼容性.协 ...
- C#基础拾遗系列之二:C#7.0新增功能点
第一部分: C#是一种通用的,类型安全的,面向对象的编程语言.有如下特点: (1)面向对象:c# 是面向对象的范例的一个丰富实现, 它包括封装.继承和多态性.C#面向对象的行为包括: 统一的类型系统 ...
- C#7.0新增功能点
原文地址: https://www.cnblogs.com/runningsmallguo/p/8972678.html 第二部分:C#7.0新增的功能 (1)数字字面量的提升: C#7中的数字文字 ...
- C#2.0新增功能01 分布类与分部方法
连载目录 [已更新最新开发文章,点击查看详细] 分部类型 拆分一个类.一个结构.一个接口或一个方法的定义到两个或更多的文件中, 每个源文件包含类型或方法定义的一部分,编译应用程序时将把所有部分组 ...
- C#4.0新增功能01 动态绑定 (dynamic 类型)
连载目录 [已更新最新开发文章,点击查看详细] C# 4 引入了一个新类型 dynamic. 该类型是一种静态类型,但类型为 dynamic 的对象会跳过静态类型检查. 大多数情况下,该对象就像 ...
随机推荐
- QT5的post Event解析
大家都知道,QT的事件机制,查了好多网上的帖子,分析的不够到位,今天给大家分享下,我的分析,请高手指正:都知道post Event通过 QScopedPointer<QEvent> ...
- 【Qt】一劳永逸解决UAC问题(修改mkspecs\win32-msvc2012\qmake.conf)
如果你的程序跑在一个开启了UAC保护的系统中,而你的程序又没有"盾牌"的话,程序总是会受到各种阻挠的,比如读写文件,写注册表等. 有了"盾牌"的话就不会出现一些 ...
- C++开源库,欢迎补充
C++在“商业应用”方面,曾经是天下第一的开发语言,但这一桂冠已经被java抢走多年.因为当今商业应用程序类型,已经从桌面应用迅速转移成Web应 用.当Java横行天下之后,MS又突然发力,搞出C#语 ...
- SQL基础复习2
一.视图 1.创建视图 创建视图后加 WITH CHECK OPTION 2.视图查询 数据库系统的处理方法: 视图消解法(View Resolution) 步骤: 进行有效性检查-> ...
- HTML连载8-video标签
一.video标签 1.作用:播放视频 2.格式:<video src="视频地址“></video> 3.可添加的属性: (1)autoplay="au ...
- 新手怎么学JS?JavaScript基础入门
新手应该怎么学习JS?JavaScript入门 - 01 准备工作 在正式的学习JavaScript之前,我们先来学习一些小工具,帮助我们更好的学习和理解后面的内容. js代码位置 首先是如何编写Ja ...
- 【shell学习4》》】系统化整理大纲
之前看的runnoob整理,细节太多也没有系统起来,昨天公交上看了一些视频,略作总结: 标题零:学习基础//创建文件touch testVar.sh //vim编辑内容#!/bin/bashvari= ...
- 【翻译】Keras.NET简介 - 高级神经网络API in C#
Keras.NET是一个高级神经网络API,它使用C#编写,并带有Python绑定,可以在Tensorflow.CNTK或Theano上运行.其关注点是实现快速实验.因为做好研究的关键是:能在尽可能短 ...
- IO解惑:cephfs、libaio与io瓶颈
最近笔者在对kernel cephfs客户端进行fio direct随机大io读测试时发现,在numjobs不变的情况下,使用libaio作为ioengine,无论怎么调节iodepth,测试结果都变 ...
- Flink会话窗口测试
Flink会话窗口测试 一.测试结论: 1.会话窗口的间隔时间和水位线作用一样,表示输出现在时间 - 间隔时间之前所有未结算时间的数据,作用类似于水位线,但是和水位线开闭不一样. 2.会话窗口显示的数 ...