Posted by
Hugo Estevam Longo
|
|
Posted on 23:19
Com o tradicional desenvolvimento orientado a objeto, quando se deseja herdar funcionalidades de uma classe, é necessário criar uma classe que estenda a classe base. Visual Basic e C# suportam esse conceito de orientação a objeto, mas algumas vezes, podemos ter classes marcadas como "NotInheritable" ou "sealed" para previnir que sejam feitas modificações no comportamento da classe através da herança. Como resultado não podemos customizar essas classes. Um exemplo disso é a classe System.String do .Net Framework.
Uma nova feature encontrada no C# 3.0 e Visual Basic 9.0 permite que você estenda as funcionalidades de um tipo existente que não permite utilizar herança. O responsável por isso são os Extension Methods(Extensão de médotos) que tem papel crucial na implementação do LINQ.
Extension Methods provém um mecanismo simples para estender tipos do sistema(valor, referência, tipos interface) com novos métodos. Os métodos estendidos, estendem as funcionalidades de um tipo original, podendo ser chamado normalmente. Eles criam a ilusão de que eles são definidos no tipo real, mas na realidade, não há alteração no tipo original.
Isto não é um conceito padrão de orientação a objeto, isto é uma feature do .Net Framework, que gera um código no Intermediate Language(IL) através do compilador gerando uma chamada compartilhada a um método.
O código abaixo mostra os Extension Methods "AlternateCase" e "
IsValidEmailAddress" que estendem a classe System.String que é marcada como "NotInheritable" ou "sealed". O primeiro método retorna uma string com seus caracteres minúsculos e maiúsculos alternadamente. Já o segundo método retorna um valor booleano que resulta da validação de um e-mail.
'VB.NET
Imports System.Runtime.CompilerServices
Imports System.Text.RegularExpressions
Module Module1
Sub Main()
Dim mail As String = "test@test.com"
'Chama método AlternateCase como uma extensão da variável mail
Console.WriteLine("mail.AlternateCase: " & mail.AlternateCase)
'Chama o método sem ser uma extensão da variável
Console.WriteLine("Extensions.AlternateCase(mail): " &
Extensions.AlternateCase(mail))
'Chama método IsValidEmailAddress como uma extensão da variável mail
Console.WriteLine("mail.IsValidEmailAddress(): " & mail.IsValidEmailAddress)
'Chama o método sem ser uma extensão da variável
Console.WriteLine("Extensions.IsValidEmailAddress(mail): " &
Extensions.IsValidEmailAddress(mail))
'Espera ação do usuário
Console.Read()
End Sub
End Module
Module Extensions
<Extension()>_
Function AlternateCase(ByVal x As String) As String
Dim b = False
Dim SB As New System.Text.StringBuilder
For Each c In x
If b Then
SB.Append(Char.ToUpper(c))
Else
SB.Append(Char.ToLower(c))
End If
b = Not b
Next
Return SB.ToString
End Function
<Extension()>_
Function IsValidEmailAddress(ByVal x As String)As Boolean
Dim regex As Regex = New Regex("^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$")
Return regex.IsMatch(x)
End Function
End Module
Note que no Visual Basic é necessário importar o namespace System.RunTime.CompilerServices e utilizar o Annotation "Extension()" em cima do método desejado.
//C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.CompilerServices;
using System.Text.RegularExpressions;
namespace ExtensionCSharp
{
class Program
{
static void Main(string[] args)
{
String mail = "test@test.com";
//Chama método AlternateCase como uma extensão da variável mail
Console.WriteLine("mail.AlternateCase(): " + mail.AlternateCase());
//Chama o método sem ser uma extensão da variável
Console.WriteLine("Extensions.AlternateCase(mail): " + Extensions.AlternateCase(mail));
//Chama método IsValidEmailAddress como uma extensão da variável mail
Console.WriteLine("mail.IsValidEmailAddress(): " + mail.IsValidEmailAddress());
//Chama o método sem ser uma extensão da variável
Console.WriteLine("Extensions.IsValidEmailAddress(mail): " + Extensions.IsValidEmailAddress(mail));
//Espera ação do usuário
Console.Read();
}
}
public static class Extensions
{
public static String AlternateCase(this String x)
{
Boolean b = false;
StringBuilder SB = new StringBuilder();
foreach(Char c in x)
{
if (b)
SB.Append(Char.ToUpper(c));
else
SB.Append(Char.ToLower(c));
b = !b;
}
return SB.ToString();
}
public static bool IsValidEmailAddress(this String x)
{
Regex regex = new Regex(@"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$");
return regex.IsMatch(x);
}
}
}
Note que em C# também se faz necessário importar o namespace System.RunTime.CompilerServices contido no assemblie System.Core.dll. Porém em C# para identificar o método como um Extension Methods não precisa utilizar Annotations, basta utilizar a palavra reservada "this" na declaração do parâmetro no método, como mostra o código acima.
Após o Extension Method ser criado, ele já fica associado a classe que ele estendeu, neste exemplo a classe System.String foi estendida, e o método pode ser visualizado através do IntelliSense do Visual Studio como mostra a figura abaixo:
Você irá ver que os Extension Methods aparecem com um ícone diferente(flecha azul apontando para baixo) para diferenciá-los dos métodos instanciados pela classe.
As vantagens em usar Extension Methods é que ele permite adicionar funcionalidades para o tipo que você deseja customizar sem que você quebre o código de aplicações já existentes. Você pode estender interfaces padrões com métodos adicionais sem alterar fisicamente a biblioteca de classes existentes.
No próximo post, pretendo mostrar outras vantagens de utilizar Extension Methods e também mostrar um macete para utilizá-lo em projetos com o .Net Framework 2.0
Para baixar a solução completa deste exemplo clique aqui (VS2008).
Até a próxima...