¿Cómo extiendo una clase con métodos de extensión c #?

98

¿Se pueden aplicar métodos de extensión a la clase?

Por ejemplo, extienda DateTime para incluir un método Tomorrow () que podría invocarse como:

DateTime.Tomorrow();

Se que puedo usar

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

O

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

para obtener un resultado similar, pero ¿cómo puedo extender DateTime para poder invocar DateTime.Tomorrow?

David Glenn
fuente

Respuestas:

70

No puede agregar métodos a un tipo existente a menos que el tipo existente esté marcado como parcial, solo puede agregar métodos que parecen ser miembros del tipo existente a través de métodos de extensión. Dado que este es el caso, no puede agregar métodos estáticos al tipo en sí, ya que los métodos de extensión usan instancias de ese tipo.

No hay nada que le impida crear su propio método auxiliar estático como este:

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

Que usarías así:

DateTime tomorrow = DateTimeHelper.Tomorrow;
Andrew Hare
fuente
6
eh woot? a menos que se implementó dentro de los 6 meses posteriores a esto y la respuesta de Kumu allí mismo, ¡esto parece realmente incompleto!
cregox
4
@Cawas esto no está incompleto, Andrew está mostrando cómo hacer esto con un ayudante estático, no con un método de extensión (ya que no hay una instancia).
Nick N.
1
Tienes razón, Nick. ¡Sin embargo, prefiero los métodos de extensión! ;)
cregox
2
¿Qué pasa con extensionmethod.net/csharp/datetime ? En mi humilde opinión, las mejores muestras para minimizar la curva de aprendizaje son aplicaciones reales con código fuente completo y buenos patrones
Kiquenet
3
El problema con este código es que solo funciona en DateTime.Now y no en ningún objeto DateTime. Como utilidad, es posible que desee utilizarlo para determinar el día después de algún día anterior (o futuro). Sin mencionar DateTime.Now se determina cada vez que lo llamas ...
MintGrowth
181

Utilice un método de extensión .

Ex:

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

Uso:

DateTime.Now.Tomorrow();

o

AnyObjectOfTypeDateTime.Tomorrow();
Kumu
fuente
2
La respuesta de Shuggy también arrojó algo de luz sobre una forma similar de resolver esto.
Cregox
8
No olvide 'utilizar ExtensionMethods;' en la parte superior de su documento para esto.
Luke Alderton
¿Por qué no puedo hacer DateTime.Tomorrow ()?
lawphotog
Hola lawphotog, esta extensión necesita un objeto, aquí DateTime es una estructura y no un objeto.
Kumu
4
Como se mencionó en comentarios anteriores (aparentemente no fue lo suficientemente claro para mí), NO podrá usar DateTime.Tomorrow()como métodos de extensión que solo funcionen en INSTANCIAS de una clase y una estructura de clase. Para "extender" un método estático en una estructura de clase, siga la respuesta de Andrew o la respuesta de Shuggy .
Alex
18

Los métodos de extensión son azúcar sintáctico para hacer que los métodos estáticos cuyo primer parámetro es una instancia de tipo T parezcan un método de instancia en T.

Como tal, el beneficio se pierde en gran medida cuando crea 'métodos de extensión estáticos', ya que servirían para confundir al lector del código incluso más que un método de extensión (ya que parecen estar completamente calificados pero en realidad no están definidos en esa clase) sin ganancia sintáctica (por ejemplo, poder encadenar llamadas en un estilo fluido dentro de Linq).

Dado que tendría que llevar las extensiones al alcance con un uso de todos modos, diría que es más simple y seguro crear:

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

Y luego use esto en su código a través de:

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

Lo más cerca que puedo llegar a la respuesta es agregando un método de extensión en un System.Typeobjeto. No es bonito, pero sigue siendo interesante.

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

De lo contrario, la OMI Andrew y ShuggyCoUk tiene una mejor implementación.

Adrian Godong
fuente
Hay problemas con este enfoque. Tener que escribir "typeof (...)" no es conveniente, y con intellisense verías extensiones de todo tipo. Aún así, es un enfoque interesante en el que no había pensado, +1.
Meta-Knight
@ Meta-Knight Cierto, por eso personalmente prefiero la respuesta del otro. Mi respuesta tendría la sintaxis más cercana a la pregunta de OP, pero no es la mejor manera de resolver este problema.
Adrian Godong
Typepuede ser reemplazado por cualquier otro tipo requerido. Lo uso con Fromy funciona perfectamente. así que supongo que esta respuesta es general pero correcta
Katia
3

Yo haría lo mismo que kumu

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

pero llámalo así nuevo DateTime (). Tomorrow ();

Creo que hace más vistas que DateTime.Now.Tomorrow ();

mimo
fuente
1
¡Y perdiste la oportunidad de escribirlo como comentario sobre la respuesta de Kumu! : P
cregox
3

Proporcionan la capacidad de ampliar los tipos existentes mediante la adición de nuevos métodos sin modificaciones necesarias al tipo. Llamar a métodos desde objetos de tipo extendido dentro de una aplicación utilizando la sintaxis de método de instancia se conoce como métodos de "extensión". Los métodos de extensión no son miembros de instancia en el tipo. El punto clave para recordar es que los métodos de extensión, definidos como métodos estáticos, están dentro del alcance solo cuando el espacio de nombres se importa explícitamente en el código fuente de su aplicación a través de la directiva using. Aunque los métodos de extensión se definen como métodos estáticos, todavía se llaman utilizando la sintaxis de instancia.

Consulte el ejemplo completo aquí http://www.dotnetreaders.com/articles/Extension_methods_in_C-sharp.net,Methods_in_C_-sharp/201

Ejemplo:

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
fuente
3

Estaba buscando algo similar: una lista de restricciones en las clases que proporcionan métodos de extensión. Parece difícil encontrar una lista concisa, así que aquí va:

  1. No puede tener nada privado o protegido: campos, métodos, etc.

  2. Debe ser una clase estática, como en public static class....

  3. Solo los métodos pueden estar en la clase y todos deben ser estáticos públicos.

  4. No puede tener métodos estáticos convencionales, los que no incluyen este argumento no están permitidos.

  5. Todos los métodos deben comenzar:

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

Entonces, el primer argumento es siempre la referencia this.

Existe un problema implícito que esto crea: si agrega métodos que requieren un bloqueo de cualquier tipo, realmente no puede proporcionarlo a nivel de clase. Normalmente, proporcionaría un bloqueo privado a nivel de instancia, pero no es posible agregar ningún campo privado, lo que le deja con algunas opciones muy incómodas, como proporcionarlo como una estática pública en alguna clase externa, etc. Se vuelve arriesgado. Signos que el lenguaje C # tuvo un mal giro en el diseño de estos .

La solución es usar su clase de método de extensión como solo una fachada a una clase normal, y todos los métodos estáticos en su clase de extensión simplemente llaman a la clase real, probablemente usando un Singleton .

Chris Moschini
fuente
2

Desafortunadamente, no puedes hacer eso. Sin embargo, creo que sería útil. Es más natural escribir:

DateTime.Tomorrow

que:

DateTimeUtil.Tomorrow

Con una clase Util, debe verificar la existencia de un método estático en dos clases diferentes, en lugar de una.

Caballero meta
fuente
1

Hemos mejorado nuestra respuesta con una explicación detallada. Ahora es más fácil de entender sobre el método de extensión

Método de extensión : Es un mecanismo a través del cual podemos extender el comportamiento de la clase existente sin usar la subclasificación o modificar o recompilar la clase o estructura original.

Podemos ampliar nuestras clases personalizadas, clases de framework .net, etc.

El método de extensión es en realidad un tipo especial de método estático que se define en la clase estática.

Como la DateTimeclase ya se tomó arriba y, por lo tanto, no hemos tomado esta clase para la explicación.

A continuación se muestra el ejemplo

// Esta es una clase Calculadora existente que solo tiene un método (Agregar)

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
fuente