C# - Métodos de Extensão (revisitado)


 Neste artigo vou apresentar os métodos de extensão e mostrar como podemos criar métodos de extensão na linguagem C#.

Eu já falei sobre os métodos de extensão para a linguagem VB .NET mas como os conceitos são idênticos vou repetir a introdução feita no artigo.

Os métodos de extensão ou extensions methods são uma implementação do padrão de projeto estrutural Composite e permitem que você adicione uma nova funcionalidade a um tipo de dado que já foi definido sem ter que criar um novo tipo derivado; dessa forma a funcionalidade se comporta como um outro membro do tipo.

Essa é uma forma de aplicar o padrão aberto/fechado que diz : 'Você deve ser capaz de estender um comportamento de uma classe, sem modificá-la.'

Através da aplicação dos métodos de extensão você pode, por exemplo, incluir funcionalidades adicionais a uma string sem ter que herdar da classe String, e, o novo comportamento é tratado como um novo membro. Dessa forma, usando este recurso, é possível escrever um método que pode ser chamado como se ele fosse um método de instância de um tipo existente.

Os métodos de extensão foram introduzidos na versão 3.0 da linguagem C# para dar suporte ao LINQ; logo é de se esperar que a LINQ usa e abusa dos métodos de extensão.

Os métodos de extensão são definidos como estáticos, mas são chamados usando a sintaxe do método de instância. Seu primeiro parâmetro especifica em que tipo o método opera e o parâmetro é precedido pelo modificador this. Os métodos de extensão só estarão no escopo quando você importar explicitamente o namespace para seu código-fonte com uma diretiva using.

Para implementar um método de extensão na linguagem C# basta seguir o roteiro:

  1. Defina uma classe estática para conter o método de extensão. Esta classe deve estar visível para o código cliente.
  2. Implemente o método de extensão como um método estático com pelo menos a mesma visibilidade que a classe que a contém;
  3. O primeiro parâmetro do método especifica o tipo no qual o método opera. Ele deve ser precedido pelo modificador this.
  4. No código de chamada, adicione uma diretiva using para especificar o namespace que contém a classe do método de extensão.
  5. Chame os métodos como se fossem métodos de instância no tipo.

Vejamos então como implementar na prática e chamar um método de extensão na linguagem C#.

Recursos usados:

Criando o projeto no VS 2017 Community

Abra o VS 2017 Community e crie um novo projeto do tipo Console App com o nome CSharp_Extensions:

Ao criar métodos de extensão geralmente você vai querer colocar o seu código em um arquivo separado.

Vamos então criar um classe no projeto chamada MetodosExtensao onde vamos criar os métodos de extensão.

A seguir vamos criar 3 métodos de extensão :

  1. CaixaAltaPrimeiraLetra(this string valor) - Põe a primeira letra da string em caixa alta;
  2. ContaPalavras(this string texto) - Conta quantas palavras tem na string;
  3. EMaiorQue(this int i, int valor) - Verifica se um inteiro é maior que outro inteiro. Aqui usamos dois parâmetros.

A seguir inclua na classe MetodosExtensao o código abaixo:

using System;
namespace CSharp_ExtensionsMethods
{
    public static class MetodosExtensao
    {
        public static string CaixaAltaPrimeiraLetra(this string valor)
        {
            // Põe a primeira letra em caixa alta
            if (valor.Length > 0)
            {
                char[] array = value.ToCharArray();
                array[0] = char.ToUpper(array[0]);
                return new string(array);
            }
            return valor;
        }
        public static int ContaPalavras(this String texto)
        {
            //conta quantas palavras exite na string
            return texto.Split(new char[] { ' ', '.', '?' }, StringSplitOptions.RemoveEmptyEntries).Length;
        }
        //método com dois parâmetros
        //como o método vai operar sobre inteiros 
        //o primeiro parametro deve ser um int
        public static bool EMaiorQue(this int i, int valor)
        {
            return i > valor;
        }
    }
}  

O código é bem simples e cabe ressaltar que a classe e os métodos são estáticos e o primeiro parâmetro usa a palavra reservada this.

Para usar basta incluir o código abaixo no método Main da classe Program:

using static System.Console;
namespace CSharp_ExtensionsMethods
{
    class Program
    {
        static void Main(string[] args)
        {
            string texto = "macoratti .net, quase tudo para a plataforma .NET";
            //  note que o primeiro parâmetro não especificado na chamada
            int numeroPalavras = texto.ContaPalavras();
            WriteLine($"O texto possui {numeroPalavras} palavras");
            //método de extensão CaixaAltaPrimeiraLetra
            texto = texto.CaixaAltaPrimeiraLetra();
            WriteLine(texto);
            //método de extensão EMaiorQue
            int numero = 10;
            bool resultado = numero.EMaiorQue(21);
            WriteLine($"O numero {numero} é maior que 21 ? " + resultado);
            ReadKey();
        }
    }
}

Executando o projeto teremos o resultado :

Agora, vamos supor que você tem uma classe chamada CalculaPreco que tem um método que retorna o PrecoTotal de um produto.

Abaixo temos o código da classe:

public class CalculaPreco  
{  
   public int PrecoTotal(int quantidade, int Custo)  
      {  
         return quantidade * Custo ;  
      }  
} 

Vamos supor que você precisa implementar um desconto no cálculo do preço total. Como você faria isso ????

Uma forma elegante de fazer isso é criar um método de extensão na classe CalculaPreco. Assim você respeita o princípio Open/Closed.

Veja como deve ficar a implementação do método de extensão:

     public static class CalculaPrecoComDesconto
    {
        public static int PrecoFinalComDesconto(this CalculaPreco obj, int quantidade, int custo, int desconto )
        {
            // calcula o preco com desconto
            return (quantidade * custo) - desconto;
        }
    }

Para testar a implementação podemos fazer assim:

using static System.Console;
namespace CSharp_ExtensionsMethods
{
    class Program
    {
        static void Main(string[] args)
        {
            WriteLine("Quantidade = 4, Preço =  1000,  Desconto = 50");
            CalculaPreco valor = new CalculaPreco();
            int precoSemDesconto = valor.PrecoTotal(4, 1000);
            int precoComDesconto = valor.PrecoFinalComDesconto(4, 1000, 50);
            WriteLine($"Preço sem desconto       : {precoSemDesconto}");
            WriteLine($"Preco com desconto de 50 : {precoComDesconto}");
            ReadKey();
        }
    }
}

Pontos importantes que você deve considerar ao usar os métodos de extensão:

E estamos conversados...

"Jesus lhes respondeu, e disse: A minha doutrina não é minha, mas daquele que me enviou.
Se alguém quiser fazer a vontade dele, pela mesma doutrina conhecerá se ela é de Deus, ou se eu falo de mim mesmo."
João 7:16,17

Referências:


José Carlos Macoratti