C# - Usando expressões lambdas para implementar delegates - III


 Continuando o nosso artigo anterior eu vou mostrar como podemos usar expressões lambdas para implementar delegates na linguagem C#.

Vamos implementar o cálculo da raiz quadrada de segundo grau usando métodos anônimos e mostrar como simplificar o código usando expressões lambdas e delegates como Func<T>.

Para você poder acompanhar e entender este artigo você tem que saber o que é um delegate. Se você tem dúvidas leia o meu artigo : C# - Delegates e Eventos : Conceitos básicos e depois prossiga na leitura.

Eu não vou entrar em detalhes sobre o que é um delegate (para detalhes leia o artigo) vou apenas apresentar a sua definição (uma delas):

Um Delegate é um ponteiro para um método. Um Delegate pode ser passado como um parâmetro para um método. Podemos mudar a implementação do método dinamicamente em tempo de execução, a única coisa que precisamos para fazer isso seria manter o tipo de parâmetro e o tipo de retorno.

Recursos usados :

Reescrevendo a implementação do cálculo da equação do segundo grau usando o delegate Func

Dependendo do cenário não precisamos criar o nosso delegate pois já existem delegates prontos que podemos pegar e usar. Este é o nosso caso pois o nosso exemplo esta usando 3 parâmetros e retornando um valor e para isso temos um delegate pronto chamado Func.

O Delegate Func encapsula um método que pode possuir até 16 parâmetros e que retorna um tipo especificado pelo parâmetro TResult.

Sua assinatura possui 17 sobrecargas:  Func(TResult), Func<T, TResult>, Func<T1,T2,TResult>, .....Func<T1,.....,T16,TResult>

Então porque se dar ao trabalho de declarar um delegate e depois atribuí-lo cada vez que precisamos usar a expressão lambda se podemos usar o delegate Func ?

Vamos voltar ao nosso exemplo de implementação para resolver uma equação do segundo grau.

Na primeira parte do artigo fizemos a implementação usando delegates com métodos anônimos.

Na segunda parte reescrevemos nossa implementação usando expressões lambdas

Como ficaria a nossa implementação usando expressões lambdas  e o delegate Func ?

O delegate EquacaoSegundoGrauDelegate não precisaria ser mais definido e seria substituído pelo delegate Func que já esta implementando na plataforma .NET.

Mas na implementação do cálculo do discriminante e das raízes vamos usar agora o delegate Func<> e as expressões lambdas.

Lembre-se que temos que passar 3 parâmetros (a, b, c) e temos que obter como retorno o valor da raiz.

Pela definição o delegate Func deve declarar os parâmetros que vai usar e o valor de retorno.

Assim teremos que declarar o delegate Func com 4 parâmetros sendo que o último é o parâmetro de retornos. Veja como ficou a nossa implementação:


 
  Func<double,double,double,double> discriminante = (a, b, c) => (b * b - 4d * a * c);
 Implementação do cálculo discriminante

 
  Func<double,double,double,double> raiz1 = (a, b, c) => (-b + Math.Sqrt(discriminante(a, b, c))) / (2 * a);
 
 Cálculo da primeira raiz

   Func<double, double, double, double> raiz2 = (a, b, c) => (-b - Math.Sqrt(discriminante(a, b, c))) / (2 * a);
  Cálculo da segunda raiz

A definição do delegate Func estão na cor vermelha.

Dessa forma abaixo temos as implementações dos delegates usando expressões lambdas usando o delegate Func com 3 exemplos de cálculos feitos :

  static void Metodo3()
  {
            Console.WriteLine("Método #2");

            // cria um método anônimo para calcular o discriminante
          
 Func<double,double,double,double> discriminante = (a, b, c) => (b * b - 4d * a * c);

            // cria métodos anônimos para calcular as raízes da equação
         
  Func<double,double,double,double> raiz1 = (a, b, c) => (-b + Math.Sqrt(discriminante(a, b, c))) / (2 * a);
            Func<double, double, double, double> raiz2 = (a, b, c) => (-b - Math.Sqrt(discriminante(a, b, c))) / (2 * a);


            // calcula as raizes para : x^2 + 5x + 6 usando a implementação das instâncias dos delegates
            double valor1 = raiz1(1d, 5d, 6d);
            double valor2 = raiz2(1d, 5d, 6d);
            //resultado
            Console.WriteLine("Para a equação:  x^2 + 5x + 6 : As raízes são {0}, {1}", valor1, valor2);
            // calcula as raizes para : x^2 + 10x + 24
            double valor3 = raiz1(1d, -10d, 24d);
            double valor4 = raiz2(1d, -10d, 24d);
            // resultado
            Console.WriteLine("Para a equação : x^2 - 10x + 24 : As raízes são {0}, {1}", valor3, valor4);
            // calcula as raizes para : x^2 + 8x + 16
            double valor5 = raiz1(1d, 8d, 16d);
            double valor6 = raiz2(1d, 8d, 16d);
            // resultado
            Console.WriteLine("Para a equação : x^2 + 8x + 16 : As raízes são {0}, {1}", valor5, valor6);
            Console.ReadLine();
   }

Dessa forma o nosso código ficou ainda mais enxuto e não houve mudança alguma na sua funcionalidade.

A seguir  temo o código completo da implementação e o resultado da sua execução :

using System;

namespace EquacaoSegundo_Grau_Func
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("------------------------------------------------------------------------");
            Console.WriteLine("Cálculo das raízes da equação do segundo grau pela fórmula de Bhaskara");
            Console.WriteLine("Usando expressões lambdas e o delegate Func<>");
            Console.WriteLine("------------------------------------------------------------------------");
            Metodo3();
            Console.WriteLine("------------------------------------------------------------------------");
            Console.ReadKey();
        }

        static void Metodo3()
        {
            Console.WriteLine("Método #2");

            // cria um método anônimo para calcular o discriminante
            Func<double,double,double,double> discriminante = (a, b, c) => (b * b - 4d * a * c);

            // cria métodos anônimos para calcular as raízes da equação
            Func<double,double,double,double> raiz1 = (a, b, c) => (-b + Math.Sqrt(discriminante(a, b, c))) / (2 * a);
            Func<double, double, double, double> raiz2 = (a, b, c) => (-b - Math.Sqrt(discriminante(a, b, c))) / (2 * a);
            // calcula as raizes para : x^2 + 5x + 6 usando a implementação das instâncias dos delegates
            double valor1 = raiz1(1d, 5d, 6d);
            double valor2 = raiz2(1d, 5d, 6d);
            //resultado
            Console.WriteLine("Para a equação:  x^2 + 5x + 6 : As raízes são {0}, {1}", valor1, valor2);
            // calcula as raizes para : x^2 + 10x + 24
            double valor3 = raiz1(1d, -10d, 24d);
            double valor4 = raiz2(1d, -10d, 24d);
            // resultado
       
    Console.WriteLine("Para a equação : x^2 - 10x + 24 : As raízes são {0}, {1}", valor3, valor4);
            // calcula as raizes para : x^2 + 8x + 16
            double valor5 = raiz1(1d, 8d, 16d);
            double valor6 = raiz2(1d, 8d, 16d);
            // resultado
            Console.WriteLine("Para a equação : x^2 + 8x + 16 : As raízes são {0}, {1}", valor5, valor6);
            Console.ReadLine();
        }
    }
}

Resultado obtido pela execução do código acima:

Assim mostramos como podemos usar delegates com métodos anônimos, expressões lambdas e também como usar o delegate Func, já implementado na plataforma .NET, para simplificar e melhorar o nosso código.

Pegue o exemplo do projeto aqui:  EquacaoSegundoGrau_Delegate_Lambda_Func.zip

 Porque não vos fizemos saber a virtude e a vinda de nosso Senhor Jesus Cristo, seguindo fábulas artificialmente compostas; mas nós mesmos vimos a sua majestade.  (2 Pedro 1:16)

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?


Referências:


José Carlos Macoratti