Hoje vou falar de um dos recursos mais interessantes, encontrados nas linguangens que rodam sobre a plataforma .NET, os Delegates. Delegates também podem ser encontrados em Javascript, C e C++, sendo algo que facilita o desenvolvimento em diversos cenários. Há pouco tempo, quando me veio a idéia de fazer esse post, me deparei com uma dúvida referente a Delegates vs Closures (algo que pode ser conferido aqui e aqui).

Delegates (eu já vi isso em algum lugar… ponteiros de função???)

No fim das contas sim, Delegates são referências que apontam para um método específico que podem ser guardadas em variáveis e até passadas como parâmetro para outros métodos. A grande diferença entre ponteiros de função e os Delegates do C# é que os Delegates são Type Safe, ou seja, delimitam em tempo de compilação o tipo do retorno e dos parâmetros que o método deverá possuir para ser atribuido aquele Delegate.

//Delegate
public delegate void DelegateExemplo(string parametro);

//Método
public  void MetodoExemplo(string parametro)
{
 Console.Writeln(parametro);
}

//Utilização
DelegateExemplo Del = MetodoExemplo;
//ou
DelegateExemplo Del = new DelegateExemplo(MetodoExemplo);
Del("teste");

//Ele também pode ser passado como parâmtro para outro método
public void TesteDelegate(string parametro, DelegateExemplo del)
{
 del(parametro);
}

//Temos também no .NET Framework 3.0 delegates anonimos:
TesteDelegate("teste", delegate(string parametro) { Console.Writeln(parametro) });

Um delegate é um método declarado no mesmo escopo dos outros métodos e somente captura o objeto referente à classe onde foi declarado, diferente de Closures, que capturam todo o contexto em que elas estão inseridas. Quem conhece Javascript, C ou C++ sabe como esse recurso pode ser utilizado de maneira interessante.

public class TesteDelegates
{
 public void Main()
 {
 new Thread(delegate() {while(true) {Console.Writeln("Usando Delegate");}}).Start();
 }
}

A grande vantagem de utilizar delegates, é que você não precisa passar um objeto inteiro como parâmetro para utilizar apenas um comportamento (método) específico, economizando um bom esforço com a criação e instanciação do objeto ao qual se deseja invocar o método. Java possui uma enorme “deficiência” em relação a essa característica, ao qual procura compensá-la com a utilização de Annonimous Inner Classes:

public class TesteDelegates {
 public static void main(String[] args) {
 new Thread(new Runnable() {
 public void run() {
 while(true) {
 System.out.println("Usando Annonimous Inner Classes");
 }
 }
 }).start();
 }
}

Em Javascript utilizamos esse recurso quando declaramos objetos:

function TesteDelegates {
 this.teste = function() { alert('Teste'); }
}

Conclusão

Esse post falou sobre delegates, um recurso muito interessante, que pode ser observado em diversas linguagens. Ele possui certa semelhança com Closures, diferindo apenas em questão de acessibilidade de escopo. Java, como pudemos ver, utiliza classes anônimas para representar códigos onde os delegates podem ser aplicados. Isso é algo que, em meu ver, dificulta um pouco a expressividade e legibilidade do código. Em breve falarei um pouco sobre os recursos de Event Handling em .NET, algo que está intimamente ligado com os delegates. Abraços e até a próxima.