Именованные и необязательные аргументы (Руководство по программированию на C#)

C# 4 вводит именованные и необязательные аргументы. Именованные аргументы позволяют указать аргумент для параметра, связав этот аргумент с именем параметра, а не с его позицией в списке параметров. Необязательные аргументы позволяют опускать аргументы для некоторых параметров. Оба варианта можно использовать с методами, индексаторами, конструкторами и делегатами.

При использовании именованных и необязательных аргументов аргументы оцениваются в том порядке, в котором они отображаются в списке аргументов, а не в списке параметров.

Именованные и дополнительные параметры позволяют указать аргументы для выбранных параметров. Эта возможность значительно упрощает вызов интерфейсов COM, таких как API автоматизации Microsoft Office.

Именованные аргументы

Именованные аргументы освобождают вас от необходимости сопоставлять порядок параметров в списках параметров вызванных методов. Параметр для каждого аргумента можно указать, используя имя параметра. Например, функция, которая выводит сведения о заказе (имя продавца, номер заказа и наименование товара и т. д.), может вызываться путем передачи аргументов по позиции в порядке, определяемом функцией.

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");
    

Позиционные аргументы после внеочередных именованных аргументов недопустимы.

// 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");    // C# 7.2 onwards
        PrintOrderDetails("Gift Shop", orderNum: 31, "Red Mug");                   // C# 7.2 onwards

        // 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}");
    }
}

Необязательные аргументы

Определение метода, конструктора, индексатора или делегата может указывать, являются его параметры обязательными или нет. Любой вызов должен содержать аргументы для всех обязательных параметров; аргументы для необязательных параметров можно опустить.

Определение каждого необязательного параметра содержит его значение по умолчанию. Если аргумент для параметра не передается, используется значение по умолчанию. Значением по умолчанию должен быть один из следующих типов выражений:

  • константное выражение;
  • выражение в форме 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 необязательные параметры заключаются в квадратные скобки, как показано на следующем рисунке:

Снимок экрана, показывающий краткие сведения IntelliSense для метода ExampleMethod.

Примечание

Необязательные параметры также можно объявлять с помощью класса .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(
                $"{_name}: {required}, {optionalstr}, and {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

Именованные и необязательные аргументы, а также поддержка динамических объектов значительно улучшают взаимодействие с API COM, такими как API автоматизации Office.

Например, метод AutoFormatв интерфейсе Microsoft Office Excel Range имеет семь параметров и все они необязательные. Эти параметры показаны на следующем рисунке:

Снимок экрана, показывающий краткие сведения IntelliSense для метода AutoFormat.

В 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);

При этом вызов AutoFormat можно значительно упростить, используя именованные и необязательные аргументы, представленные в C# 4.0. Именованные и необязательные аргументы позволяют опускать аргументы для необязательных параметров, если значение параметра по умолчанию менять не нужно. В следующем вызове значение задается только для одного из семи параметров.

// 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 и получению доступа к объектам взаимодействия Office с помощью функций языка C#.

Overload Resolution

Использование именованных и необязательных аргументов влияет на разрешение перегрузки описанным ниже образом.

  • Метод, индексатор или конструктор является кандидатом на выполнение, если каждый из его параметров необязателен либо по имени или позиции соответствует одному и тому же аргументу в операторе вызова, и этот аргумент можно преобразовать в тип параметра.
  • Если найдено более одного кандидата, правила разрешения перегрузки для предпочтительных преобразований применяются к аргументам, указанным явно. Опущенные аргументы для необязательных параметров игнорируются.
  • Если два кандидата определяются как равно подходящие, предпочтение отдается кандидату без необязательных параметров, аргументы которых в вызове были опущены. При разрешении перегрузки обычно используются кандидаты с меньшим числом параметров.

Спецификация языка C#

Дополнительные сведения см. в спецификации языка C#. Спецификация языка является предписывающим источником информации о синтаксисе и использовании языка C#.