Mostrando postagens com marcador C#. Mostrar todas as postagens
Mostrando postagens com marcador C#. Mostrar todas as postagens

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.

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 ;
}


domingo, 28 de setembro de 2008

Orientação a Objetos: De religião a ferramenta

Me lembro muito bem que nos primeiros anos de faculdade, as tendências rumavam para a tecnologia J2EE da Sun, em torno de uma forte linguagem que se consolidou, naquela época, que foi o Java. Isso foi entre 2002 e 2003.
Junto com a linguagem Java, o paradigma de orientação a objetos consolidou uma legião de adeptos, e é de uma parte desses adeptos principalmente que eu dirijo esse post.

Naquela epoca, embora a OO já possuísse um conjunto de regras que a delineava, alguns grupos insistiam em seguir certas doutrinas como uma religião. Cansei de ouvir alguns gurus comentando sobre features presentes no C# (delegates, partial classes, etc..) em seus comparativos inevitáveis algo como: "isso é uma implementação que foge os princípios da orientação a objetos. [ponto final]" (como se isso fosse algum demérito!) - na minha opnião, dane-se!

Afinal de contas, quem está a serviço de quem? Não me lembro de ter assinado nenhum contrato de escravidão com a OO. Além do mais, dogmas são extremamente nocivos para a inovação, pois enquanto você para de questionar algo, como você vai evoluir?
Design patterns? Será que só Gof sabem pensar, se você usa o seu padrão nas suas aplicações será que só porque você produziu, ele não é bom o bastante? Para alguns desses gurus, se não é um dos padrões altamente conhecidos, então é muito provável que você seja visto como alguem que não mereça crédito.

Semana passada eu li num artigo um comentário de um cidadão defendendo ferrenhamente que o Java se mantenha como está, utilizando o argumento de que é a implementação mais fiel da OO.
Na minha opnião, é o maior tiro no pé que o Java poderia dar (além de ser uma p... burrice). Pois isso significa parar no tempo e não se adaptar as novas tendências. Em outras palavras, suicídio.

É que tendências seriam essas?
Na minha opnião, a resposta está ficando cada vez mais fácil de ver: linguagens dinâmicas.

Não estou dizendo aqui que elas se tornarão a base de todo o código desenvolvido nas coorporações. O que eu acredito é que durante essa evolução dos últimos anos na tecnologia do desenvolvimento de software, apareceram alguns abismos causados principalmente por paradigmas distintos ( OO x ER e outros ) . Esses paradigmas necessitam de "pontes", e o uso de práticas de desenvolvimento advindas de linguagens dinâmicas atendem bem a esse propósito.

Com esse cenário, no fim de 2006 a Microsoft apresentou o a sua estratégia dentro dessa tendência, que seriam novas implementações na sua linguagem principal, o C#. Daí tivemos a chance de conhecer implementações que "dinamizaram" a linguagem com muitos elementos que são encontrados nas linguagens dinâmicas e até nos scripts, mas a grande diferença (que continuo a batendo) é a tipagem forte e a conservação de todas as características OO não como fator restritivo, mas sim funcional.

Então, se o Java tem juízo, vai acabar seguindo a tendência da mesma forma, a custo de ficar para trás na evolução das ferramentas de desenvolvimento. :-)
A bem da verdade, andei lendo em alguns fórums que features idênticas aos delegates do C# serão finalmente implementadas na próxima versão do java, a 1.7 (já é um começo, afinal de contas, qualquer linguagem que queira implementar recursos mais complexos de interação de coleções, que é a base do "Linq", necessita começar pela base: uma estrutura como um delegate ). Não duvido muito que estruturas similares a Extension Methods e Anonymous Types também venham no pacote.

Concluíndo, já estamos vendo que todas as novas funcionalidades advindas de bons feedbacks aprendidos das experiências com linguagens dinâmicas estão trazendo as linguagens de programação OO tradicionais para um novo patamar, onde a OO continua importante, mas agora sua doutrina fica em segundo plano.
Então observamos que ao longo do tempo, o que antes era visto como dogmas de uma religião ("não romper os princípios da OO!") começou a se tornar uma ferramenta. E podemos ainda concluir que a maior resistência a evolução para as novas tendências parte de quem mais defendeu os "preceitos religiosos" aqui referidos. Em termos práticos: A comunidade java tem uma ligação muito mais forte com os princípios puros da OO e Design Patterns, acredito eu que é em função disso que até agora ainda não possuem uma ferramenta que possa concorrer com o Linq no .net.

domingo, 21 de setembro de 2008

Anders Hejlsberg

Procurando pelo Blog desse gênio para acrescentar na minha lista de feeds do google reader, acabei achando essas duas entrevistas super interessantes sobre o Anders Hejlsberg.

Pra quem não conhece, Anders é o criador de nada menos que ferramentas como o Turbo Pascal e Delphi . Contratado pela Microsoft em 2006 por um trocado ($ 40.000.000,00) para desenvolver uma linguagem de programação totalmente nova que preparasse a Microsoft para aquilo que seria o .net, o C#.

Chanel 9: Life and Times of Anders Hejlsberg (2006) e What Influenced The Development of C# ( 2004)


Ahh.. Não achei o blog dele :-/

A evolução dos delegates

Ao longo das versões do C#, uma das funcionalidades que mais me reteve atenção como desenvolvedor foram Lambda Expressions. Desta forma, resolvi fazer um artigo expondo uma abordagem evolutiva sobre o tema (nada muito didático, meramente informativo):

C# 1.0

Quando tínhamos que escrever “ponteiros para uma função/método” no C# (óbvio que muitos não conhecem por esse nome, que é muito popular em C++, vou explicar melhor mais a frente), nós podíamos (e ainda podemos) adicioná-las em estruturas denominadas delegates da seguinte forma:



1- Se escreve o delegate, que é uma estrutura que funciona como um tipo, o qual aquele método vai ser vinculado, ou seja, se define uma referência com assinatura de método específica.

2- Se cria o método o qual se quer que o ponteiro aponte.

3- Com isso você pode adicionar (e remover) nessa referência qualquer método que tenha essa mesma assinatura, como se fosse uma lista de execução.

A conclusão que podemos chegar com delegates é que são mecanismos que permitem o agrupamento de vários métodos de diferentes classes para um pipeline execução. E justamente por isso, ele é utilizado em várias partes do .net framework, como threading, eventos, serialização etc.

Eventos
Como falei, no topo da estrutura de delegates está construída uma arquitetura de invocação implícita que ficou muito popular: eventos de componentes. Eventos são delegates especiais. Ele tem uma assinatura restrita que não deve retornar nada a não ser void, e só podem ser executados pela classe que os possui (classes filhas não executam diretamente eventos da classe pai). Essa especificidade é atribuída ao declarar a referência delegate a palavra chave event.



C# 2.0

As coisas ficaram um pouco mais práticas com o advento dos Anonymous Methods...

1 – Em muitos casos se deseja simplesmente executar uma operação vinculada a um evento de um componente (ex: setar visible=false no click do botão).
Isso significa que escrever um método unicamente pra fazer essa operação ser “burocracia demais”.

Pensando nisso, na versão do C# 2.0 foi criada, entre outras funcionalidades, Anonymous Methods, que é uma forma simplificada de escrever um método no contexto de um delegate:




Realmente simplificou mais, mas ainda não terminou...


C# 3.0

Tudo estava indo bem, até que apareceram essas tais lambda expressions, mas afinal, o que são lambda expressions? A resposta que mais gostei e a que uso é que é uma forma simplificada de escrever um delegate:

if ( querSaberMais?) {

goto: especificação do C# 3.0

if ( naoEntendiMuitoBem) {
Console.WriteLine(" Vou explicar com o nosso exemplo :-) ");
}
}

Na versão 2.0, criar um método anônimo para isso era a possibilidade mais ágil. Mas agora é possível proceder para resolver o mesmo problema com lambda expressions. A diferença é meramente uma questão de sintaxe:

Assim, assinar eventos simples como click’s de botão ficaram tão mais fáceis, que começei a inscrever muitos "onclicks" manualmente. Detalhe: a inferência de tipo é que faz o compilador procurar saber o tipo de "obj" e "e", o que é muito legal para quem tem dificuldades (como eu) de ficar decorando todos os XXXXEventArgs que tem poraí para cada evento diferente em função da vasta quantidade de XXXEventHandlers diferentes que os controles usam. :-)

Bom, é isso pessoal, no próximo post falarei sobre interfaces e Extension Methods, aguarde!

domingo, 7 de setembro de 2008

Strong typing com jeito de weak typing no C#




Pegando o gancho no último post sobre Javascript:

Acredito que o leitor deve ter percebido que uma coisa que pessoalmente não me agrada (com raríssimas exceções em casos específicos) são linguagens de programação que encorajam que seus tipos sejam "weakly typed"(fracamente tipados) .

A bem da verdade, produzir scripts que necessitam ligar um aplicativo, passar parâmetros de datas pra lá e pra cá, tarefas que realmente não necessitam propriamente de uma linguagem de programação robusta, basicamente uma linguagem dinâmica de script é o suficiente.

Agora quando você necessita de uma linguagem que, além de ser facilmente legível e ágil como as linguagens dinâmicas, mas que permita um encadeamento lógico necessário para se construir blocos de código estruturais, internos aos aplicativos, onde processo de construção necessita de uma abordagem diferenciada. Aí não há como dizer que tipagem forte não representa a opção mais sensata.

Alguns argumentos em favor disso:
  • A gerência da memória de dados é simplificada, afinal, quem define os tipos é o programador (não estou contando com reflection). Geralmente numa linguagem dinâmica, o tipo muda de acordo com o valor da variável, e é necessária uma estrutura extra pra cuidar desse processo.
  • Os recursos de intelisense ficam simplificados na implementação e 100% precisos, nada de “sugestões”. O javascript e outras linguagens sofrem bastante com esse problema.
  • Aumenta a facilidade de leitura, pois você já consegue identificar o tipo pela declaração.
  • A tipagem forte permite a você garantir que problemas inerentes ao tipo (conversões, chamadas de métodos, etc) não serão passados para a versão final do programa, uma vez que esse modelo também é efetivo contra a filtragem de erros e tempo de compilação/verificação de sintaxe.

No C# 3.0 conseguiu-se um meio termo muito interessante entre os principais argumentos de quem tem preferência por tipagem fraca (principalmente referidas a escrita) mas mantendo a solidez do modelo fortemente tipado.

Type Inference (Inferência de Tipo)

Observe:


Uma novidade no C# é a nova sintaxe para deixar que o compilador infira para você o tipo do objeto, com a palavra reservada var.

Na prática, o compilador (e o intelisense também) inferem que você inicializou o objeto com o tipo int, então o tipo daquela referência é int.

Datalhe: se você for querer passar para a variável, após o momento da inicialização algum valor que não seja do tipo inferido, ocorre um erro de compilação.



Type Inference + Anonymous Types

Mas se tem alguem ainda insatisfeito porque adoram o jeito "JSON" de programar das linguagens dinâmicas, saibam que o C# incorporou na sua versão 3.0 uma forma bastante interessante de declaração de dados:




O tipo é anônimo, mas é um tipo forte,o intelisense mostra isso: podemos acessar as variáveis internas do tipo anônimo sem delongas.

Conclusão

Embora uma implementação de linguagens com tipagem fraca careçam de alguns elementos importantes para o processo de desenvolvimento de software básico, existem princípios que podem ser bem aproveitados em linguagens como C# a fim de torná-la uma linguagem completa sem aumento de complexidade.