C#4.0新增功能02 命名实参和可选实参

Wesley13
• 阅读 294

系列目录    【已更新最新开发文章,点击查看详细】

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", 31, "Gift Shop");

示例

以下代码执行本节以及某些其他节中的示例。

class NamedExample
{
    static void Main(string[] args)
    {
        // 使用位置参数以常规方式调用方法。
        PrintOrderDetails("Gift Shop", 31, "Red Mug");

        // 可以按任意顺序为参数提供命名参数。
        PrintOrderDetails(orderNum: 31, productName: "Red Mug", sellerName: "Gift Shop");
        PrintOrderDetails(productName: "Red Mug", sellerName: "Gift Shop", orderNum: 31);

        // 与位置参数混合的命名参数只要在正确的位置使用就有效
        PrintOrderDetails("Gift Shop", 31, productName: "Red Mug");
        PrintOrderDetails(sellerName: "Gift Shop", 31, productName: "Red Mug");    // C# 7.2 onwards
        PrintOrderDetails("Gift Shop", orderNum: 31, "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}");
    }
}

可选实参

方法、构造函数、索引器或委托的定义可以指定其形参为必需还是可选。 任何调用都必须为所有必需的形参提供实参,但可以为可选的形参省略实参。

每个可选形参都有一个默认值作为其定义的一部分。 如果没有为该形参发送实参,则使用默认值。 默认值必须是以下类型的表达式之一:

  • 常量表达式;

  • new ValType() 形式的表达式,其中 ValType 是值类型,例如 enum 或 struct

  • default(ValType) 形式的表达式,其中 ValType 是值类型。

可选参数定义于参数列表的末尾和必需参数之后。 如果调用方为一系列可选形参中的任意一个形参提供了实参,则它必须为前面的所有可选形参提供实参。 实参列表中不支持使用逗号分隔的间隔。 例如,在以下代码中,使用一个必选形参和两个可选形参定义实例方法 ExampleMethod

public void ExampleMethod(int required, string optionalstr = "default string",int optionalint = 10)

下面对 ExampleMethod 的调用会导致编译器错误,原因是为第三个形参而不是为第二个形参提供了实参。

//anExample.ExampleMethod(3, ,4);

但是,如果知道第三个形参的名称,则可以使用命名实参来完成此任务。

anExample.ExampleMethod(3, optionalint: 4);

IntelliSense 使用括号表示可选形参,如下图所示:

C#4.0新增功能02 命名实参和可选实参

还可通过使用 .NET OptionalAttribute 类声明可选参数。 OptionalAttribute 形参不需要默认值。

在以下示例中,ExampleClass 的构造函数具有一个可选形参。 实例方法 ExampleMethod 具有一个必选形参(required)和两个可选形参(optionalstr 和 optionalint)。 Main 中的代码演示了可用于调用构造函数和方法的不同方式。

 1 namespace OptionalNamespace
 2 {
 3     class OptionalExample
 4     {
 5         static void Main(string[] args)
 6         {
 7             // 实例 anexample 不发送构造函数可选参数的参数。
 8             ExampleClass anExample = new ExampleClass();
 9             anExample.ExampleMethod(1, "One", 1);
10             anExample.ExampleMethod(2, "Two");
11             anExample.ExampleMethod(3);
12 
13             // 实例anoThereExample为构造函数的可选参数发送参数。
14             ExampleClass anotherExample = new ExampleClass("Provided name");
15             anotherExample.ExampleMethod(1, "One", 1);
16             anotherExample.ExampleMethod(2, "Two");
17             anotherExample.ExampleMethod(3);
18 
19             // 以下语句产生编译器错误。
20 
21             // 必须为第一个参数提供参数,并且该参数必须是整数。
22             //anExample.ExampleMethod("One", 1);
23             //anExample.ExampleMethod();
24 
25             // 您不能在提供的参数中留下空白。
26             //anExample.ExampleMethod(3, ,4);
27             //anExample.ExampleMethod(3, 4);
28 
29             // 可以使用命名参数使前一条语句工作。
30             anExample.ExampleMethod(3, optionalint: 4);
31         }
32     }
33 
34     class ExampleClass
35     {
36         private string _name;
37 
38         // 因为构造函数name的参数有一个指定给它的默认值,所以是可选的
39         public ExampleClass(string name = "Default name")
40         {
41             _name = name;
42         }
43 
44         // 第一个参数(必需)没有指定默认值。因此,它不是可选的。OptionalStr和OptionalInt都有分配给它们的默认值。它们是可选的。
45         public void ExampleMethod(int required, string optionalstr = "default string",
46             int optionalint = 10)
47         {
48             Console.WriteLine("{0}: {1}, {2}, and {3}.", _name, required, optionalstr,
49                 optionalint);
50         }
51     }
52 
53     // 输出:
54     // Default name: 1, One, and 1.
55     // Default name: 2, Two, and 10.
56     // Default name: 3, default string, and 10.
57     // Provided name: 1, One, and 1.
58     // Provided name: 2, Two, and 10.
59     // Provided name: 3, default string, and 10.
60     // Default name: 3, default string, and 4.
61 
62 }

COM 接口

命名实参和可选实参,以及对动态对象的支持和其他增强功能大大提高了与 COM API(例如 Office Automation API)的互操作性。

例如,Microsoft Office Excel 的 Range 接口中的 AutoFormat 方法有七个可选形参。 这些形参如下图所示:

C#4.0新增功能02 命名实参和可选实参

在 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 互操作对象

重载决策

使用命名实参和可选实参将在以下方面对重载决策产生影响:

  • 如果方法、索引器或构造函数的每个参数是可选的,或按名称或位置对应于调用语句中的单个自变量,且该自变量可转换为参数的类型,则方法、索引器或构造函数为执行的候选项。

  • 如果找到多个候选项,则会将用于首选转换的重载决策规则应用于显式指定的自变量。 将忽略可选形参已省略的实参。

  • 如果两个候选项不相上下,则会将没有可选形参的候选项作为首选项,对于这些可选形参,已在调用中为其省略了实参。 这是重载决策中的常规引用的结果,该引用用于参数较少的候选项。

系列目录    【已更新最新开发文章,点击查看详细】

点赞
收藏
评论区
推荐文章
浅梦一笑 浅梦一笑
2个月前
初学 Python 需要安装哪些软件?超级实用,小白必看!
编程这个东西是真的奇妙。对于懂得的人来说,会觉得这个工具是多么的好用、有趣,而对于小白来说,就如同大山一样。其实这个都可以理解,大家都是这样过来的。那么接下来就说一下python相关的东西吧,并说一下我对编程的理解。本人也是小白一名,如有不对的地方,还请各位大神指出01名词解释:如果在编程方面接触的比较少,那么对于软件这一块,有几个名词一定要了解,比如开发环
blmius blmius
1年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录 问题 用navicat导入数据时,报错: 原因这是因为当前的MySQL不支持datetime为0的情况。 解决修改sql\mode: sql\mode:SQL Mode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。 全局s
Stella981 Stella981
1年前
Opencv中Mat矩阵相乘——点乘、dot、mul运算详解
Opencv中Mat矩阵相乘——点乘、dot、mul运算详解 ============================== 2016年09月02日 00:00:36 [\-牧野-](https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fme.csdn.net%2Fdcrmg) 阅读数:59593
Stella981 Stella981
1年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置 1、virsh edit centos7 找到“memory”和“vcpu”标签,将 <name>centos7</name> <uuid>2220a6d1-a36a-4fbb-8523-e078b3dfe795</uuid>
Wesley13 Wesley13
1年前
VS2008插件CodeRush Xpress for C#
VS2008插件CodeRush Xpress for C# 2009-03-25 00:28 前段时间 [DevExpress](https://www.oschina.net/action/GoToLink?url=http%3A%2F%2Fwww.devexpress.com%2F) 和微软共同发布了 [CodeRush Xpress for
Wesley13 Wesley13
1年前
MySQL查询按照指定规则排序
1.按照指定(单个)字段排序 select * from table_name order id desc; 2.按照指定(多个)字段排序 select * from table_name order id desc,status desc; 3.按照指定字段和规则排序 selec
Stella981 Stella981
1年前
Angular material mat
Icon Icon Name mat-icon code _add\_comment_ add comment icon <mat-icon> add\_comment</mat-icon> _attach\_file_ attach file icon <mat-icon> attach\_file</mat-icon> _attach\
Wesley13 Wesley13
1年前
PHP中的NOW()函数
是否有一个PHP函数以与MySQL函数`NOW()`相同的格式返回日期和时间? 我知道如何使用`date()`做到这一点,但是我问是否有一个仅用于此的函数。 例如,返回: 2009-12-01 00:00:00 * * * ### #1楼 使用此功能: function getDatetimeNow() {
Wesley13 Wesley13
1年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
#### 背景描述 # Time: 2019-01-24T00:08:14.705724+08:00 # User@Host: **[**] @ [**] Id: ** # Schema: sentrymeta Last_errno: 0 Killed: 0 # Query_time: 0.315758 Lock_
helloworld_34035044 helloworld_34035044
4个月前
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。 uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid() 或 uuid(sep)参数说明:sep 布尔值,生成的uuid中是否包含分隔符'',缺省为