Come estendo una classe con metodi di estensione c #?


98

È possibile applicare metodi di estensione alla classe?

Ad esempio, estendi DateTime per includere un metodo Tomorrow () che potrebbe essere richiamato come:

DateTime.Tomorrow();

So che posso usare

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

O

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

per un risultato simile, ma come posso estendere DateTime in modo da poter richiamare DateTime.Tomorrow?

Risposte:


70

Non è possibile aggiungere metodi a un tipo esistente a meno che il tipo esistente non sia contrassegnato come parziale, è possibile aggiungere solo metodi che sembrano essere un membro del tipo esistente tramite metodi di estensione. Poiché questo è il caso, non è possibile aggiungere metodi statici al tipo stesso poiché i metodi di estensione utilizzano istanze di quel tipo.

Non c'è nulla che ti impedisca di creare il tuo metodo di supporto statico come questo:

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

Quale useresti in questo modo:

DateTime tomorrow = DateTimeHelper.Tomorrow;

6
eh woot? a meno che non sia stato implementato entro 6 mesi da questo e la risposta di Kumu proprio lì, questo sembra effettivamente incompleto!
cregox

4
@Cawas questo non è incompleto, Andrew sta mostrando come farlo con un helper statico, non con un metodo di estensione (poiché non ci sono istanze).
Nick N.

1
Hai ragione Nick. Preferisco però i metodi di estensione! ;)
cregox

2
Che mi dici di extensionmethod.net/csharp/datetime ? IMHO, esempi migliori per ridurre al minimo la curva di apprendimento sono applicazioni reali con codice sorgente completo e buoni modelli
Kiquenet

3
Il problema con questo codice è che funziona solo su DateTime.Now e non su qualsiasi oggetto DateTime. Come utilità, è possibile utilizzarlo per determinare il giorno dopo un giorno precedente (o futuro). Per non parlare di DateTime.Now è determinato ogni volta che lo chiami ...
MintGrowth

181

Usa un metodo di estensione .

Ex:

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

Utilizzo:

DateTime.Now.Tomorrow();

o

AnyObjectOfTypeDateTime.Tomorrow();

2
La risposta di Shuggy ha anche fatto luce su un modo simile per risolvere questo problema.
cregox

8
Non dimenticare "using ExtensionMethods;" nella parte superiore del documento per questo.
Luke Alderton

perché non posso fare DateTime.Tomorrow ()?
lawphotog

Ciao lawphotog, questa estensione ha bisogno di un oggetto, qui DateTime è una struttura e non un oggetto.
Kumu

4
Come accennato nei commenti precedenti (a quanto pare non era abbastanza chiaro per me), NON sarai in grado di utilizzare DateTime.Tomorrow()come metodi di estensione funzionano solo su ISTANZE di una classe e una struttura di classe. Per "estendere" un metodo statico su una struttura di classe, segui la risposta di Andrew o la risposta di Shuggy .
Alex

18

I metodi di estensione sono zucchero sintattico per fare in modo che i metodi statici il cui primo parametro è un'istanza di tipo T sembrino un metodo di istanza su T.

In quanto tale, il vantaggio è in gran parte perso se si creano `` metodi di estensione statici '' poiché servirebbero a confondere il lettore del codice anche più di un metodo di estensione (poiché sembrano essere pienamente qualificati ma non sono effettivamente definiti in quella classe) per nessun guadagno sintattico (ad esempio essere in grado di concatenare chiamate in uno stile fluente all'interno di Linq).

Dal momento che dovresti comunque portare le estensioni nell'ambito di un utilizzo, direi che è più semplice e sicuro creare:

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

E poi usalo nel tuo codice tramite:

WriteLine("{0}", DateTimeUtils.Tomorrow)

11

Il più vicino possibile alla risposta è l'aggiunta di un metodo di estensione in un System.Typeoggetto. Non carino, ma comunque 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();
        }
    }
}

Altrimenti, IMO Andrew e ShuggyCoUk ha un'implementazione migliore.


Ci sono problemi con questo approccio. Dover digitare "typeof (...)" non è conveniente, e con intellisense vedresti estensioni di ogni tipo. Tuttavia, è un approccio interessante a cui non avevo pensato, +1.
Meta-Knight

@ Meta-Knight Vero, ecco perché personalmente preferisco la risposta dell'altro. La mia risposta avrebbe la sintassi più vicina alla domanda OP, ma non è il modo migliore per risolvere questo problema.
Adrian Godong,

Typepuò essere sostituito con qualsiasi altro tipo richiesto. Lo uso con Frome funziona perfettamente. quindi immagino che questa risposta sia generale ma corretta
Katia

3

Farei lo stesso di Kumu

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

ma chiamalo come questo nuovo DateTime (). Tomorrow ();

Penso che faccia più visualizzazioni di DateTime.Now.Tomorrow ();


1
E ti sei perso l'occasione di scriverlo come commento alla risposta di Kumu! : P
cregox

3

Forniscono la capacità di estendere i tipi esistenti aggiungendo nuovi metodi senza modifiche necessarie al tipo. La chiamata di metodi da oggetti di tipo esteso all'interno di un'applicazione utilizzando la sintassi del metodo di istanza è nota come metodi di "estensione". I metodi di estensione non sono membri di istanza del tipo. Il punto chiave da ricordare è che i metodi di estensione, definiti come metodi statici, rientrano nell'ambito solo quando lo spazio dei nomi viene importato esplicitamente nel codice sorgente dell'applicazione tramite la direttiva using. Anche se i metodi di estensione sono definiti come metodi statici, vengono comunque chiamati utilizzando la sintassi dell'istanza.

Controlla l'esempio completo qui http://www.dotnetreaders.com/articles/Extension_methods_in_C-sharp.net,Methods_in_C_-sharp/201

Esempio:

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

3

Stavo cercando qualcosa di simile: un elenco di vincoli sulle classi che forniscono metodi di estensione. Sembra difficile trovare un elenco conciso, quindi ecco qui:

  1. Non puoi avere nulla di privato o protetto: campi, metodi, ecc.

  2. Deve essere una classe statica, come in public static class....

  3. Solo i metodi possono essere nella classe e devono essere tutti statici pubblici.

  4. Non puoi avere metodi statici convenzionali: quelli che non includono questo argomento non sono consentiti.

  5. Tutti i metodi devono iniziare:

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

Quindi il primo argomento è sempre il riferimento this.

C'è un problema implicito che questo crea: se aggiungi metodi che richiedono un blocco di qualsiasi tipo, non puoi davvero fornirlo a livello di classe. Tipicamente forniresti un blocco privato a livello di istanza, ma non è possibile aggiungere alcun campo privato, lasciandoti con alcune opzioni molto scomode, come fornirlo come statico pubblico su qualche classe esterna, ecc. Segni che il linguaggio C # ha avuto una svolta negativa nella progettazione per questi .

La soluzione alternativa consiste nell'usare la classe del metodo di estensione come semplice facciata di una classe normale e tutti i metodi statici nella classe di estensione chiamano semplicemente la classe reale, probabilmente utilizzando un Singleton .


2

Sfortunatamente, non puoi farlo. Credo che sarebbe utile, però. È più naturale digitare:

DateTime.Tomorrow

di:

DateTimeUtil.Tomorrow

Con una classe Util, devi verificare l'esistenza di un metodo statico in due classi diverse, invece di una.


1

Abbiamo migliorato la nostra risposta con spiegazioni dettagliate, ora è più facile capire il metodo di estensione

Metodo di estensione : è un meccanismo attraverso il quale possiamo estendere il comportamento della classe esistente senza utilizzare la sottoclasse o modificare o ricompilare la classe o la struttura originale.

Possiamo estendere le nostre classi personalizzate, classi .net framework ecc.

Il metodo di estensione è in realtà un tipo speciale di metodo statico definito nella classe statica.

Poiché la DateTimeclasse è già stata presa sopra e quindi non abbiamo preso questa classe per la spiegazione.

Di seguito è riportato l'esempio

// Questa è una classe Calculator esistente che ha un solo metodo (Aggiungi)

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)

    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.