Menu

Parâmetros opcionais e argumentos nomeados em C#: padrões e regras

Como parâmetros opcionais e argumentos nomeados funcionam em C#: valores padrão e a regra da constante de tempo de compilação, ordem dos parâmetros, pular argumentos pelo nome, parâmetros opcionais versus sobrecargas, atributos de informação do chamador e a armadilha de versionamento dos padrões gravados em quem chama.

Esta página tem editores executáveis - edite, execute e veja a saída na hora.

Um parâmetro opcional tem um valor padrão na declaração do método, então quem chama pode omiti-lo. Um argumento nomeado passa um valor pelo nome do parâmetro em vez da posição. Juntos, eles permitem que um método atenda a muitas formas de chamada sem uma pilha de sobrecargas.

Saída:

to ana@mail.com: (no subject), retries 3
to ben@mail.com: Invoice #1042, retries 3
to cy@mail.com: (no subject) [URGENT], retries 3
to dev@mail.com: Build failed, retries 0

A terceira chamada pula subject e define urgent pelo nome; sem argumentos nomeados, ela teria que passar "(no subject)" de novo só para chegar à terceira posição. A última chamada passa todos os argumentos pelo nome, em uma ordem diferente da declaração, o que é válido.

Regras para valores padrão

Um valor padrão precisa ser algo que o compilador consiga calcular:

  • uma constante (3, "INFO", true, 1.5m, um campo const, um membro de enum)
  • null para um tipo de referência ou anulável
  • default(T), ou new T() para um tipo de valor T

Qualquer coisa avaliada em tempo de execução é rejeitada. O caso clássico é uma data:

static void Schedule(string task, DateTime at = DateTime.Now) { }
// error CS1736: Default parameter value for 'at' must be a compile-time constant

A solução padrão é um parâmetro anulável com null como padrão, resolvido no corpo:

Saída:

backup at 2026-01-01 09:00, tags: 0
report at 2026-03-15 18:30, tags: 0
deploy at 2026-01-01 09:00, tags: 2

O mesmo truque serve para coleções: um padrão new List<string>() não é uma constante, então use null como padrão e crie a lista dentro do método. Isso também evita o bug do padrão mutável compartilhado do Python, que C# descarta ao aceitar só constantes.

Regras de ordem

Os parâmetros obrigatórios vêm primeiro, os opcionais depois, e um array params (se houver) por último:

static void Log(string message, string level = "INFO", params string[] tags) { }   // OK

static void Log(string level = "INFO", string message) { }
// error CS1737: Optional parameters must appear after all required parameters

Parâmetros ref e out não podem ser opcionais.

Na chamada, os argumentos posicionais preenchem os parâmetros a partir do começo. Argumentos nomeados podem vir depois deles em qualquer ordem. Desde o C# 7.2, um argumento nomeado também pode aparecer antes de um posicional, mas só quando está na sua própria posição (SendEmail("a@b.c", subject: "Hi", true)); em versões mais antigas, os argumentos nomeados precisam vir todos no final. Deixar de fora um parâmetro obrigatório, mesmo nomeando outros, é um erro de compilação.

Argumentos nomeados para legibilidade

Argumentos nomeados são úteis mesmo quando nada é opcional. Literais true, false, null e números soltos não dizem nada no ponto da chamada:

ResizeImage(photo, 800, 600, true, false);                                   // which is which?
ResizeImage(photo, width: 800, height: 600, keepAspect: true, upscale: false);

Renomear um parâmetro passa a ser uma mudança que quebra quem usa o nome, o que vale lembrar em uma biblioteca pública.

Parâmetros opcionais versus sobrecargas

Antes do C# 4, a mesma flexibilidade exigia uma sobrecarga por combinação. Parâmetros opcionais reúnem tudo em um método:

// overloads
static void Connect(string host) => Connect(host, 443);
static void Connect(string host, int port) => Connect(host, port, 30);
static void Connect(string host, int port, int timeoutSeconds) { /* ... */ }

// one method with optional parameters
static void Connect(string host, int port = 443, int timeoutSeconds = 30) { /* ... */ }

Quando os dois existem, a resolução de sobrecarga prefere um candidato que não precise de nenhum padrão preenchido:

Saída:

Greet()
Greet(string) with Lena

Greet() corresponde aos dois métodos, e o compilador escolhe o que não tem parâmetro opcional omitido. Misturar as duas técnicas no mesmo nome costuma gerar chamadas cujo destino é difícil de prever, então escolha uma por método.

Escolha sobrecargas quando as variantes precisam de código ou tipos de parâmetro diferentes, e parâmetros opcionais quando só diferem nos valores padrão.

Os padrões ficam gravados em quem chama

Um valor padrão não é consultado em tempo de execução. O compilador o copia para cada ponto de chamada quando o código que chama é compilado. Connect("api.shop.com") compila como Connect("api.shop.com", 443, 30).

Isso tem uma consequência para bibliotecas. Suponha que a versão 1 de um pacote traga Connect(string host, int timeoutSeconds = 30) e que a versão 2 mude o padrão para 10. Uma aplicação compilada contra a versão 1 continua passando 30 depois que você coloca a DLL da versão 2, até a própria aplicação ser recompilada. Adicionar um novo parâmetro opcional a um método público existente também quebra quem já foi compilado, porque a assinatura do método mudou e eles ainda procuram a antiga (uma MissingMethodException em tempo de execução).

Dentro de uma aplicação compilada como um todo, isso nunca importa. Para APIs públicas em pacotes NuGet, sobrecargas (que mantêm os padrões dentro da biblioteca) ou um padrão null resolvido no corpo evitam o problema.

Padrões e o tipo declarado

A mesma regra de tempo de compilação faz com que, quando uma interface e uma classe declaram padrões, o padrão venha do tipo da variável pela qual você chama, não do objeto:

Saída:

printing "report" x5
printing "report" x1

O mesmo objeto, dois padrões diferentes. Mantenha os valores padrão idênticos entre uma interface e suas implementações, ou declare-os em um só lugar.

Atributos de informação do chamador

Parâmetros opcionais também são a base dos atributos de informação do chamador em System.Runtime.CompilerServices. O compilador os preenche com detalhes do ponto de chamada:

Saída:

[Main:18] starting
[SaveOrder:13] order saved

É assim que bibliotecas de log registram de onde veio uma mensagem sem que quem chama precise digitar isso, e é assim que implementações de INotifyPropertyChanged obtêm o nome da propriedade. [CallerFilePath] adiciona o caminho do arquivo fonte da mesma forma.

Perguntas frequentes

Como tornar um parâmetro opcional em C#?

Dê a ele um valor padrão na declaração: static void Log(string message, string level = "INFO"). Quem chama pode então escrever Log("started") ou Log("failed", "ERROR"). Parâmetros opcionais precisam vir depois de todos os obrigatórios, e o padrão precisa ser uma constante de tempo de compilação.

O que são argumentos nomeados em C#?

Argumentos passados com o nome do parâmetro: SendEmail(to: "ana@mail.com", urgent: true). Eles permitem pular parâmetros opcionais do meio, passar argumentos em qualquer ordem e deixar legíveis de relance chamadas com true/false literais ou números.

Por que não posso usar DateTime.Now como valor padrão de um parâmetro?

Os padrões precisam ser constantes de tempo de compilação, e DateTime.Now é calculado em tempo de execução, então o compilador reporta CS1736, Default parameter value for 'at' must be a compile-time constant. Use um parâmetro anulável: DateTime? at = null, e depois DateTime time = at ?? DateTime.Now; no corpo.

Devo usar parâmetros opcionais ou sobrecarga de métodos em C#?

Parâmetros opcionais são mais simples quando as variantes só diferem nos valores padrão. Sobrecargas são melhores quando as variantes precisam de lógica ou tipos diferentes, e em bibliotecas públicas, porque um valor padrão é compilado em cada chamada e mudá-lo depois não chega ao código já compilado.

O que significa "Optional parameters must appear after all required parameters"?

Erro CS1737: um parâmetro com valor padrão é seguido por um sem. Coloque os parâmetros obrigatórios primeiro: (string to, bool urgent = false), não (bool urgent = false, string to). Depois de um parâmetro opcional, só podem vir outros opcionais ou um array params.

Coddy programming languages illustration

Aprenda a programar com o Coddy

COMEÇAR