sábado, 18 de outubro de 2008

Interfaces e Extension Methods: Uma Combinação poderosa (parte 2)

Olá Pessoal,

Finalmente consegui terminar! Essa parte do post demorou um pouco porque o trabalho apertou. Espero que curtam.

Agora que vocês estão familiarizados com Extension Methods, então vale a pena mostrar do que ele é capaz na prática no sentido de facilitar e viabilizar desenhos arquiteturais antes de difícil implementação.

No nosso exemplo, a idéia é mostrar como se cria uma biblioteca de controles herdada da biblioteca padrão System.Web.UI.WebControls e adicionar aos controles uma propriedade chamada DataBinder do tipo IDataBinder.

public interface IDataBinder
{

}

public class MeuTextBoxHerdado : System.Web.UI.WebControls.TextBox
{
public IDataBinder DataBinder{ get; set; }
}

A classe que implementará a propriedade nesse cenário é o que menos irá importar. O importante é que DataBinder será um ponto onde nós poderemos pendurar Extension Methods. A idéia lembra um pouco as "Interfaces de Marcação", que são utilizada em algumas situações no ASP.NET para indicar que uma classe deve receber alguma implementação especial que será controlada por outra classe (procure saber sobre INamingContainer), só que sem a necessidade do uso de reflection.

A diferença é que o ponto de marcação não é uma classe atributo, mas sim uma propriedade, e a partir dela poderemos implementar uma gama de recursos, que poderão ser facilmente portados para outros controles. Para isso, basta que os mesmos possuam uma propriedade qualquer que seja daquele tipo.

Assim, podemos começar a construir nossa biblioteca de extension Methods.


public static BibliotecaDataBinder{

public static void BindText(this IDataBinder control, object dataSource)
{

}

public static object Read(this IDataBinder control)
{

}

...

}

Para usar, basta referenciar o namespace, e finalmente:

MeuTextBoxHerdado h = new MeuTextBoxHerdado();
h.DataBinder.BindText("Olá");

Assim, você pode usar vários métodos úteis através da propriedade. Cabe a você como arquiteto decidir quais os métodos e propriedades que a interface deve mandar implementar para ter o trabalho feito.

Nesse aspecto, dependendo do caso, sería até uma estratégia interessante manter a própria classe como implementadora da interface IDataBinder, assim, os membros da classe vão poder ser acessados diretamente pela nossa biblioteca.

Reconheço que essa parte é um pouco complicada de abstrair, mas a flexibilidade do modelo faz ele valer a pena. Com essa arquitetura, recentemente migramos do modelo WebForms para MVC com uma simples adição de uma propriedade.

quarta-feira, 15 de outubro de 2008

Silverlight 2 Released!

Olá pessoal!

O recado de hoje é que o Silverlight 2 já está liberado na versão final. É uma ótima oportunidade de começar a experimentar novos paradigmas, desenvolvendo a próxima geração de interfaces web.

[]'s!

PS: Ainda estou escrevendo a segunda parte do post sobre Interfaces e Extension Methods ( muito trabalho essa semana e foi complicado de avançar)

domingo, 5 de outubro de 2008

Interfaces e Extension Methods: uma combinação poderosa (parte 1)

Dividi esse post em três partes para que quem estiver vendo ExtensionMethods pela primeira vez possa digerir e aplicar a informação para que se siga para a segunda e terceira parte.

A primeira parte (esse post) explica os coneitos básicos de Extension Methods.

A segunda parte (que vou terminar de escrever ao longo da semana) vai procurar mostrar como implementar um modelo de validação de controles distintos através de interfaces comuns com extension methods.

A terceira parte (que pretendo escrever em breve) vai mostrar a importância do uso de extension methods com interfaces na arquitetura do linq. Procurando dissecar a estratégia usada na classe IQueryable.

Extension Methods (Vamos lá!)

Se eu pudesse enumerar um motivo para não deixar o C# 3.0 por qualquer versão anterior no .net, esse motivo seria Extension Methods. Definitivamente!

Extension Methods é uma maneira muito elegante de incorporar em classes métodos que não são própriamente da classe, mas sim de uma classe de "extensão".

Para escrever extension Methods, devemos ter em mente algumas regrinhas básicas:

  • Extension Methods devem contidos em classes estáticas, ou seja, uma classe que contenha apenas membros estáticos.
  • Assim, não é difícil concluir que Extension Methods são métodos estáticos. :-P
  • Pela natureza dessa funcionalidade, há possibilidade de colisão de identificadores, então, o compilador C# adota padrões de precedência.

Pois bem, para quem nunca viu um Extension Method, funciona da seguinte forma:

Se imagine no C# 2.0, onde você tem sua função "CpfValido" que faz a verificação de um CPF a partir de uma string de entrada e retorna bool (true se o CPF for válido):

string cpf = "822.232.339-99";
...

if ( MinhaClasse.EhCpf(cpf) ){
//código válido...
}

Confesse! :-) O que você realmente gostaria de usar seria:

string cpf = "822.232.339-99";
...

if ( cpf.EhCpf() ){
//código válido...
}


mas afinal, isso era impossível! EhCpf não é um método da classe string, e sim de uma classe utilitária que não tem nenhuma relação de herança com a classe string. E até esse ponto (C# 2.0) não há nenhuma forma de produzir tal efeito se não fosse através de mecanismos de herança (e no caso da classe string, que é selada, nem isso! Então como fica?). Mas o panorama mudou no C# 3.0...

na sua classe utilitária, que era algo do tipo:

namespace MeuNamespace{

public static class MinhaClasse{

public static bool EhCpf(string cpf){
//Trata se eh CPF

}

}


}

Agora fica:


namespace MeuNamespace{

public static class MinhaClasse{

public static bool EhCpf(this string cpf){
//Trata se eh CPF

}

}


}
Só isso! Agora sua classe "MinhaClasse" pode ser usada como um extension method da classe string. Mas para isso, você deve referenciar o namespace com a clausula using no contexto do código, como descrito no exemplo.

quarta-feira, 1 de outubro de 2008

Dica: Application Idle

Quando se fala de processamento background em .net, você pode encontrar toneladas de formas diferentes de executar operações. A grande maioria delas envolvem threads diferentes da thread principal do programa (Application Pool, ThreadStart etc...).

Mas uma maneira interessante realizar atividades que não demandam de tanta carga de processamento pode ser o uso do evento Application.Idle.

Esse evento existe porque o .net tem como saber quando a thread principal está entrando no modo Idle (ocioso), e a execução do evento permite que se faça "alguma coisinha a mais" antes de entrar no modo idle.

Tenho utilizado o idle para implementar a persistência de um buffer de log de atividades de um sistema, e o desempenho é bem satisfatório, afinal, você deixar essa operação no evento Idle significa que ela não vai ficar sendo executada toda hora, e sim quando a aplicação teoricamente "não tiver nada de mais importante pra fazer", o que já é legal:

int contador = 0;

private void Form1_Load(object sender, System.EventArgs e)
{
Application.Idle += ( o, e) => { contador++ ; };
}


Esse é só um exemplo, mas aviso que nesse caso, o "Form1" em questão é o principal e
quando ele fecha, é porque a aplicação fecha, então tudo bem ter um lambda expression
aí (anônimo). Mas possivelmente não será uma boa prática para outros casos.

A razão disso está no fato de que como o evento Idle é estático, é muito importante que
no momento em que você vincula um delegate do tipo EventHandler a ele, é necesário
que você mantenha uma rotina de desvinculação preparada para retirar o evento, senão
isso pode se tornar um memory leak.
int contador = 0;
EventHandler myHandler = new EventHandler(Contar);

private void Contar( object sender, EventArgs e)
{
contador++;
}

private void Form1_Load(object sender, System.EventArgs e)
{
Application.Idle += myHandler
;
}

//o código de desvinculação pode ficar associado ao destrutor
~Form1()
{
Application.Idle -= myHandler ;
}