Como faço para estender uma classe com métodos de extensão c #?

98

Os métodos de extensão podem ser aplicados à classe?

Por exemplo, estenda DateTime para incluir um método Tomorrow () que poderia ser invocado como:

DateTime.Tomorrow();

Eu sei que posso usar

static DateTime Tomorrow(this Datetime value) { //... }

Ou

public static MyClass {
  public static Tomorrow() { //... }
}

para um resultado semelhante, mas como posso estender DateTime para poder invocar DateTime.Tomorrow?

David Glenn
fonte

Respostas:

70

Você não pode adicionar métodos a um tipo existente, a menos que o tipo existente seja marcado como parcial; você só pode adicionar métodos que parecem ser membros do tipo existente por meio de métodos de extensão. Como esse é o caso, você não pode adicionar métodos estáticos ao próprio tipo, pois os métodos de extensão usam instâncias desse tipo.

Não há nada que impeça você de criar seu próprio método auxiliar estático como este:

static class DateTimeHelper
{
    public static DateTime Tomorrow
    {
        get { return DateTime.Now.AddDays(1); }
    }
}

Que você usaria assim:

DateTime tomorrow = DateTimeHelper.Tomorrow;
Andrew Hare
fonte
6
huh woot? a menos que tenha sido implementado 6 meses após isso e a resposta de Kumu ali, isso parece realmente incompleto!
cregox de
4
@Caw como isso não está incompleto, Andrew está mostrando como fazer isso com um auxiliar estático, não com um método de extensão (já que não há instância).
Nick N.
1
Você está certo, Nick. Eu prefiro métodos de extensão embora! ;)
cregox
2
E sobre extensionmethod.net/csharp/datetime ? IMHO, melhores exemplos para minimizar a curva de aprendizado são aplicativos reais com código-fonte completo e bons padrões
Kiquenet
3
O problema com esse código é que ele funciona apenas em DateTime.Now e não em qualquer objeto DateTime. Como um utilitário, pode-se querer usá-lo para determinar o dia seguinte a algum dia anterior (ou futuro). Sem mencionar DateTime.Now é determinado cada vez que você chamá-lo ...
MintGrowth de
181

Use um método de extensão .

Ex:

namespace ExtensionMethods
{
    public static class MyExtensionMethods
    {
        public static DateTime Tomorrow(this DateTime date)
        {
            return date.AddDays(1);
        }    
    }
}

Uso:

DateTime.Now.Tomorrow();

ou

AnyObjectOfTypeDateTime.Tomorrow();
Kumu
fonte
2
A resposta de Shuggy também lançou alguma luz sobre uma maneira semelhante de resolver isso.
cregox de
8
Não se esqueça de 'using ExtensionMethods;' na parte superior do seu documento para isso.
Luke Alderton
por que não posso fazer DateTime.Tomorrow ()?
lawphotog
Oi lawphotog, esta extensão precisa de um objeto, aqui DateTime é uma estrutura e não um objeto.
Kumu
4
Como mencionado nos comentários anteriores (não ficou claro o suficiente para mim aparentemente), você NÃO poderá usar DateTime.Tomorrow()como métodos de extensão funcionam apenas em INSTÂNCIAS de uma classe e em uma estrutura de classe. Para "estender" um método estático em uma estrutura de classe, siga a resposta de Andrew ou a resposta de Shuggy .
Alex
18

Os métodos de extensão são açúcares sintáticos para fazer métodos estáticos cujo primeiro parâmetro é uma instância do tipo T pareçam ser um método de instância em T.

Como tal, o benefício é amplamente perdido quando você faz 'métodos de extensão estáticos', pois eles serviriam para confundir o leitor do código ainda mais do que um método de extensão (uma vez que eles parecem ser totalmente qualificados, mas não são realmente definidos nessa classe) para nenhum ganho sintático (ser capaz de encadear chamadas em um estilo fluente no Linq, por exemplo).

Já que você teria que trazer as extensões para o escopo com um uso de qualquer maneira, eu diria que é mais simples e seguro criar:

public static class DateTimeUtils
{
    public static DateTime Tomorrow { get { ... } }
}

E use isso em seu código por meio de:

WriteLine("{0}", DateTimeUtils.Tomorrow)
ShuggyCoUk
fonte
11

O mais próximo que posso chegar da resposta é adicionando um método de extensão a um System.Typeobjeto. Não é bonito, mas ainda assim interessante.

public static class Foo
{
    public static void Bar()
    {
        var now = DateTime.Now;
        var tomorrow = typeof(DateTime).Tomorrow();
    }

    public static DateTime Tomorrow(this System.Type type)
    {
        if (type == typeof(DateTime)) {
            return DateTime.Now.AddDays(1);
        } else {
            throw new InvalidOperationException();
        }
    }
}

Caso contrário, IMO Andrew e ShuggyCoUk tem uma implementação melhor.

Adrian Godong
fonte
Existem problemas com esta abordagem. Ter que digitar "typeof (...)" não é conveniente, e com o intellisense você veria extensões de todo tipo. Ainda assim, é uma abordagem interessante que eu não tinha pensado, +1.
Meta-Knight
@ Meta-Knight True, é por isso que pessoalmente prefiro a resposta do outro. Minha resposta teria a sintaxe mais próxima da pergunta do OP, mas não é a melhor maneira de resolver esse problema.
Adrian Godong
Typepode ser substituído por qualquer outro tipo necessário. Eu uso com Fromele e funciona perfeitamente. então acho que essa resposta é geral, mas correta
Katia,
3

Eu faria o mesmo que Kumu

namespace ExtensionMethods
{
    public static class MyExtensionMethods
    {
        public static DateTime Tomorrow(this DateTime date)
        {
           return date.AddDays(1);
        }    
    }
}

mas chame-o assim novo DateTime (). Tomorrow ();

Acho que faz mais seens do que DateTime.Now.Tomorrow ();

mimo
fonte
1
E você perdeu a chance de escrever um comentário sobre a resposta de Kumu! : P
cregox de
3

Eles fornecem a capacidade de estender tipos existentes, adicionando novos métodos sem modificações necessárias para o tipo. Chamar métodos de objetos do tipo estendido em um aplicativo usando a sintaxe de método de instância é conhecido como métodos de '' extensão ''. Os métodos de extensão não são membros de instância no tipo. O ponto principal a ser lembrado é que os métodos de extensão, definidos como métodos estáticos, estão no escopo apenas quando o namespace é importado explicitamente para o código-fonte do aplicativo por meio da diretiva using. Mesmo que os métodos de extensão sejam definidos como métodos estáticos, eles ainda são chamados usando a sintaxe de instância.

Verifique o exemplo completo aqui http://www.dotnetreaders.com/articles/Extension_methods_in_C-sharp.net,Methods_in_C_-sharp/201

Exemplo:

class Extension
    {
        static void Main(string[] args)
        {
            string s = "sudhakar";
            Console.WriteLine(s.GetWordCount());
            Console.ReadLine();
        }

    }
    public static class MyMathExtension
    {

        public static int GetWordCount(this System.String mystring)
        {
            return mystring.Length;
        }
    }
Sudhakar
fonte
3

Eu estava procurando por algo semelhante - uma lista de restrições em classes que fornecem Métodos de Extensão. Parece difícil encontrar uma lista concisa, então aqui vai:

  1. Você não pode ter nada privado ou protegido - campos, métodos, etc.

  2. Deve ser uma classe estática, como em public static class....

  3. Apenas métodos podem estar na classe e todos devem ser public static.

  4. Você não pode ter métodos estáticos convencionais - aqueles que não incluem este argumento não são permitidos.

  5. Todos os métodos devem começar:

    public static ReturnType MethodName (this ClassName _this, ...)

Portanto, o primeiro argumento é sempre a referência this.

Isso cria um problema implícito - se você adicionar métodos que exigem um bloqueio de qualquer tipo, não poderá realmente fornecê-lo no nível da classe. Normalmente, você forneceria um bloqueio de nível de instância privado, mas não é possível adicionar nenhum campo privado, deixando você com algumas opções muito estranhas, como fornecê-lo como um estático público em alguma classe externa, etc. Torna-se perigoso. Sinais de que a linguagem C # teve uma espécie de má evolução no design desses .

A solução alternativa é usar sua classe Extension Method apenas como uma fachada para uma classe regular, e todos os métodos estáticos em sua classe Extension apenas chamam a classe real, provavelmente usando um Singleton .

Chris Moschini
fonte
2

Infelizmente, você não pode fazer isso. Eu acredito que seria útil, no entanto. É mais natural digitar:

DateTime.Tomorrow

do que:

DateTimeUtil.Tomorrow

Com uma classe Util, você deve verificar a existência de um método estático em duas classes diferentes, ao invés de uma.

Meta-Knight
fonte
1

Melhoramos nossa resposta com uma explicação detalhada. Agora é mais fácil entender sobre o método de extensão

Método de extensão : É um mecanismo pelo qual podemos estender o comportamento da classe existente sem usar a subclasse ou modificar ou recompilar a classe ou estrutura original.

Podemos estender nossas classes personalizadas, classes de estrutura .net etc.

O método de extensão é, na verdade, um tipo especial de método estático definido na classe estática.

Como a DateTimeclasse já foi feita acima e, portanto, não usamos esta classe para a explicação.

Abaixo está o exemplo

// Esta é uma classe Calculadora existente que tem apenas um método (Adicionar)

public class Calculator 
{
    public double Add(double num1, double num2)
    {
        return num1 + num2;
    }

}

// Below is the extension class which have one extension method.  
public static class Extension
{
    // It is extension method and it's first parameter is a calculator class.It's behavior is going to extend. 
    public static double Division(this Calculator cal, double num1,double num2){
       return num1 / num2;
    }   
}

// We have tested the extension method below.        
class Program
{
    static void Main(string[] args)
    {
        Calculator cal = new Calculator();
        double add=cal.Add(10, 10);
        // It is a extension method in Calculator class.
        double add=cal.Division(100, 10)

    }
}
Sheo Dayal Singh
fonte