Argumentos nomeados e opcionais (Guia de Programação C#)

C# 4 introduz argumentos nomeados e opcionais. Os argumentos nomeados permitem especificar um argumento para um parâmetro, combinando o argumento com o seu nome e não com a sua posição na lista de parâmetros. Os argumentos opcionais permitem-lhe omitir argumentos para alguns parâmetros. Ambas as técnicas podem ser usadas com métodos, indexadores, construtores e delegados.

Quando utiliza argumentos nomeados e opcionais, os argumentos são avaliados na ordem em que aparecem na lista de argumentos, não na lista de parâmetros.

Os parâmetros nomeados e opcionais permitem-lhe fornecer argumentos para parâmetros selecionados. Esta capacidade facilita muito as chamadas para interfaces COM, como as APIs de Automação do Microsoft Office.

Argumentos com nome

Os argumentos nomeados libertam-no de combinar a ordem dos argumentos com a ordem dos parâmetros nas listas de parâmetros dos métodos chamados. O argumento de cada parâmetro pode ser especificado pelo nome do parâmetro. Por exemplo, uma função que imprime detalhes de encomenda (como, nome do vendedor, nome do produto número & de encomenda) pode ser chamada enviando argumentos por posição, na ordem definida pela função.

PrintOrderDetails("Gift Shop", 31, "Red Mug");

Se não se lembrar da ordem dos parâmetros mas souber os seus nomes, pode enviar os argumentos por qualquer ordem.

PrintOrderDetails(orderNum: 31, productName: "Red Mug", sellerName: "Gift Shop");
PrintOrderDetails(productName: "Red Mug", sellerName: "Gift Shop", orderNum: 31);

Os argumentos nomeados também melhoram a legibilidade do seu código identificando o que cada argumento representa. No método de exemplo abaixo, o sellerName espaço não pode ser nulo ou branco. Como ambos sellerName e productName são tipos de cordas, em vez de enviar argumentos por posição, faz sentido usar argumentos nomeados para desambiguar os dois e reduzir a confusão para quem lê o código.

Os argumentos nomeados, quando usados com argumentos posicionais, são válidos desde que

  • não são seguidos por quaisquer argumentos posicionais, ou

    PrintOrderDetails("Gift Shop", 31, productName: "Red Mug");
    
  • começando com C# 7.2, são utilizados na posição correta. No exemplo abaixo, o parâmetro orderNum está na posição correta, mas não está explicitamente nomeado.

    PrintOrderDetails(sellerName: "Gift Shop", 31, productName: "Red Mug");
    

Os argumentos posicionais que seguem quaisquer argumentos fora de ordem são inválidos.

// This generates CS1738: Named argument specifications must appear after all fixed arguments have been specified.
PrintOrderDetails(productName: "Red Mug", 31, "Gift Shop");

Exemplo

O código que se segue implementa os exemplos desta secção juntamente com alguns outros.

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

Argumentos opcionais

A definição de método, construtor, indexador ou delegado pode especificar os seus parâmetros são necessários ou opcionais. Qualquer chamada deve apresentar argumentos para todos os parâmetros necessários, mas pode omitir argumentos para parâmetros opcionais.

Cada parâmetro opcional tem um valor predefinido como parte da sua definição. Se não for enviado qualquer argumento para esse parâmetro, o valor predefinido é utilizado. Um valor predefinido deve ser um dos seguintes tipos de expressões:

  • uma expressão constante;
  • Uma expressão da forma new ValType(), onde ValType se trata de um tipo de valor, como um enum ou uma estrutura;
  • uma expressão do formulário padrão (ValType), onde ValType é um tipo de valor.

Os parâmetros opcionais são definidos no final da lista de parâmetros, após os parâmetros necessários. Se o chamador apresentar um argumento para qualquer uma de uma sucessão de parâmetros opcionais, deve apresentar argumentos para todos os parâmetros opcionais anteriores. As lacunas separadas pela vírgula na lista de argumentos não são apoiadas. Por exemplo, no seguinte código, o método ExampleMethod de instância é definido com um necessário e dois parâmetros opcionais.

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

A chamada ExampleMethod seguinte causa um erro do compilador, porque é apresentado um argumento para o terceiro parâmetro, mas não para o segundo.

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

No entanto, se souber o nome do terceiro parâmetro, pode usar um argumento nomeado para realizar a tarefa.

anExample.ExampleMethod(3, optionalint: 4);

O IntelliSense utiliza suportes para indicar parâmetros opcionais, como mostra a seguinte ilustração:

Screenshot mostrando informações rápidas intelliSense para o método ExemploMethod.

Nota

Também pode declarar parâmetros opcionais utilizando a classe .NET OptionalAttribute . OptionalAttribute parâmetros não requerem um valor padrão.

Exemplo

No exemplo seguinte, o construtor ExampleClass tem um parâmetro, que é opcional. O método ExampleMethod de instância tem um parâmetro necessário, requirede dois parâmetros opcionais, optionalstr e optionalint. O código mostra Main as diferentes formas pelas quais o construtor e o método podem ser invocados.

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.
}

O código anterior mostra uma série de exemplos em que os parâmetros opcionais não são aplicados corretamente. A primeira ilustra que deve ser apresentado um argumento para o primeiro parâmetro, que é necessário.

Interfaces COM

Argumentos nomeados e opcionais, juntamente com o suporte a objetos dinâmicos, melhoram consideravelmente a interoperabilidade com as APIs da COM, como apis de automação de escritório.

Por exemplo, o AutoFormat método na interface do Microsoft Office Excel Range tem sete parâmetros, todos os quais são opcionais. Estes parâmetros são mostrados na seguinte ilustração:

Screenshot mostrando informações rápidas intelliSense para o método AutoFormat.

Nas versões C# 3.0 e anteriores, é necessário um argumento para cada parâmetro, como mostra o exemplo seguinte.

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

No entanto, pode simplificar muito a chamada AutoFormat utilizando argumentos nomeados e opcionais, introduzidos em C# 4.0. Argumentos nomeados e opcionais permitem-lhe omitir o argumento de um parâmetro opcional se não quiser alterar o valor padrão do parâmetro. Na chamada seguinte, um valor é especificado para apenas um dos sete parâmetros.

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

Para obter mais informações e exemplos, consulte Como utilizar argumentos nomeados e opcionais na programação do Office e como aceder a objetos de interop do Office utilizando funcionalidades C#.

Resolução de sobrecarga

A utilização de argumentos nomeados e opcionais afeta a resolução de sobrecargas das seguintes formas:

  • Um método, indexador ou construtor é um candidato à execução se cada um dos seus parâmetros for opcional ou corresponder, por nome ou por posição, a um único argumento na declaração de chamada, e esse argumento puder ser convertido para o tipo de parâmetro.
  • Se mais de um candidato for encontrado, as regras de resolução de sobrecarga para conversões preferenciais são aplicadas aos argumentos explicitamente especificados. Os argumentos omitidos para parâmetros opcionais são ignorados.
  • Se dois candidatos forem considerados igualmente bons, a preferência vai para um candidato que não tem parâmetros opcionais para os quais os argumentos foram omitidos na chamada. A resolução de sobrecarga geralmente prefere candidatos que tenham menos parâmetros.

Especificação linguística C#

Para mais informações, consulte a Especificação de Idioma C. A especificação linguística é a fonte definitiva para a sintaxe e utilização C#.