通过命名实参,你可以为形参指定实参,方法是将实参与该形参的名称匹配,而不是与形参在形参列表中的位置匹配。 通过可选参数,你可以为某些形参省略实参。 这两种技术都可与方法、索引器、构造函数和委托一起使用。
使用命名参数和可选参数时,将按实参出现在实参列表(而不是形参列表)中的顺序计算这些实参。
通过命名形参和可选形参,你可以为所选形参提供实参。 此功能极大地方便了对 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 都是字符串类型,所以使用命名实参而不是按位置发送实参是有意义的,可以区分这两种类型并减少代码阅读者的困惑。
当命名实参与位置实参一起使用时,只要
1. 没有后接任何位置实参或
PrintOrderDetails("Gift Shop", 31, productName: "Red Mug");
2. 它们用在正确位置。 在以下示例中,形参 orderNum 位于正确的位置,但未显式命名。
PrintOrderDetails(sellerName: "Gift Shop", 31, productName: "Red Mug");
遵循任何无序命名参数的位置参数无效。
// This generates CS1738: Named argument specifications must appear after all fixed arguments have been specified.
PrintOrderDetails(productName: "Red Mug", 31, "Gift Shop");
示例
以下代码执行本节以及某些其他节中的示例。
class NamedExample
{
static void Main(string[] args)
{
// The method can be called in the normal way, by using positional arguments.
PrintOrderDetails("Gift Shop", 31, "Red Mug");
// Named arguments can be supplied for the parameters in any order.
PrintOrderDetails(orderNum: 31, productName: "Red Mug", sellerName: "Gift Shop");
PrintOrderDetails(productName: "Red Mug", sellerName: "Gift Shop", orderNum: 31);
// Named arguments mixed with positional arguments are valid
// as long as they are used in their correct position.
PrintOrderDetails("Gift Shop", 31, productName: "Red Mug");
PrintOrderDetails(sellerName: "Gift Shop", 31, productName: "Red Mug");
PrintOrderDetails("Gift Shop", orderNum: 31, "Red Mug");
// However, mixed arguments are invalid if used out-of-order.
// The following statements will cause a compiler error.
// 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}");
}
}
COM 接口
命名实参和可选实参,以及对动态对象的支持大大提高了与 COM API(例如 Office Automation API)的互操作性。
例如,Microsoft Office Excel 的 Range 接口中的 AutoFormat 方法有七个可选形参。 这些形参如下图所示:
但是,可以通过使用命名实参和可选实参来大大简化对 AutoFormat 的调用。 如果不希望更改形参的默认值,则可以通过使用命名实参和可选实参来省略可选形参的实参。 在下面的调用中,仅为 7 个形参中的其中一个指定了值。
var excelApp = new Microsoft.Office.Interop.Excel.Application();
excelApp.Workbooks.Add();
excelApp.Visible = true;
var myFormat =
Microsoft.Office.Interop.Excel.XlRangeAutoFormat.xlRangeAutoFormatAccounting1;
excelApp.Range["A1", "B4"].AutoFormat( Format: myFormat );
重载决策
使用命名实参和可选实参将在以下方面对重载决策产生影响:
如果方法、索引器或构造函数的每个参数是可选的,或按名称或位置对应于调用语句中的单个自变量,且该自变量可转换为参数的类型,则方法、索引器或构造函数为执行的候选项。
如果找到多个候选项,则会将用于首选转换的重载决策规则应用于显式指定的自变量。 将忽略可选形参已省略的实参。
如果两个候选项不相上下,则会将没有可选形参的候选项作为首选项,对于这些可选形参,已在调用中为其省略了实参。 重载决策通常首选具有较少形参的候选项。