C# 4.0: Argumentos opcionais e argumentos nomeados

Email

Ufa, já faz 2 semanas que eu falei de C# 4. Estou finalizando uma edição da .Net Magazine e o grupo de arquitetura, o .Net Architects, tem tomado meu tempo (para assuntos bem legais, é verdade, ainda assim…). Assim que o fechamento da .Net Magazine passar tenho um monte de coisas para escrever por aqui. Enfim, vamos lá.

Se você está chegando agora, este é o quarto post sobre o assunto. Se você não viu os posts anteriores:

  1. C# 4.0 – Quanto antes melhor – onde apresentei um resumo das novidades, além de assuntos que envolvem a nova versão da linguagem;
  2. C# 4.0: Uma linguagem dinâmica – onde apresentei as novidades do C# 4.0 que vão aproximá-lo mais de uma linguagem dinâmicas.
  3. C# 4.0: Teremos covariância e contravariância – onde apresentei a tão esperada variância do C#.

O assunto que vou tratar aqui hoje, argumentos opcionais e nomeados, é mais uma feature para o pessoal reclamar que o C# está ficando parecido com o VB. Se você está reclamando já adianto, C# e VB são linguagens irmãs, são dialetos de uma mesma lingua, e, segundo a Microsoft, vão ficar mais e mais parecido ao longo dos anos. Tudo que tiver em um vai ter no outro (o que for possível, ao menos). Não vou ficar falando que VB é uma linguagem tão profissional quanto C#, e que as duas têm prós e contras, porque já disse isso aqui antes, em um dos posts da série Polêmicas (para a qual já tenho uns 5 ou 6 assuntos guardados). Fato é: as linguagens todas vão ficar mais dinâmicas. É a influência do Ruby (e do LINQ) sobre o .Net. Você não precisa usar, mas vai perder um monte se não usar.

Na linha deste tipo de preocupação, na última reunião do grupo, o André Dias e eu estávamos conversando sobre essa história do C# vir com dinamismo, e que tem gente achando que a palavra-chave dynamic é igual a um "Dim". Não é. Depois aproveito e posto sobre isso também.

Indo então ao ponto: argumentos opcionais e nomeados. Antes, se você tinha um método, e quisesse que algum parâmetro fosse opcional, você fazia um overload:

    class Boliche
    {
        public void Derrubar(int pinos)
        {
        }
        public void Derrubar()
        {
            this.Derrubar(0);
        }
    }

Assim, chamar Boliche.Derrubar(), sem parâmetros, é o mesmo que chamar Boliche.Derrubar(0), passando zero. Funcionava perfeitamente, só que dava um trabalhão, principalmente se você tivesse um monte de overloads, além de não ser explícito para o consumidor da classe, que tinha que ficar escolhendo qual overload usar e não sabia qual o valor padrão. Afinal, o consumidor não tem acesso ao fonte necessariamente, e onde está escrito que o valor padrão é zero? Pois agora esse problema será resolvido. O C# utilizará uma sintaxe muito parecida com a do VB, onde, após a definição do nome do parâmetro, você coloca um igual e o valor padrão. No VB ainda precisa da palavra-chave "optional". No C# não precisa. É simples assim, e é uma mão na roda, livrando a gente daquele monte de overloads, para fazer algo tão simples:

    class Boliche
    {
        public void Derrubar(int pinos = 0)
        {
        }
    }

A chamada do cliente ao método fica idêntica.

Parâmetros opcionais não são nada de novo. Existe no .Net (e portanto no CLR e no CLS) desde a versão 1.0, já que eram necessários para o VB funcionar. A IL sempre gerou parâmetros opcionais para o VB. São "novidades" em uma linguagem com release de 8 anos, existente desde o VB com guaraná com rolha… Não entendo porque o C# não tem isso desde o princípio… vai ver o pessoal do Java e do C/C++ que estava migrando ia reclamar que C# era muito parecido com o VB. Vai saber…

Pois bem, isso são parâmetros opcionais. Indo em frente: Argumentos nomeados vêm de mão dadas com parâmetros opcionais. Vejam esse exemplo:

    class Boliche
    {
        public void Derrubar(int pinos = 0, int pinosRestantes = 10)
        {
        }
    }

Posso chamar direto Boliche.Derrubar(), mas isso passaria zero e dez aos parâmetros. E se eu quisesse chamar o método passando somente o segundo argumento, chamado pinosRestantes? Fácil:

        static void Main(string[] args)
        {
            var b = new Boliche();
            b.Derrubar(pinosRestantes: 7);
        }

Neste caso, estou dizendo ao compilador que quero passar somente o segundo parâmetro, e que no primeiro aceito o valor padrão, que é zero. Também muito simples.

Algumas regras:

  1. Parâmetros opcionais são sempre os últimos. Você não pode ter um parâmetro não opcional à direita de um opcional. Faz sentido se você pensar na estruturação da sintaxe.
  2. Somente constantes são aceitas como valores padrão de parâmetros opcionais. Isso pode ser um bom motivo para continuar a usar overloads em alguns casos.
  3. Argumentos nomeados podem ser especificados em qualquer ordem. Você poderia chamar, por exemplo, Boliche.Derrubar(pinosRestantes: 5, pinos: 3), sem problemas. Mas ainda que possam ser especificados em qualquer ordem, eles serão avaliados na ordem escrita no método que está chamando, e não na ordem declarada na função. Isso é importante caso você esteja chamando funções para passar valor aos parâmetros, como Boliche.Derrubar(pinosRestantes: this.ObterPinosRestantes(), pinos: this.ObterPinosDerrubados()). Neste caso, o método ObterPinosRestantes é chamado antes do método ObterPinosDerrubados. Isso pode ser um problema caso você tenha funções com efeitos colaterais, algo que deve ser evitado a todo custo (não crie uma função que retorna um valor, e altera outro no contexto quase de forma escondida, a não ser que queira problemas para depurar depois).
  4. Você pode especificar argumentos não opcionais por nome normalmente. Isso não está restrito a argumentos opcionais.

Essas features são plenamente suportadas no CTP do Visual Studio 2010 que saiu em Outubro, ao contrário das features de variância e dinamismo, que estão pela metade.

No próximo post de C# 4.0 vou falar de interop com COM, e vocês vão ver o quanto isso ajuda neste tipo de caso.

Email
Esse post foi publicado em Sem categoria e marcado por Giovanni Bassi. Marcar link permanente.

Sobre Giovanni Bassi

Arquiteto e desenvolvedor, agilista, pai, filho, namorado, escalador, provocador.
Programa porque gosta, e começou a trabalhar com isso porque acha que trabalhar como administrador é meio chato. Por esse motivo sempre diz que nunca mais vai virar gerente de ninguém. E também porque acredita que pessoas autogerenciadas funcionam melhor e por acreditar que heterarquia é melhor que hierarquia. Mas isso é outro assunto.
Foi reconhecido  Microsoft MVP depois que alguém notou que ele não dormia a noite pra ficar escrevendo artigos, cuidando e participando do .Net Architects, gravando o podcast Tecnoretórica, escrevendo posts no blog e falando o que bem entende no twitter @giovannibassi. E por falar nisso é no twitter que conta pra todos que gerencia de projetos deve ser feita pelo time e não por um gerentes, que greves em TI são coisas sem sentido e que stored procedure com regras de negócio são malígnas.
Você já deve ter percebido (até porque está lá na primeira frase) que Giovanni é agilista. De tanto gostar disso ele trouxe os programas de certificação e treinamento  PSD e PSM da Scrum.org pro Brasil, e por causa deles, do MVP e de algum trabalho que aparece tem que ficar indo pros EUA de vez enquando, coisa que prefere não fazer. (É bem comum você ouvir ele perguntando porque a Scrum.org e a Microsoft não estão na Itália, por exemplo.)
Junto com alguns Jedis criou a Lambda3, que, apesar de ser pequena e de não ser muito comum no Brasil, insiste em fazer projetos e consultoria direito. Por causa da Lambda3 ele tem trabalhado mais do que quando era consultor independente, mas menos do que a maioria das pessoas. Quer dizer, isso se você considerar que os trabalhos junto à comunidade não são trabalho, caso contrário ele trabalha mais que a maioria das pessoas.
Recentemente ele resolveu que merecia viver melhor e ganhar uns anos de vida e desistiu de ser sedentário, fazendo algum barulho de vez em quando com os amigos no twitter com a hashtag #DotNetEmForma. Por causa do convite recente de amigos do lado Open Source (que ele respeita e admira), começou a escalar, e agora está sempre com as mãos machucadas. Mas ainda dá pra programar. Você encontra ele sempre em algum evento, como o TechEd, e o DNAD, mas também outros menos comuns para o pessoal do .NET, como a RubyConf. Nesses eventos, ou ele está vendo palestras, ou batendo papo com alguém, ou codando alguma aplicação que alguém achou que dava pra fazer durante o evento.
  • http://blog.fujiy.net/ Felipe Fujiy

    Algumas semanas atras li sobre o assunto num blog americano. E vi uma "falha" no caso dos argumentos nomeados. Na hora que voce os compila, ele ve no metodo qual os valores padrões e embute no codigo cliente, sua chamada ficaria:

    static void Main(string[] args)
    {
    var b = new Boliche();
    b.Derrubar(0, 7);
    }

    E se você mudar a DLL com o método, mudando o padrão do primeiro argumento pra 1, o valor padrão no cliente continuara sendo 0. A solução é recompilar todos os clientes do seu metodo.

  • http://unplugged.giggio.net/ Giovanni Bassi

    Felipe, é verdade. Mas isso já acontece com o Visual Basic. Acho que não vai mudar…

  • Heberton Melo

    Olá Giovanni.

    Estou aprendendo os conceito basico do C#, e estou com uma dúvida, poderia me explicar o que é parâmetros e argumentos?

    Desde já fico muit grato mesmo.

    Atenciosamente: Heberton Melo

  • http://unplugged.giggio.net/ Giovanni Bassi

    Olá Heberton,

    Neste caso, estou usando parâmetros e argumentos como sinônimos. Argumentos são os valores que você passa à uma função.
    Por exemplo, na função:

    public void Derrubar(int pinos = 0, int pinosRestantes = 10)

    Os parâmetros são os valores passados para "pinos" e "pinosRestantes".

  • Tulio Henrique

    Isso de arguntos com valor default já e muito utilizado no PHP

  • http://discountwatchonline.biz/ Audemars Piguet

    Do you accept guest posts? I would love to write couple articles here.

  • http://thewatchshop.biz/ Tommy Hilfiger

    I like your blog curently we are looking for a part time article writer would you be interested?