Delegados C#

Resumo : neste tutorial, você aprenderá sobre os delegados C# e como usá-los de maneira eficaz.

Introdução aos delegados C#

Em C#, delegados são tipos que representam referências a métodos com uma lista de parâmetros e tipo de retorno específicos.

Para definir um delegado, você usa a delegatepalavra-chave e especifica a assinatura do método. Por exemplo:

delegate void Greeting(string message);Linguagem de código:  C#  ( cs )

Neste exemplo, definimos o Greetingtipo delegado que pode fazer referência a qualquer método que aceite um argumento de string e retorne void.

Como the Greetingé um tipo delegado, você pode declará-lo fora de uma classe como outras classes.

O seguinte define o SayHi()método da Programclasse, que possui a mesma assinatura do Greetingdelegado:

class Program
{
    static void SayHi(string name)
    {
        Console.WriteLine($"Hi {name}");
    }
    // ...
}Linguagem de código:  C#  ( cs )

Para chamar o SayHi()método por meio do Greetingdelegado, você cria uma instância do Greetingdelegado com o SayHimétodo como argumento e chama o Invoke()método da instância do delegado assim:

Greeting greeting = new Greeting(SayHi);
greeting.Invoke("John");Linguagem de código:  C#  ( cs )

Nesta sintaxe, greetingé uma instância do Greetingtipo delegado. O greetingdelegado contém uma referência ao SayHi()método. Internamente, o greetingdelegado mantém uma lista de invocação que contém uma referência ao SayHi()método.

Quando você chama o Invoke()método do greetingdelegado, C# chamará o SayHi()método com o mesmo argumento. Portanto, as seguintes afirmações são funcionalmente equivalentes:

greeting.Invoke("John");Linguagem de código:  JavaScript  ( javascript )

E:

SayHi("John");Linguagem de código:  JavaScript  ( javascript )

C# fornece uma maneira mais curta de criar uma nova instância do Greetingdelegado, atribuindo o SayHimétodo a uma variável delegada e chamando o método referenciado por meio do delegado:

Greeting greeting = SayHi;
greeting("John");Linguagem de código:  JavaScript  ( javascript )

Observe que você atribui o nome do método SayHisem parênteses ()à variável delegada.

Junte tudo.

delegate void Greeting(string message);

class Program
{
    static void SayHi(string name)
    {
        Console.WriteLine($"Hi {name}");
    }

    static void Main(string[] args)
    {
        Greeting greeting = SayHi;
        greeting("John");
    }
}Linguagem de código:  C#  ( cs )

Saída:

Hi JohnLinguagem de código:  C#  ( cs )

Se você tem experiência em C++, a maneira mais rápida de entender os delegados é considerá-los como ponteiros de função. No entanto, um delegado é totalmente orientado a objetos em C#. E, diferentemente dos ponteiros de função C++, os delegados encapsulam uma instância de objeto e um método.

Por que delegados

Como você pode chamar o SayHi()método diretamente, não precisa chamá-lo por meio do delegado. A questão é por que você precisa de um delegado?

Como os delegados mantêm referências a métodos, você pode passar métodos como argumentos para outros métodos por meio dos delegados. Portanto, os delegados são ideais para definir métodos de retorno de chamada .

Suponha que você queira definir um método que filtre uma lista de inteiros com base no resultado de outro método. Para fazer isso, você pode usar um delegado.

Primeiro, defina um tipo delegado que aceite um número inteiro e retorne um valor booleano:

delegate bool Callback(int x);Linguagem de código:  C#  ( cs )

Segundo, defina o Filter()método que aceita uma lista de números inteiros e uma instância do arquivo Callback. Se um número inteiro fizer com que o retorno de chamada retorne true, o resultado do Filter()método incluirá esse número inteiro:

static List<int> Filter(List<int> numbers, Callback callback)
{
    var results = new List<int>();

    foreach (var number in numbers)
    {
        if (callback(number))
        {
            results.Add(number);
        }
    }

    return results;
}Linguagem de código:  C#  ( cs )

Terceiro, defina o isOdd()método que retorna truese um número for ímpar e o isEven()método que retorna truese um número for par:

static bool IsOdd(int x) => x % 2 != 0;
static bool IsEven(int x) => x % 2 == 0;Linguagem de código:  C#  ( cs )

Quarto, chame o Filter()método e passe uma instância do Callbackdelegado que faz referência ao IsEven()método. O Filter()método retorna uma lista de números inteiros pares:

var numbers = new List<int> { 1, 2, 3, 4, 5 };

var evenNumbers = Filter(numbers, IsEven);

Console.WriteLine("Even numbers:");
foreach (var number in evenNumbers)
{
    Console.WriteLine($"{number}");
}Linguagem de código:  C#  ( cs )

Saída:

Even numbers:
2
4Linguagem de código:  C#  ( cs )

Quinto, chame o Filter()método e passe uma instância do Callbackdelegado que faz referência ao isOdd()método. O Filter()método retorna uma lista de números inteiros ímpares:

var numbers = new List<int> { 1, 2, 3, 4, 5 };

var oddNumbers = Filter(numbers, IsOdd);

Console.WriteLine("Odd numbers:");
foreach (var number in oddNumbers)
{
    Console.WriteLine($"{number}");
}Linguagem de código:  C#  ( cs )

Saída:

Odd numbers:
1
3
5Linguagem de código:  C#  ( cs )

Junte tudo:

class Program
{
    delegate bool Callback(int x);

    static List<int> Filter(List<int> numbers, Callback callback)
    {
        var results = new List<int>();

        foreach (var number in numbers)
        {
            if (callback(number))
            {
                results.Add(number);
            }
        }

        return results;
    }

    static bool IsOdd(int x) => x % 2 != 0;
    static bool IsEven(int x) => x % 2 == 0;

    static void Main(string[] args)
    {
        var numbers = new List<int> { 1, 2, 3, 4, 5 };

        var evenNumbers = Filter(numbers, IsEven);
        Console.WriteLine("Even numbers:");
        foreach (var number in evenNumbers)
        {
            Console.WriteLine($"{number}");
        }


        var oddNumbers = Filter(numbers, IsOdd);
        Console.WriteLine("Odd numbers:");
        foreach (var number in oddNumbers)
        {
            Console.WriteLine($"{number}");
        }
    }
}Linguagem de código:  C#  ( cs )

Usando um delegado como retorno de chamada, você pode passar um método como argumento para outro método. Neste exemplo, o Filter()método é muito dinâmico e pode aceitar qualquer método para filtrar a lista de inteiros.

Adicionando métodos a um delegado

Um delegado pode conter referências a vários métodos. Neste caso, o delegado é chamado de delegado multicast .

Para adicionar um método a um delegado, você usa o +=operador. Por exemplo:

delegate void Greeting(string message);

class Program
{
    static void SayHi(string name) => Console.WriteLine($"Hi {name}");

    static void SayBye(string name) => Console.WriteLine($"Bye {name}");
   
    static void Main(string[] args)
    {
        Greeting greeting = SayHi;
        greeting += SayBye;
        greeting("John");
    }
}Linguagem de código:  JavaScript  ( javascript )

Saída:

Hi John
Bye John

Como funciona.

Primeiro, defina o Greetingtipo de delegado:

delegate void Greeting(string message);Linguagem de código:  JavaScript  ( javascript )

A seguir, defina dois métodos estáticos SayHi()e SayBye()na Programclasse:

static void SayHi(string name) => Console.WriteLine($"Hi {name}");
static void SayBye(string name) => Console.WriteLine($"Bye {name}");Linguagem de código:  JavaScript  ( javascript )

Em seguida, crie uma nova instância do Greetingtipo delegado e atribua o SayHimétodo à variável de saudação:

Greeting greeting = SayHi;

Depois disso, adicione um novo método à lista de invocação do greetingdelegado:

greeting += SayBye;

Finalmente, chame os métodos na lista de invocação do delegado de saudação:

greeting("John");Linguagem de código:  JavaScript  ( javascript )

Esta instrução invoca o método SayHi()and SayBye()na lista de invocação do método de saudação. É importante observar que o delegado pode chamar os métodos da sua lista de invocação em qualquer ordem. Portanto, você não deve confiar na ordem dos métodos.

Os delegados são imutáveis. Isso significa que um delegado não pode ser alterado depois de criado. Portanto, o seguinte cria um novo delegado e o atribui à variável de saudação:

greeting += SayBye;

Removendo um método de um delegado

Para remover um método de um delegado, você usa o -=operador. Observe que o C# emitirá um erro se você tentar chamar um delegado com uma lista de invocação vazia.

O exemplo a seguir ilustra como remover um método da lista de invocação de um delegado:

delegate void Greeting(string message);

class Program
{
    static void SayHi(string name) => Console.WriteLine($"Hi {name}");

    static void SayBye(string name) => Console.WriteLine($"Bye {name}");

    static void Say(string message) => Console.WriteLine(message);

    static void Main(string[] args)
    {
        Greeting greeting = SayHi;
        greeting += Say;
        greeting += SayBye;

        greeting -= SayHi;

        greeting("John");
    }
}Linguagem de código:  C#  ( cs )

Saída:

John
Bye John

Neste exemplo, antes de chamar os métodos, removemos o SayHimétodo da lista de invocação do delegado de saudação:

greeting -= SayHi;Linguagem de código:  C#  ( cs )

Se você remover todos os métodos da lista de invocação de um delegado, o delegado será nulo. Para invocar o delegado com uma verificação nula, você pode usar um operador condicional nulo como este:

greeting?.Invoke("John");Linguagem de código:  C#  ( cs )

Resumo

  • Um delegado é um tipo que faz referência a métodos com uma lista de parâmetros e tipo de retorno específicos.
  • Use um delegado como retorno de chamada para passar um método como argumento para outro método.
  • Os delegados são imutáveis.
  • Use +=o operador para adicionar um método à lista de invocação de um delegado.
  • Use -=o operador para remover um método da lista de invocação de um delegado.

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *