Wie erweitere ich eine Klasse mit c # -Erweiterungsmethoden?

98

Können Erweiterungsmethoden auf die Klasse angewendet werden?

Erweitern Sie DateTime beispielsweise um eine Tomorrow () -Methode, die wie folgt aufgerufen werden kann:

DateTime.Tomorrow();

Ich weiß, dass ich verwenden kann

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

Oder

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

für ein ähnliches Ergebnis, aber wie kann ich DateTime erweitern, damit ich DateTime.Tomorrow aufrufen kann?

David Glenn
quelle

Antworten:

70

Sie können einem vorhandenen Typ keine Methoden hinzufügen, es sei denn, der vorhandene Typ ist als teilweise markiert. Sie können nur Methoden hinzufügen, die anscheinend über Erweiterungsmethoden Mitglied des vorhandenen Typs sind. Da dies der Fall ist, können Sie dem Typ selbst keine statischen Methoden hinzufügen, da Erweiterungsmethoden Instanzen dieses Typs verwenden.

Nichts hindert Sie daran, Ihre eigene statische Hilfsmethode wie folgt zu erstellen:

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

Was Sie so verwenden würden:

DateTime tomorrow = DateTimeHelper.Tomorrow;
Andrew Hare
quelle
6
huh woot? es sei denn, es wurde innerhalb von 6 Monaten nach dieser und Kumus Antwort genau dort implementiert , sieht dies tatsächlich unvollständig aus!
Cregox
4
@Cawas dies nicht unvollständig ist, zeigt Andrew, wie dies mit einem statischen Helfer gemacht wird, nicht mit einer Erweiterungsmethode (da es keine Instanz gibt).
Nick N.
1
Du hast recht, Nick. Ich bevorzuge jedoch Erweiterungsmethoden! ;)
Cregox
2
Was ist mit extensionmethod.net/csharp/datetime ? IMHO, bessere Beispiele für die Minimierung der Lernkurve sind echte Anwendungen mit vollem Quellcode und guten Mustern
Kiquenet
3
Das Problem mit diesem Code ist, dass er nur mit DateTime.Now und nicht mit einem DateTime-Objekt funktioniert. Als Dienstprogramm kann es verwendet werden, um den Tag nach einem vorherigen (oder zukünftigen) Tag zu bestimmen. Ganz zu schweigen von DateTime.Now wird jedes Mal bestimmt, wenn Sie es aufrufen ...
MintGrowth
181

Verwenden Sie eine Erweiterungsmethode .

Ex:

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

Verwendung:

DateTime.Now.Tomorrow();

oder

AnyObjectOfTypeDateTime.Tomorrow();
Kumu
quelle
2
Shuggys Antwort wirft auch ein Licht auf die ähnliche Art und Weise, wie dies gelöst werden kann.
Cregox
8
Vergessen Sie nicht, ExtensionMethods zu verwenden. oben in Ihrem Dokument.
Luke Alderton
Warum kann ich DateTime.Tomorrow () nicht ausführen?
Lawphotog
Hallo lawphotog, diese Erweiterung benötigt ein Objekt, hier ist DateTime eine Struktur und kein Objekt.
Kumu
4
Wie in früheren Kommentaren erwähnt (es war mir anscheinend nicht klar genug), können Sie NICHT DateTime.Tomorrow()als Erweiterungsmethoden verwenden, die nur für INSTANZEN einer Klasse und einer Klassenstruktur funktionieren. Folgen Sie Andrews Antwort oder Shuggys Antwort , um eine statische Methode auf einer Klassenstruktur zu "erweitern" .
Alex
18

Erweiterungsmethoden sind syntaktischer Zucker, um statische Methoden, deren erster Parameter eine Instanz vom Typ T ist, so aussehen zu lassen, als wären sie eine Instanzmethode für T.

Als solches geht der Vorteil weitgehend verloren, wenn Sie "statische Erweiterungsmethoden" erstellen, da diese dazu dienen würden, den Leser des Codes noch mehr zu verwirren als eine Erweiterungsmethode (da sie vollständig qualifiziert zu sein scheinen, aber in dieser Klasse nicht definiert sind). für keinen syntaktischen Gewinn (z. B. in der Lage, Anrufe in Linq fließend zu verketten).

Da Sie die Erweiterungen ohnehin mit einer Verwendung in den Geltungsbereich bringen müssten, würde ich argumentieren, dass das Erstellen einfacher und sicherer ist:

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

Und dann verwenden Sie dies in Ihrem Code über:

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

Die Antwort kann ich am ehesten erreichen, indem ich einem System.TypeObjekt eine Erweiterungsmethode hinzufüge . Nicht schön, aber trotzdem interessant.

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

Ansonsten haben IMO Andrew und ShuggyCoUk eine bessere Implementierung.

Adrian Godong
quelle
Es gibt Probleme mit diesem Ansatz. Die Eingabe von "typeof (...)" ist nicht bequem, und mit Intellisense würden Sie Erweiterungen aller Typen sehen. Trotzdem ist es ein interessanter Ansatz, an den ich nicht gedacht hatte, +1.
Meta-Knight
@ Meta-Knight Stimmt, deshalb persönlich bevorzuge ich die Antwort des anderen. Meine Antwort hätte die der OP-Frage am nächsten kommende Syntax, aber es ist nicht der beste Weg, um dieses Problem zu lösen.
Adrian Godong
Typekann durch jeden anderen erforderlichen Typ ersetzt werden. Ich benutze es mit Fromund es funktioniert perfekt. Ich denke, diese Antwort ist allgemein, aber richtig
Katia
3

Ich würde das gleiche tun wie Kumu

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

aber nenne es wie dieses neue DateTime (). Tomorrow ();

Denke, es macht mehr Seens als DateTime.Now.Tomorrow ();

mimo
quelle
1
Und du hast die Gelegenheit verpasst, es als Kommentar zu Kumus Antwort zu schreiben! : P
Cregox
3

Sie bieten die Möglichkeit, vorhandene Typen zu erweitern, indem neue Methoden hinzugefügt werden, ohne dass Änderungen am Typ erforderlich sind. Das Aufrufen von Methoden von Objekten des erweiterten Typs innerhalb einer Anwendung unter Verwendung der Instanzmethodensyntax wird als "Erweitern" -Methoden bezeichnet. Erweiterungsmethoden sind keine Instanzmitglieder des Typs. Der wichtigste Punkt, den Sie beachten sollten, ist, dass Erweiterungsmethoden, die als statische Methoden definiert sind, nur dann im Geltungsbereich liegen, wenn der Namespace über die using-Direktive explizit in Ihren Anwendungsquellcode importiert wird. Obwohl Erweiterungsmethoden als statische Methoden definiert sind, werden sie dennoch mithilfe der Instanzsyntax aufgerufen.

Das vollständige Beispiel finden Sie hier http://www.dotnetreaders.com/articles/Extension_methods_in_C-sharp.net,Methods_in_C_-sharp/201

Beispiel:

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

Ich suchte nach etwas Ähnlichem - einer Liste von Einschränkungen für Klassen, die Erweiterungsmethoden bereitstellen. Es scheint schwierig zu sein, eine präzise Liste zu finden.

  1. Sie können nichts Privates oder Geschütztes haben - Felder, Methoden usw.

  2. Es muss eine statische Klasse sein, wie in public static class....

  3. Es können nur Methoden in der Klasse sein, und sie müssen alle öffentlich statisch sein.

  4. Sie können keine herkömmlichen statischen Methoden verwenden - solche, die dieses Argument nicht enthalten, sind nicht zulässig.

  5. Alle Methoden müssen beginnen:

    public static ReturnType MethodName (dieser Klassenname _this, ...)

Das erste Argument ist also immer diese Referenz.

Dies führt zu einem impliziten Problem: Wenn Sie Methoden hinzufügen, für die eine Sperre erforderlich ist, können Sie diese nicht wirklich auf Klassenebene bereitstellen. Normalerweise stellen Sie eine Sperre auf privater Instanzebene bereit, aber es ist nicht möglich, private Felder hinzuzufügen, sodass Sie einige sehr umständliche Optionen haben, z. B. die Bereitstellung als öffentliche Statik für eine externe Klasse usw. Wird schwierig. Zeichen die C # -Sprache hatte, hatten eine schlechte Wendung im Design für diese .

Die Problemumgehung besteht darin, Ihre Erweiterungsmethodenklasse nur als Fassade für eine reguläre Klasse zu verwenden, und alle statischen Methoden in Ihrer Erweiterungsklasse rufen nur die reale Klasse auf, wahrscheinlich unter Verwendung eines Singleton .

Chris Moschini
quelle
2

Das kannst du leider nicht. Ich glaube jedoch, dass es nützlich wäre. Es ist natürlicher zu tippen:

DateTime.Tomorrow

als:

DateTimeUtil.Tomorrow

Bei einer Util-Klasse müssen Sie überprüfen, ob eine statische Methode in zwei verschiedenen Klassen statt in einer vorhanden ist.

Meta-Knight
quelle
1

Wir haben unsere Antwort mit detaillierten Erklärungen verbessert. Jetzt ist die Erweiterungsmethode leichter zu verstehen

Erweiterungsmethode : Dies ist ein Mechanismus, mit dem wir das Verhalten vorhandener Klassen erweitern können, ohne die Unterklassifizierung zu verwenden oder die ursprüngliche Klasse oder Struktur zu ändern oder neu zu kompilieren.

Wir können unsere benutzerdefinierten Klassen, .net Framework-Klassen usw. erweitern.

Die Erweiterungsmethode ist eine spezielle statische Methode, die in der statischen Klasse definiert ist.

Da die DateTimeKlasse bereits oben belegt ist und wir diese Klasse daher nicht zur Erklärung herangezogen haben.

Unten ist das Beispiel

// Dies ist eine vorhandene Calculator-Klasse mit nur einer Methode (Add)

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
quelle