Back-End

22 jun, 2018

C# – Combinando Delegates (Delegate.Combine)

Publicidade

Hoje veremos como combinar Delegates na linguagem C#. Vamos começar lembrando a definição de delegate:

“Um delegate é um elemento da linguagem C# que permite que você faça referência a um método”.

Assim, usando um delegate, você pode encapsular a referência a um método dentro de um objeto de delegação.

O objeto de delegação pode ser passado para o código, o qual pode chamar o método referenciado sem ter que saber em tempo de compilação qual método será chamado.

Uma das formas simples de ver isso funcionando são os eventos. Para simplificar, vou usar os eventos dos controles Windows Forms. Em um projeto Windows Forms, quando temos um formulário com controles como o TextBox, geralmente usamos os eventos desses controles para realizar alguma ação.

Assim, vamos supor que temos um formulário Form1.cs com dois botões de comando: btnCancelar e btnOK.

A forma mais simples de usar os eventos neste caso é apenas clicar nos botões e acessar o código para o evento que é gerado automaticamente:

 private void btnOK_Click(object sender, EventArgs e)
        {
        }
        private void btnCancelar_Click(object sender, EventArgs e)
        {
        }

Uma outra forma é definir os eventos via código em um método no formulário.

Para isso, vamos definir uma chamada para um método EventosControles() no construtor do formulário, e a seguir, criar este método.

Neste método, vamos acessar o evento Click dos controles Buttons, definir um evento do tipo EventHandler e criar um método que manipula esse evento:

Pressionando F12 sobre o evento Click veremos a assinatura:

public event EventHandler Click;

Vamos então atribuir o evento EventHandler ao atributo Click, e como argumento, vamos definir o método btnOK_Click para o botão btnOK. Repetindo o processo para o botão btnCancelar, vamos definir o método btnCancelar_Click.

Teremos assim o seguinte código no formulário:

using System;
using System.Windows.Forms;
namespace Combinando_Delegates
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            EventosControles();
        }
        private void EventosControles()
        {
               this.btnOK.Click += new EventHandler(this.btnOK_Click);
            this.btnCancelar.Click += new EventHandler(this.btnCancelar_Click);
        } 
        private void btnCancelar_Click(object sender, EventArgs e)
        {
             DialogResult = DialogResult.Cancel;
             Close();
         }

         private void btnOK_Click(object sender, EventArgs e)
         {
             DialogResult = DialogResult.Ok;
             Close();
         }
    }
}

Para criar os métodos btnCancelar_Click e btnOK_Click, pressionamos F12 no evento EventHandler e verificamos que a assinatura deste evento é:

Assim, os métodos criados têm que retornar void e possuir dois parâmetros: object e EventArgs para se adequar à assinatura do delegate. Observe que usamos o operador += para incluir um comportamento quando o evento ocorrer.

Dessa forma o argumento do construtor do delegate fortemente tipado é uma referência para um método que respeita sua assinatura.

Agora note que temos código duplicado pois ambos os métodos chamam o método Close();

Vamos então simplificar o código definindo um novo método Fechar() onde chamamos o método Close(); e passando este método como um argumento para o delegate EventHandler.

using System;
using System.Windows.Forms;
namespace Combinando_Delegates
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            EventosControles();
        }
        private void EventosControles()
        {
            this.btnOK.Click += new EventHandler(this.btnOK_Click);
            this.btnCancelar.Click += new EventHandler(this.btnCancelar_Click);
            //
            btnOK.Click += new EventHandler(Fechar);
            btnCancelar.Click += new EventHandler(Fechar);
        }
        private void btnCancelar_Click(object sender, EventArgs e)
        {
            DialogResult = DialogResult.Cancel;
        }
        private void btnOK_Click(object sender, EventArgs e)
        {
            DialogResult = DialogResult.OK;
        }
        private void Fechar (object sender, EventArgs e)
        {
            Close();
        }
    }
}

Melhorou, mas podemos ir além.

Podemos otimizar o código combinando os delegates e podemos fazer isso usando duas sintaxes distintas:

  • var OkEventHandler = (EventHandler)btnOK_Click + Fechar;
  • var cancelarEventHandler = (EventHandler)Delegate.Combine((EventHandler)btnCancelar_Click, (EventHandler)Fechar);

O primeiro usa a sobrecarga do operador +, e, o segundo, o método Delegate.Combine que concatena listas de invocação de um matriz de delegates.

Assim o nosso código, já otimizado, ficaria assim:

using System;
using System.Windows.Forms;
namespace Combinando_Delegates
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            EventosControles();
        }
        private void EventosControles()
        {
            var OkEventHandler = (EventHandler)btnOK_Click + Fechar;
            var cancelarEventHandler = (EventHandler)Delegate.Combine((EventHandler)btnCancelar_Click, (EventHandler)Fechar);
            //
            btnOK.Click += OkEventHandler;
            btnCancelar.Click += cancelarEventHandler;
        }
        private void btnCancelar_Click(object sender, EventArgs e)=> DialogResult = DialogResult.Cancel;
        private void btnOK_Click(object sender, EventArgs e) => DialogResult = DialogResult.OK;
        private void Fechar (object sender, EventArgs e) =>  Close();
    }
}

Embora o exemplo seja bem simples deu para perceber que usando o recurso dos delegates podemos combinar invocações de mais de um delegate e tornar o nosso código mais elegante.

E estamos conversados.