命名实参和可选实参(C# 编程指南)

Visual C# 2010 引入了命名实参和可选实参。 利用“命名实参”,您将能够为特定形参指定实参,方法是将实参与该形参的名称关联,而不是与形参在形参列表中的位置关联。 利用“可选实参”,您将能够为某些形参省略实参。 这两种技术都可与方法、索引器、构造函数和委托一起使用。

在使用命名实参和可选实参时,将按实参出现在实参列表(而不是形参列表)中的顺序计算这些实参。

命名形参和可选形参一起使用时,您将能够只为可选形参列表中的少数形参提供实参。 此功能大大方便了对 COM 接口(例如 Microsoft Office 自动化 API)的调用。

命名实参

有了命名实参,您将不再需要记住或查找形参在所调用方法的形参列表中的顺序。 可以按形参名称指定每个实参的形参。 例如,可以采用标准方式调用计算身体质量指数 (BMI) 的函数,方法是依照该函数定义的顺序按位置发送体重和身高的实参。

CalculateBMI(123, 64);

如果不记得形参的顺序,但却知道其名称,您可以按任意顺序(先发送体重或先发送身高)发送实参。

CalculateBMI(weight: 123, height: 64);

CalculateBMI(height: 64, weight: 123);

命名实参还可以标识每个实参所表示的含义,从而改进代码的可读性。

命名实参可以放在位置实参后面,如此处所示。

CalculateBMI(123, height: 64);

但是,位置实参不能放在命名实参后面。 下面的语句会导致编译器错误。

//CalculateBMI(weight: 123, 64);

示例

下面的代码实现本节中的示例。

class NamedExample
{
    static void Main(string[] args)
    {
        // The method can be called in the normal way, by using positional arguments.
        Console.WriteLine(CalculateBMI(123, 64));

        // Named arguments can be supplied for the parameters in either order.
        Console.WriteLine(CalculateBMI(weight: 123, height: 64));
        Console.WriteLine(CalculateBMI(height: 64, weight: 123));

        // Positional arguments cannot follow named arguments.
        // The following statement causes a compiler error.
        //Console.WriteLine(CalculateBMI(weight: 123, 64));

        // Named arguments can follow positional arguments.
        Console.WriteLine(CalculateBMI(123, height: 64));
    }

    static int CalculateBMI(int weight, int height)
    {
        return (weight * 703) / (height * height);
    }
}

可选参数

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

每个可选形参都具有默认值作为其定义的一部分。 如果没有为该形参发送实参,则使用默认值。 默认值必须为常量。

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

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

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

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

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

anExample.ExampleMethod(3, optionalint: 4);

IntelliSense 使用括号指示可选形参,如下图所示。

ExampleMethod 中的可选形参

ExampleMethod 方法的 IntelliSense 快速信息。

提示

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

示例

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

namespace OptionalNamespace
{
    class OptionalExample
    {
        static void Main(string[] args)
        {
            // Instance anExample does not send an argument for the constructor's
            // optional parameter.
            ExampleClass anExample = new ExampleClass();
            anExample.ExampleMethod(1, "One", 1);
            anExample.ExampleMethod(2, "Two");
            anExample.ExampleMethod(3);

            // Instance anotherExample sends an argument for the constructor's
            // optional parameter.
            ExampleClass anotherExample = new ExampleClass("Provided name");
            anotherExample.ExampleMethod(1, "One", 1);
            anotherExample.ExampleMethod(2, "Two");
            anotherExample.ExampleMethod(3);

            // The following statements produce compiler errors.

            // An argument must be supplied for the first parameter, and it
            // must be an integer.
            //anExample.ExampleMethod("One", 1);
            //anExample.ExampleMethod();

            // You cannot leave a gap in the provided arguments. 
            //anExample.ExampleMethod(3, ,4);
            //anExample.ExampleMethod(3, 4);

            // You can use a named parameter to make the previous 
            // statement work.
            anExample.ExampleMethod(3, optionalint: 4);
        }
    }

    class ExampleClass
    {
        private string _name;

        // Because the parameter for the constructor, name, has a default
        // value assigned to it, it is optional.
        public ExampleClass(string name = "Default name")
        {
            _name = name;
        }

        // The first parameter, required, has no default value assigned
        // to it. Therefore, it is not optional. Both optionalstr and 
        // optionalint have default values assigned to them. They are optional.
        public void ExampleMethod(int required, string optionalstr = "default string",
            int optionalint = 10)
        {
            Console.WriteLine("{0}: {1}, {2}, and {3}.", _name, required, optionalstr,
                optionalint);
        }
    }

    // The output from this example is the following:
    // 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 接口

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

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

AutoFormat 形参

AutoFormat 方法的 IntelliSense 快速信息。

在 C# 3.0 和早期版本中,每个形参都需要一个实参,如以下示例所示。

// In C# 3.0 and earlier versions, you need to supply an argument for
// every parameter. The following call specifies a value for the first
// parameter, and sends a placeholder value for the other six. The
// default values are used for those parameters.
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 的调用。 如果不希望更改形参的默认值,则可以通过使用命名实参和可选实参来为可选形参省略实参。 在下面的调用中,仅为七个形参中的其中一个指定了值。

// The following code shows the same call to AutoFormat in C# 4.0. Only
// the argument for which you want to provide a specific value is listed.
excelApp.Range["A1", "B4"].AutoFormat( Format: myFormat );

有关更多信息和示例,请参见如何:在 Office 编程中使用命名参数和可选参数(C# 编程指南)如何:通过使用 Visual C# 2010 功能访问 Office 互操作对象(C# 编程指南)

重载决策

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

  • 如果方法、索引器或构造函数的各个形参均为可选,或者按名称或位置与调用语句中的单个实参对应,并且该实参可转换为形参的类型,则该方法、索引器或构造函数是执行的候选项。

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

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

C# 语言规范

有关更多信息,请参见 C# 语言规范。C# 语言规范是 C# 语法和用法的权威资料。

请参见

任务

如何:在 Office 编程中使用命名参数和可选参数(C# 编程指南)

参考

使用构造函数(C# 编程指南)

使用索引器(C# 编程指南)

其他资源

使用类型 dynamic(C# 编程指南)