C# - Apresentando o delegate Func


 Neste artigo eu vou apresentar os conceitos básicos envolvidos na utilização do delegado Func na linguagem C#.

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 :

Conceitos Básicos

1- O delegate 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>

Sintaxe :

 public delegate TResult Func<out TResult>
 public  delegate TResult Func<in T, out TResult>( T arg)
 public  delegate TResult Func<in T1, in T2, out TResult>( T1 arg, T2 arg)  
 mais 13 sobrecargas...

Parâmetros de tipo :

         in T

         - Onde T é o tipo do parâmetro do método que encapsula este delegado. (Este parâmetro de tipo é contravariante. Ou seja, você pode usar o tipo especificado ou qualquer tipo que seja menos derivado)

       out TResult
  -  O tipo de valor de retorno do método que encapsula a este delegado.

Parâmetros :

        arg

        - O parâmetro do método que encapsula este delegado;

Valor de retorno :

        Tipo: TResult
        -  O valor de retorno do método que encapsula a este delegado.

Este delegate está contido no assembly mscorlib.dll namespace System.

Como você pode observar nas definições, este delegate sempre segue a mesma regra : O último tipo declarado é o tipo de retorno devolvido pela função que implementa este delegado.

Então se você precisar de um delegate que retorne um valor e tenha de 1 até 16 parâmetros pode usar delegate Func.

Exemplo : Usando 1 parâmetro :

using System;
namespace CSharp_Delegate_Func
{
    class Program
    {
        static void Main(string[] args)
        {
            Func<string> saudacoes = BomDia;
            string bomdia = saudacoes();
            Console.WriteLine(bomdia);
        }
        private static string BomDia()
        {
            return  "Bom dia";
        }
    }
}

Exemplo : Usando 2 parâmetros :

using System;
namespace Func2
{
    class Program
    {
        static void Main(string[] args)
        {
            Func<double, double, double> Calcular = Adicionar;
            double resultadoSoma = Calcular(9.7, 12.6);
            Console.WriteLine(resultadoSoma);
            Console.ReadKey();
        }
        private static double Adicionar(double n1, double n2)
        {
            return n1 + n2;
        }
    }
}

Na linguagem C# também podemos definir delegates usando Funções Anônimas ou (Anonymous Functions).

Uma função anônima é uma declaração "in-line" ou expressão que pode ser usada sempre que um tipo de delegado é esperado. Podemos usá-las para inicializar um delegado nomeado ou passar um função anônima em vez de um tipo de delegado nomeado como um parâmetro de método.

Existem dois tipos de de Funções Anônimas:

  1. Métodos Anônimos (Anonymous Method)

  2. Expressões Lambdas (Lambdas Expressions).

1- Usando Métodos Anônimos

Vejamos um exemplo de utilização de delegate Func usando métodos anônimos :

using System;
namespace Func_MetodoAnonimo
{
    class Program
    {
        static void Main(string[] args)
        {
            Func<int , bool> IsPositivo = delegate(int numero)
            {
                return numero > 0;
            };
            Console.WriteLine(string.Format("O Numero 9 é positivo : {0} ", IsPositivo(9)));
             Console.ReadKey();
        }
    }
}

No código acima definimos um delegado Func na seguinte declaração :

 Func<int , bool> IsPositivo = delegate(int numero)
 {
      return numero > 0;
 };

Nesta declaração estamos definindo um delegado com um método sem nome (gerado automaticamente pelo compilador) que é vinculado a instância do delegado (IsPositivo).

Nota: Lembre-se que os parâmetros definidos em um método anônimo possui escopo de bloco ou seja são válidos somente dentro da declaração do método anônimo.

1- Usando Expressões Lambdas

Uma expressão lambda é uma função anônima, ou seja, um método sem uma declaração, sem modificador de acesso, sem declaração de valor de retorno e sem nome.

Elas pode conter instruções e expressões e podemos usá-las para criar delegates ou tipos de árvores de expressão.  O operador lambda  é identificado como " => " e significa 'vai para'.

Declaração : Parâmetros => Código;

A partir da versão 3.0 da linguagem C# podemos expressar um delegate usando expressões lambdas. O mesmo exemplo acima ficaria assim usando este recurso:

using System;
namespace Func_MetodoAnonimo
{
    class Program
    {
        static void Main(string[] args)
        {
            Func<int, bool> IsPositivo = (int numero) =>
            {
                return numero > 0;
            };
            Console.WriteLine(string.Format("O Numero 9 é positivo : {0} ", IsPositivo(9)));
             Console.ReadKey();
        }
    }
}

Podemos simplificar ainda mais nossa declaração de delegate usando expressões lambdas (esse é um dos motivos para usá-las). Veja como fica agora o mesmo exemplo:

using System;
namespace Func_MetodoAnonimo
{
    class Program
    {
        static void Main(string[] args)
        {
            Func<int, bool> IsPositivo = numero => numero > 0;
            Console.WriteLine(string.Format("O Numero 9 é positivo : {0} ", IsPositivo(9)));
            Console.ReadKey();
        }
    }
}

Comparando a declaração do delegate podemos ver a evolução usando métodos anônimos e expressões lambdas:

 Func<int , bool> IsPositivo = delegate(int numero)
 {
      return numero > 0;
 };
Método anônimo
 Func<int , bool> IsPositivo = (int numero ) =>
 {
      return numero > 0;
 };
Expressão lambda
 Func<int , bool> IsPositivo = numero => numero > 0; Expressão lambda

Este recurso é válido para qualquer delegate. (Action, Func, Predicate, etc...)

Vejamos agora um exemplo mais prático e complexo de uso do delegate Func:

using System;
namespace Func_3
{
    class Program
    {
        static void Main(string[] args)
        {
            Func<Aluno, string> verificaNome = aluno =>
            {
                if (aluno.Nome.StartsWith("J"))
                    return aluno.Nome;
                else
                    return "O Aluno não atende o critério.";
            };
        Console.WriteLine(verificaNome(new Aluno() { Id = 12, Nome = "Macoratti" }));
        Console.WriteLine(verificaNome(new Aluno() { Id = 10, Nome = "Jefferson" }));
        Console.WriteLine(verificaNome(new Aluno() { Id = 7, Nome = "Janice" }));
        Console.ReadKey();
        }
    }
    public class Aluno
    {
        public int Id { get; set; }
        public string Nome { get; set; }
    }
}

Simplificando a sintaxe com o uso de expressões lambdas podemos escrever a declaração do nosso delegate Func como:


  Func<Aluno, string> verificaNome = aluno => aluno.Nome.StartsWith("J") ? aluno.Nome : "Não atende o critério";

 

Assim o delegate Func pode ser usado sempre que devemos ter um valor de retorno.

Pegue o exemplo do projeto aqui: CSharp_Delegate_Func.zip

    Lucas 9:23 E dizia a todos : Se alguém quer vir após mim, negue-se a si mesmo, e tome cada dia sua cruz, e siga-me.
    Lucas 9:24 Porque, qualquer que quiser salvar a sua vida, perdê-la-á; mas qualquer que, por amor de mim, perder a sua vida, a salvará.


 

Referências:


José Carlos Macoratti