Olá pessoal. Tudo certo?!
No último post, mostrei como melhorar o “significado” do código através da criação de tipos para ValueTypes.
Nesse post, tento demonstrar como melhorar o código através de Extension Methods.
O que são Extension Methods
Segundo o MSDN:
Extension Methods permitem a você “adicionar” métodos para tipos existentes sem criar um novo derivado de tipo, recompilar ou modifique o tipo original de alguma forma. São um tipo especial de método estático, mas eles são chamados como se fossem os métodos de instância no tipo estendido. Para o código de cliente escrito em C# e Visual Basic, não existe aparente diferença entre chamar um método de extensão e os métodos que realmente são definidos em um tipo.
Estamos entendidos?
Criando um Extension Method
Como explicado na definição, um Extension Method é um tipo especial de método estático. Além disso, ele precisa estar definido em uma classe estática. Observe:
public static class StringExtensions
{
public static MemoryStream ToStream(this string value)
{
return new MemoryStream(Encoding.UTF8.GetBytes(value));
}
}
Agora, podemos escrever códigos assim:
var st = "Hello World!"; var s1 = st.ToStream(); var s2 = "Essa string será convertida em Stream".ToStream();
… e o compilador aceita!
Repare também na presença do modificador this antes do primeiro argumento. Esse modificador explicita o tipo que estamos “ampliando”.
Usos criativos
Nunca gostei da sintaxe do TimeSpan. Por isso, adorei a possibilidade de melhorar a legibilidade dos códigos que usam TimeSpan com Extension Methods. Observe:
public static class TimeSpanExtensions
{
public static TimeSpan Hours(this int value)
{
return new TimeSpan(value, 0, 0);
}
public static TimeSpan Minutes(this int value)
{
return new TimeSpan(0, value, 0);
}
public static TimeSpan Seconds(this int value)
{
return new TimeSpan(0, 0, value);
}
}
Bacana, não?! Agora, meus códigos que necessitam Timespan ficam assim:
class MainClass
{
public static void Main (string[] args)
{
var t = 2.Hours() + 14.Minutes() + 27.Seconds();
Console.WriteLine (t);
}
}
Bacana, não?!
Use, com moderação
Como vimos, Extension Methods representam uma excelente oportunidade de melhorar o código. Entretanto, eles podem fazer com que deixemos de realizar todo potencial da OO expandindo tipos existentes no lugar de definir tipos novos. Eu mesmo, cometo esse “engano” com mais frequência que gostaria.
Era isso.






Angelo
26/12/2011
Essa idéia de extender o TimeSpan me lembrou Ruby on Rails agora…
Muito Bom…
Alexandre Gama
26/12/2011
Bem legal o Post Elemar!
Pena que (se eu não me engano) teremos extension methods só no Java 8 =/
Abraços!
elemarjr
26/12/2011
Mas vai chegar …
Alfredo Lotar
26/12/2011
Ótimo artigo.
elemarjr
26/12/2011
Muito obrigado pelo feedback
Robson Ramos
26/12/2011
Ola Elemar. Tudo bem?
Eu também acho que Extension Methods é um recurso poderoso!
Mas, vale lembrar que a criação destes métodos são sensíveis a namespace, ou seja, se declarados em namespaces diferentes eu tenho que lembar de adicionar o “using” do namespace em questão (além do using da própria classe) para ter acesso aos métodos, assim como ocorre com o System.Linq.
Isto de certa forma me incomoda um pouco, não concorda?
elemarjr
26/12/2011
Opa! Muito bem lembrado.
Concordo com o “incômodo”. Mas, infelizmente, penso que esse seja um mal necessário. Há cenários onde não desejamos usar determinados Extension Methods (há também o conflito de assinaturas, em alguns cenários).
[]s
programator
26/12/2011
Olá Elemar, tudo bem? excelente artigo, parabéns.
Por uma feliz coincidência republiquei em um site hoje um artigo sobre o mesmo assunto, Extensions Methods, caso tenha interesse em dar uma olhada, fica o link:
http://csharpbrasil.com.br/csharp/conceitos-e-exemplo-pratico-extensions-methods/
Abraços e keep coding!
Acaz Souza
27/12/2011
Elemar, obrigado mais uma vez por esse excelente conteúdo. Mas resolvi pensar pela contra-mão e queria ouvir sua resposta: os métodos do LINQ são extension methods certo? Quais seriam os “down-sides” se os métodos do LINQ não fossem extension methods? Ou seja, o que ganhamos usando os métodos do LINQ como extension methods e não métodos de instância mesmo? Ou perguntando de outra maneira: que problemas foram evitados colocando extension methods em vez de acrescentar os métodos diretamente nos tipos?
elemarjr
27/12/2011
Opa. Excelentes perguntas.
LINQ foi planejado para funcionar com Interfaces, não com classes abstratas. Basicamente, foram necessárias apenas duas implementações: uma para IEnumberable, outra para IQueryable. Apenas duas implementações para um “mundo”de alternativas, visto que essas implementações conseguem cobrir praticamente qualquer implementação concreta de coleções do framework. Outro ponto a destacar é o suporte imediato a “yield return/break. Tudo isso só foi possível devido aos Extension Methods.
A implementação para IQueryable, especificamente, é uma “obra-prima” visto que vai “compondo” uma Expression tree que, mais tarde, é convertida em “consulta fim” mediante um provider adequado.
Escrever LINQ de outra forma implicaria em “repetição” de código.
Vale destacar que Extension Methods são Sugars. Pois mylist.Where(condition) .Where(mylist, condition).
Fui claro?
elemarjr
27/12/2011
Outro aspecto inteligente dessa abordagem é que você pode “substituir” facilmente o comportamento padrão escrevendo uma versão específica do operador na classe “alvo”. Ou seja, quer fazer um novo “Where”, escreva um.
acazsouza
28/12/2011
Uma pesquisada rápida e vi que um outro aspecto inteligente é que as interfaces IEnumberable/IQueryable praticamente “ganharam implementações”, o que não é possível fazer nas interfaces diretamente.
Percebo que não existe um porquê técnico ou teórico de porque algo foi feito dessa maneira e não de outra, o próprio Eric Lippert (principal desenvolvedor do compilador de C#) explica nessa resposta: http://stackoverflow.com/a/4914207/492460
Obrigado Elemar.
Felipe
30/01/2012
Elemar, lendo, surgiu-me uma dúvida. Em relação a desempenho, há alguma influência? Se sim, boa ou ruim?
Grato, um abraço.
elemarjr
30/01/2012
Grande Felipe,
Não há qualquer prejuízo de performance. Na prática, são apenas métodos estáticos, com chamadas em tempo de compilação.
Além disso, sempre haverá a possibilidade do compilador fazer “inlining” do método (para mais, veja http://elemarjr.net/2010/08/06/era-uma-vez-um-cdigo-que-executava-rpido/).
[]s
Renan Henrique
29/02/2012
Olá, bacana o post, mais um aprendizado, continue assim!