Welcome to GASP Sign in | Join | Help

Paulo Morgado

Tudo sobre Arquitectura de Software

Localização dos Visitantes

  • Localização dos Visitantes

Livros

  • LINQ com C#

Eventos

Renûncia

As opiniões e pontos de vista expressos neste sítio são minhas e podem não reflectir as da Microsoft, do meu empregador, ou de qualquer comunidade a que pertença. Qualquer código ou opinião é oferecido sem qualquer garantia. Os produtos ou serviços mencionados são comprados por mim, disponibilizados pelo meu empregador ou pelo fabricante/vendedor o que não influencia em nada a minha opinião.

C# 4.0: Argumentos Com Nome E Opcionais

Como parte do esforço de co-evolução do C# e do Visual Basic, o C# 4.0 introduz Argumentos com Nome e Opcionais.

Primeiro clarifiquemos o que são argumentos e o que são parâmetros:

  • Os parâmetros da definição de um método são as variáveis de entrada do método.
  • Os argumentos da declaração da chamada a um método são os valores providenciados para os .

De facto, a Especificação da Linguagem C# afirma em §7.5 que:

A lista de argumentos (§7.5.1) da invocação de um membro função providencia os valores que vão ser efectivamente usados como variáveis ou referências a variáveis como parâmetros do membro função.

Dadas as definições acima, podemos afirmar que:

  • Os parâmetros sempre tiveram, e continua a ter, nome.
  • Os parâmetros nunca foram, e continuam a não ser, opcionais.

Argumentos Com Nome

Até agora, a forma como o compilador de C# fazia corresponder os argumentos da declaração de uma chamada a um método era pela sua posição. O primeiro argumento providencia o valor para o primeiro parâmetro o segundo argumento providencia o valor para o segundo parâmetro, e por aí fora, independentemente do número de parâmetros. Se algum parâmetro não tivesse um argumento correspondente para lhe providenciar o valor, isso faria o compilador emitir um erro de compilação.

Para esta chamada:

Greeting("Mr.", "Morgado", 42);

este métdo:

public void Greeting(string title, string name, int age)

receberá como parâmetros:

  • title: “Mr.”
  • name: “Morgado”
  • age: 42

O que esta nova funcionalidade permite é usar os nomes dos parâmteros para identificar os argumentos correspondentes na forma: name:value

Nem todos os argumentos da lista precisam de ser identificados com o nome do correspondente parâmetros. No entanto, todos os argumentos com nome devem ser posicionados no fim da lista de argumentos. A correspondência entre os argumentos (e a avaliação do seu valor) e os parâmetros será feita primeiro pelo nome dos argumentos com nome (apesar destes se encontrarem no fim da lista) e em seguida pela posição, para os parâmteros para os quais ainda não foi atribuído valor.

Isto quer dizer que, para esta definição de método:

public void Method(int first, int second, int third)

esta declaração de chamada:

int i = 0;
Method(i, third: i++, second: ++i);

terá o seguinte código gerado pelo compilador:

int i = 0;
int CS$0$0000 = i++;
int CS$0$0001 = ++i;
Method(i, CS$0$0001, CS$0$0000);

o que dará aos parâmetros do método os seguintes valores:

  • first: 2
  • second: 2
  • third: 0

Note-se que os nomes das variáveis geradas pelo compilador não são identificadores C# válidos. No entanto, são identificadores .NET válidos evitando, assim, colisões de nomes entre o código gerado pelo compilador e o código escrito pelo programador.

Para além de permitir reordenar a lista de argumentos, esta funcionalidade apresenta-se muito útil para documentar código que quando, por exemplo, a lista de argumentos é muito extensa ou é pouco claro o significado dos argumentos na declaração da chamada ao método.

Argumentos Opcionais

Agora os parâmetros pode ter valores por omissão:

public void Method(int first, int second = 2, int third = 3)

Os parâmetros com valores por omissão têm de ser os últimos da lista de parâmetros e esse valor é usado se o argumento correspondente estiver em falta na lista de argumentos da declaração da chamado ao método.

Para esta declaração de chamada:

int i = 0;
Method(i, third: ++i);

terá o seguinte código gerado pelo compilador:

int i = 0;
int CS$0$0000 = ++i;
Method(i, 2, CS$0$0000);

o que dará aos parâmetros do método os seguintes valores:

  • first: 1
  • second: 2
  • third: 1

Porque, quando os parâmetros do método têm valores por omissão, os arumentos podem ser omitidos na declaração da chamada ao método, pode parecer-se com sobreposição de métodos, mas não é.

Embora métodos como este:

public StreamReader OpenTextFile(
    string path,
    Encoding encoding = null,
    bool detectEncoding = true,
    int bufferSize = 1024)

permitam que as sua chamadas sejam escritas assim:

OpenTextFile("foo.txt", Encoding.UTF8);
OpenTextFile("foo.txt", Encoding.UTF8, bufferSize: 4096);
OpenTextFile(
    bufferSize: 4096,
    path: "foo.txt",
    detectEncoding: false);

O compilador trata os valores por omissão como trata os campos constantes tomando o seu valor e usando-o em vez de uma referência ao valor. Portanto, tal como com os campos constantes, os métodos com parâmetros com valores por omissão não devem ser expostos publicamente (não esquecer que membros internos podem ser aceiddos publicamente – InternalsVisibleToAttribute). Se tais métodos forem acedidos publicamente por outra assemby, esses valores serão codificados no código chamador e, se a assembly chamada tiver esses valores modificados, essa modificação não se reflectirá no código já compilado.

À primeira vista, pensei que usar os argumentos opcionais para chamar “mau” código era bom, mas a possibilidade de definir esse tipo de métodos era terrível. Mas depois apercebi-me que, uma vez que uso campos constantes, não será mau usar métodos com parâmetros com valores por omissão pra métodos de acesso privado.

Posted: Friday, April 16, 2010 2:06 AM by Paulo Morgado

Comments

Paulo Morgado said:

Tal como mencionei na minha última entrada , expor publicamente métodos com argumentos opcionais é uma...

http://paulomorgado.net/pt/blog/archive/2010/04/18/c-4-0-alternativa-aos-argumentos-opcionais.aspx

# April 18, 2010 5:45 AM
Anonymous comments are disabled