Welche Vorteile von Verlängerungsmethoden haben Sie gefunden? [geschlossen]


84

Ein "Ungläubiger" von C # fragte mich, was der Zweck von Erweiterungsmethoden sei. Ich erklärte, dass Sie dann bereits definierten Objekten neue Methoden hinzufügen können, insbesondere wenn Sie die Quelle des ursprünglichen Objekts nicht besitzen / steuern.

Er sprach: "Warum nicht einfach eine Methode zu deiner eigenen Klasse hinzufügen?" Wir sind herumgegangen (auf eine gute Art und Weise). Meine allgemeine Antwort ist, dass es ein weiteres Werkzeug im Werkzeuggürtel ist, und seine Antwort ist, dass es eine nutzlose Verschwendung eines Werkzeugs ist ... aber ich dachte, ich würde eine "aufgeklärtere" Antwort bekommen.

In welchen Szenarien haben Sie Erweiterungsmethoden verwendet, für die Sie keine Methode hätten verwenden können (oder sollten), die Ihrer eigenen Klasse hinzugefügt wurde?


2
Ich denke, es gibt definitiv gültige Punkte, die Leute zur Unterstützung von Erweiterungsmethoden machen können (und gemacht haben) ... aber es gibt definitiv kein Szenario, in dem man statische Methoden anstelle von Erweiterungsmethoden " nicht hätte verwenden können". Erweiterungsmethoden wirklich sind nur statische Methoden, eine andere Art und Weise zugegriffen. Nur etwas zu beachten.
Dan Tao

@DanTao, etwas leichter gesagt, das einzige, was den Aufruf durch die Erweiterungsmethode unersetzlich macht, ist ihre Namensgebung. Extensions.To(1, 10)ist bedeutungslos und 1.To(10)beschreibend. Natürlich verstehe ich die technische Seite, von der Sie sprechen, nur um es zu sagen. Tatsächlich gibt es Szenarien, in denen ein Erweiterungsansatz anstelle statischer Methoden " nicht hätte verwendet werden können", beispielsweise Reflexion, ein anderer Fall dynamic.
Nawfal

Antworten:


35

Ich denke, Erweiterungsmethoden helfen beim Schreiben von Code sehr. Wenn Sie Basistypen Erweiterungsmethoden hinzufügen, erhalten Sie diese schnell im Intellisense.

Ich habe einen Formatanbieter zum Formatieren einer Dateigröße . Um es zu benutzen, muss ich schreiben:

Console.WriteLine(String.Format(new FileSizeFormatProvider(), "{0:fs}", fileSize));

Erstellen einer Erweiterungsmethode, die ich schreiben kann:

Console.WriteLine(fileSize.ToFileSize());

Sauberer und einfacher.


4
Ein aussagekräftigerer Name für Ihre Erweiterungsmethode würde sie noch sauberer machen. zB fileSize.ToFormattedString ();
David Alpert

1
mmm, ToFormattedFizeSize () Vielleicht ist es eine Erweiterungsmethode für einen Long-Typ. ToFormattedString () ist kein beschreibender Name
Eduardo Campañó

3
Punkt gemacht, obwohl. Wenn ich fileSize.ToFileSize () lese, frage ich, warum die Duplizierung? Was macht es eigentlich? Ich weiß, dass es nur ein Beispiel ist, aber beschreibende Namen helfen, es sauber und einfach zu machen.
David Alpert

1
Sie haben Recht, wie bei Tests ist es sehr wichtig, den richtigen Namen zu wählen
Eduardo Campañó

5
Dies beantwortet die Frage jedoch nicht direkt, da das von Ihnen bereitgestellte Beispiel keine Erweiterungsmethode sein muss. Sie hätten haben können LongToFileSize(fileSize), was genauso prägnant und wohl genauso klar ist.
Dan Tao

83

Der einzige Vorteil von Erweiterungsmethoden ist die Lesbarkeit des Codes. Das ist es.

Mit den Erweiterungsmethoden können Sie Folgendes tun:

foo.bar();

an Stelle von:

Util.bar(foo);

Jetzt gibt es in C # viele Dinge, die so sind. Mit anderen Worten, es gibt viele Funktionen in C #, die trivial erscheinen und an und für sich keinen großen Nutzen haben. Sobald Sie jedoch anfangen, diese Funktionen miteinander zu kombinieren, sehen Sie etwas, das nur ein bisschen größer ist als die Summe seiner Teile. LINQ profitiert stark von Erweiterungsmethoden, da LINQ-Abfragen ohne sie fast nicht lesbar wären. LINQ wäre möglich ohne Erweiterungsmethoden, aber nicht praktikabel.

Erweiterungsmethoden ähneln stark den Teilklassen von C #. An sich sind sie nicht sehr hilfreich und scheinen trivial. Wenn Sie jedoch mit einer Klasse arbeiten, die generierten Code benötigt, sind Teilklassen viel sinnvoller.


1
Dies wird noch wichtiger, wenn Sie verkettete Methoden wie x.Foo (etwas) .Bar (etwas anderes) .Baz (noch etwas) verwenden. Dies ist am häufigsten in den IEnumerable <> -Erweiterungsmethoden und erhöht die Lesbarkeit erheblich
ShuggyCoUk

2
Was ich nicht verstehe, ist, dass foo.bar () mir vorschlägt, dass bar () eine Methode von foo ist. Wenn es also nicht funktioniert, suche ich am falschen Ort. Ich bin mir nicht sicher, ob dies tatsächlich eine Verbesserung der Lesbarkeit für mich ist.
Martin Brown

3
Wenn Sie in VS IDE mit der rechten Maustaste auf die Leiste () klicken und zur Definition wechseln, gelangen Sie an die richtige Stelle.
Jeff Martin

9
Der einzige Vorteil von 98% der Sprachkonstrukte ist die Lesbarkeit des Codes. Alles, was über einen Filialisten, ein Label, ein Goto oder ein Inkrement hinausgeht, erleichtert Ihnen das Leben ein wenig.
Giovanni Galbo

2
Das ist nicht ganz richtig, es gibt Situationen, in denen Erweiterungsmethoden die einzige Möglichkeit sind, eine Klasse zu erweitern. Neben versiegelten Klassen benutze ich sie in einer ziemlich einzigartigen Situation. Siehe meinen Beitrag unten.
Edwin Jarvis

34

Werkzeuge nicht vergessen! Wenn Sie eine Erweiterungsmethode M für den Typ Foo hinzufügen, erhalten Sie 'M' in der Intellisense-Liste von Foo (vorausgesetzt, die Erweiterungsklasse ist im Gültigkeitsbereich). Dadurch ist 'M' viel einfacher zu finden als MyClass.M (Foo, ...).

Letztendlich ist es nur syntaktischer Zucker für anderswo statische Methoden, aber wie beim Kauf eines Hauses: 'Ort, Ort, Ort!' Wenn es am Typ hängt, werden die Leute es finden!


2
Dies hat auch einen leichten Nachteil: Erweiterungsmethoden (wie die von System.Linq füllen die automatische Vervollständigung von IntelliSense mit einer längeren Liste, was die Navigation etwas erschwert).
Jared Updike

@Jared: ... aber nur, wenn Sie den Namespace importiert haben, in dem sich die Erweiterungsmethoden befinden, haben Sie also tatsächlich ein geringes Maß an Kontrolle über diese "IntelliSense-Verschmutzung". Zweitens dürfen wir nicht vergessen, dass es in der BCL Klassen gibt (z. B. String), die eine ziemlich lange Liste von Instanzmethoden enthalten, sodass dieses Problem nicht spezifisch für Erweiterungsmethoden ist.
stakx - nicht mehr beitragen

29

Zwei weitere Vorteile von Erweiterungsmethoden, auf die ich gestoßen bin:

  • Eine fließende Schnittstelle kann in eine statische Klasse von Erweiterungsmethoden eingekapselt werden, wodurch eine Trennung der Bedenken zwischen der Kernklasse und ihren fließenden Erweiterungen erreicht wird. Ich habe gesehen, dass eine größere Wartbarkeit erreicht wird.
  • Erweiterungsmethoden können an Schnittstellen aufgehängt werden, sodass Sie einen Vertrag (über eine Schnittstelle) und eine zugehörige Reihe von schnittstellenbasierten Verhaltensweisen (über Erweiterungsmethoden) angeben können, was wiederum eine Trennung der Bedenken ermöglicht. Ein Beispiel sind die Linq Verlängerungsverfahren wie Select(...), Where(...)usw. Hung von der IEnumerable<T>Schnittstelle.

1
Können Sie bitte einige Codebeispiele für beide Punkte zitieren, damit sie besser verstehen? Es scheint ein interessanter Gesichtspunkt zu sein.
RBT

Ja, ein Beispiel für den 2. Punkt wäre schön.
Ini

26

Einige der besten Anwendungen, die ich für Erweiterungsmethoden hatte, sind die folgenden Möglichkeiten:

  1. Erweitern Sie die Funktionalität für Objekte von Drittanbietern (ob kommerziell oder unternehmensintern, aber von einer separaten Gruppe verwaltet), die in vielen Fällen als gekennzeichnet werden sealed.
  2. Erstellen Sie Standardfunktionen für Schnittstellen, ohne eine abstrakte Klasse implementieren zu müssen

Nehmen Sie zum Beispiel , IEnumerable<T>. Obwohl es reich an Erweiterungsmethoden ist, fand ich es ärgerlich, dass keine generische ForEach-Methode implementiert wurde. Also habe ich meine eigenen gemacht:

public void ForEach<T>(this IEnumerable<T> enumerable, Action<T> action)
{
    foreach ( var o in enumerable )
    {
        action(o);
    }
}

Voila, alle meine IEnumerable<T>Objekte, unabhängig vom Implementierungstyp, und ob ich sie geschrieben habe oder jemand anderes, hatten jetzt eine ForEachMethode, indem sie eine entsprechende "using" -Anweisung in meinen Code einfügten.


3
+1 Ich liebe diese Erweiterung, ich habe eine genau so geschrieben. So sehr nützlich
Maslow

10
Beachten Sie, dass die Methode statisch sein muss. Ich empfehle, blogs.msdn.com/ericlippert/archive/2009/05/18/… zu lesen, bevor Sie sich für diese Erweiterung entscheiden.
TrueWill

Grund, warum die Implementierung der ForEach-Erweiterungsmethode auf IEnumerable nicht geschätzt wird - blogs.msdn.microsoft.com/ericlippert/2009/05/18/…
RBT

12

Einer der Hauptgründe für die Verwendung von Erweiterungsmethoden ist LINQ. Ohne Erweiterungsmethoden wäre vieles, was Sie in LINQ tun können, sehr schwierig. Die Erweiterungsmethoden Where (), Contains (), Select bedeuten, dass vorhandenen Typen viel mehr Funktionen hinzugefügt werden, ohne dass ihre Struktur geändert wird.


4
Es ist nicht 'einer von', es ist DER Grund für Erweiterungsmethoden.
Gbjbaanb

3
Wie? Dies ist einer der vielen Gründe für Erweiterungsmethoden, nicht die einzige Voraussetzung. Ich kann Erweiterungsmethoden ohne LINQ verwenden.
Ray Booysen

Ich denke, er meinte, es sei der Grund, warum sie erschaffen wurden, aber ja, er lässt es so klingen, als wären sie die einzig richtige Verwendung für sie.
Brent Rittenhouse

9

Es gibt viele Antworten auf die Vorteile von Erweiterungsmethoden. Wie wäre es mit einem, der die Nachteile angeht ?

Der größte Nachteil ist, dass es keinen Compilerfehler oder eine Warnung gibt, wenn Sie eine reguläre Methode und eine Erweiterungsmethode mit derselben Signatur im selben Kontext haben.

Angenommen, Sie erstellen eine Erweiterungsmethode, die auf eine bestimmte Klasse angewendet wird. Später erstellt jemand eine Methode mit einer identischen Signatur für diese Klasse.

Ihr Code wird kompiliert und Sie erhalten möglicherweise nicht einmal einen Laufzeitfehler. Sie führen jedoch nicht mehr denselben Code wie zuvor aus.


1
4. Überlegen Sie zweimal, bevor Sie Typen erweitern, die Sie nicht besitzen . Wenn Sie nur Erweiterungsmethoden für Typen schreiben, die Sie besitzen, müssen Sie sich keine Sorgen machen, dass Ihre Erweiterungen durch Änderungen am erweiterten Typ beschädigt werden. Auf der anderen Seite, wenn Sie andere Volkstypen erweitern, sind Sie im Wesentlichen ihrer Gnade ausgeliefert.
DavidRR

1
... Alternativ können Sie dieses Risiko minimieren, indem Sie Namen auswählen, die wahrscheinlich nicht von einer anderen Person verwendet werden, oder indem Sie die Gesamtzahl der von Ihnen definierten Erweiterungsmethoden minimieren (dh die Oberfläche reduzieren). Eine Technik hierfür kann darin bestehen, eine Erweiterungsmethode zu schreiben, die das zugrunde liegende Objekt in einen anderen Typ konvertiert, der von Ihnen gesteuert wird.
DavidRR

Erweiterungsmethoden (C # -Programmierhandbuch) : Im Allgemeinen werden Sie Erweiterungsmethoden wahrscheinlich weitaus häufiger aufrufen als eigene.
DavidRR


4

Mein persönliches Argument für Erweiterungsmethoden ist, dass sie sehr gut in ein OOP-Design passen: Betrachten Sie die einfache Methode

bool empty = String.IsNullOrEmpty (myString)

im Vergleich zu

bool empty = myString.IsNullOrEmpty ();

Ich verstehe nicht, was Ihr Beispiel mit OOP zu tun hat. Was meinst du?
Andrew Hare

1
es "scheint", dass die Methode zum Objekt gehört
Bluenuance

3
Dies ist ein schlechtes Beispiel (kann NullReferenceException auslösen), aber er ist auf dem richtigen Weg. Ein besseres Beispiel könnte sein, Math.abs (-4) durch etwas wie -4.abs () zu ersetzen;
Outlaw Programmer

15
Meines Wissens (und meiner Erfahrung nach, wenn Speicherplatz zur Verfügung steht) muss myString.IsNullOrEmpty () keine NullReferenceException auslösen, da für Erweiterungsmethoden keine Objektinstanz erforderlich ist, um ausgelöst zu werden.
David Alpert

1
Ich persönlich bin kein Fan von Erweiterungsmethoden, die mit einer Null-Instanz arbeiten sollen - es sieht für den Leser wie eine Sache aus, macht dann aber etwas anderes.
Mark Simpson

4

Oben finden Sie unzählige gute Antworten darauf, welche Erweiterungsmethoden Sie verwenden können.

Meine kurze Antwort lautet: Sie machen Fabriken fast überflüssig.

Ich möchte nur darauf hinweisen, dass sie kein neues Konzept sind und eine der größten Bestätigungen dafür ist, dass sie ein Killer-Feature in Objective-C ( Kategorien ) sind. Sie bieten der Framework-basierten Entwicklung so viel Flexibilität, dass NeXT Finanzmodellierer der NSA und der Wall Street als Hauptnutzer hatte.

REALbasic implementiert sie auch als erweiterte Methoden und sie waren dort von ähnlichem Nutzen, um die Entwicklung zu vereinfachen.


4

Ich möchte die anderen Antworten hier unterstützen, die eine verbesserte Lesbarkeit des Codes als wichtigen Grund für Erweiterungsmethoden erwähnen. Ich werde dies anhand von zwei Aspekten demonstrieren: Methodenverkettung im Vergleich zu verschachtelten Methodenaufrufen und Unordnung einer LINQ-Abfrage mit bedeutungslosen statischen Klassennamen.


Nehmen wir diese LINQ-Abfrage als Beispiel:

numbers.Where(x => x > 0).Select(x => -x)

Beide Whereund Selectsind Erweiterungsmethoden, die in der statischen Klasse definiert sind Enumerable. Wenn also keine Erweiterungsmethoden vorhanden wären und dies normale statische Methoden wären, müsste die letzte Codezeile im Wesentlichen so aussehen:

Enumerable.Select(Enumerable.Where(numbers, x => x > 0), x => -x)

Sehen Sie, wie viel fieser diese Abfrage gerade geworden ist.


Zweitens, wenn Sie jetzt Ihren eigenen Abfrageoperator einführen möchten, haben Sie natürlich keine Möglichkeit, ihn innerhalb der Enumerablestatischen Klasse zu definieren, wie alle anderen Standardabfrageoperatoren, da er Enumerablesich im Framework befindet und Sie keine Kontrolle über diese Klasse haben. Daher müssten Sie Ihre eigene statische Klasse definieren, die Erweiterungsmethoden enthält. Möglicherweise erhalten Sie dann Fragen wie diese:

Enumerable.Select(MyEnumerableExtensions.RemoveNegativeNumbers(numbers), x => -x)
//                ^^^^^^^^^^^^^^^^^^^^^^
//                different class name that has zero informational value
//                and, as with 'Enumerable.xxxxxx', only obstructs the
//                query's actual meaning.

3

Es ist wahr, dass Sie Ihre (Erweiterungs-) Methode direkt zu Ihrer Klasse hinzufügen können. Aber nicht alle Klassen werden von Ihnen geschrieben. Klassen aus der Kernbibliothek oder Bibliotheken von Drittanbietern werden häufig geschlossen, und es wäre unmöglich, den syntatischen Zucker ohne Erweiterungsmethoden zu erhalten. Denken Sie jedoch daran, dass Erweiterungsmethoden wie (statische) eigenständige Methoden in z. c ++


3

Erweiterungsmethoden können auch dazu beitragen, Ihre Klassen und Klassenabhängigkeiten sauber zu halten. Beispielsweise benötigen Sie möglicherweise überall dort, wo Foo verwendet wird, eine Bar () -Methode für die Foo-Klasse. Möglicherweise möchten Sie jedoch eine .ToXml () -Methode in einer anderen Assembly und nur für diese Assembly. In diesem Fall können Sie die erforderlichen System.Xml- und / oder System.Xml.Linq-Abhängigkeiten in dieser Assembly und nicht in der ursprünglichen Assembly hinzufügen.

Vorteile: Abhängigkeiten in Ihrer definierenden Klassenassembly werden nur auf das Nötigste reduziert, und andere konsumierende Assemblys können die ToXml () -Methode nicht verwenden. Weitere Informationen finden Sie in dieser PDC-Präsentation .


3

Ich bin damit einverstanden, dass Erweiterungsmethoden die Lesbarkeit von Code verbessern, aber es ist wirklich nichts anderes als statische Hilfsmethoden.

IMO, das Erweiterungsmethoden zum Hinzufügen von Verhalten zu Ihren Klassen verwendet, kann sein:

Verwirrend: Programmierer glauben möglicherweise, dass Methoden Teil des erweiterten Typs sind, und verstehen daher nicht, warum die Methoden weg sind, wenn der Erweiterungs-Namespace nicht importiert wird.

Ein Antimuster: Sie beschließen, Typen in Ihrem Framework mithilfe von Erweiterungsmethoden Verhalten hinzuzufügen und sie dann an eine Person weiterzuleiten, die sie einem Komponententest unterzieht. Jetzt steckt er in einem Framework fest, das eine Reihe von Methoden enthält, die er nicht vortäuschen kann.


Es ist nicht wahr, dass ein Entwickler mit einer Reihe von Methoden feststeckt, die er nicht vortäuschen kann. Diese Erweiterungsmethoden rufen schließlich eine Methode für die Klasse / Schnittstelle auf, die sie erweitern, und diese Methode kann abgefangen werden, da sie virtuell ist.
Patrik Hägne

1
Nun, dann kommt es darauf an, was in der Erweiterungsmethode gemacht wird. Angenommen, Sie verwenden bereitgestellte Erweiterungsmethoden für eine Schnittstelle, ohne zu wissen, dass es sich um Erweiterungsmethoden handelt. Dann möchten Sie keinen Methodenaufruf an eine Schnittstelle vortäuschen, aber Sie stellen fest, dass Sie tatsächlich eine statische Methode aufrufen. Ein statischer Methodenaufruf kann nicht von einer Proxy-basierten Fälschungs-API abgefangen werden. Sie können also nur über die Erweiterungsmethode nachdenken, um herauszufinden, welche Methoden tatsächlich gefälscht werden sollen. In Kombination mit IMO-Unit-Tests immer noch Antipattern.
HaraldV

2

Erweiterungsmethoden sind eigentlich die .NET-Integration des Refactors "Introduce Foreign Method" aus Martin Fowlers Buch (bis hin zur Methodensignatur). Sie haben im Grunde die gleichen Vorteile und Fallstricke. In dem Abschnitt über diesen Refactor sagt er, dass sie eine Problemumgehung sind, wenn Sie die Klasse nicht ändern können, die die Methode wirklich besitzen sollte.


2
+1, aber beachten Sie, dass Sie Erweiterungsmethoden auch mit Schnittstellen verwenden können.
TrueWill

2

Ich sehe Erweiterungsmethoden hauptsächlich als ein Eingeständnis, dass sie freie Funktionen vielleicht nicht unzulässig hätten sein dürfen.

In der C ++ - Community wird es häufig als gute OOP-Praxis angesehen, kostenlose Nichtmitgliedsfunktionen gegenüber Mitgliedern zu bevorzugen, da diese Funktionen die Kapselung nicht unterbrechen, indem sie Zugriff auf nicht benötigte private Mitglieder erhalten. Erweiterungsmethoden scheinen ein Umweg zu sein, um dasselbe zu erreichen. Das heißt, eine sauberere Syntax für statische Funktionen, die keinen Zugriff auf private Mitglieder haben.

Erweiterungsmethoden sind nichts anderes als syntaktischer Zucker, aber ich sehe keinen Schaden darin, sie zu verwenden.


2
  • Intellisense für das Objekt selbst, anstatt eine hässliche Dienstprogrammfunktion aufrufen zu müssen
  • Für Konvertierungsfunktionen kann "XToY (X x)" in "ToY (dieses X x)" geändert werden, was zu hübschem x.ToY () anstelle von hässlichem XToY (x) führt.
  • Erweitern Sie Klassen, über die Sie keine Kontrolle haben
  • Erweitern Sie die Funktionalität von Klassen, wenn es nicht wünschenswert ist, den Klassen selbst Methoden hinzuzufügen. Beispielsweise können Sie Geschäftsobjekte einfach und logikfrei halten und spezifische Geschäftslogik mit hässlichen Abhängigkeiten in Erweiterungsmethoden hinzufügen

2

Ich verwende sie, um meine Objektmodellklassen wiederzuverwenden. Ich habe eine Reihe von Klassen, die Objekte darstellen, die ich in einer Datenbank habe. Diese Klassen werden auf der Clientseite nur zum Anzeigen der Objekte verwendet, sodass die grundlegende Verwendung der Zugriff auf Eigenschaften ist.

public class Stock {
   public Code { get; private set; }
   public Name { get; private set; }
}

Aufgrund dieses Verwendungsmusters möchte ich keine Geschäftslogikmethoden in diesen Klassen haben, daher mache ich jede Geschäftslogik zu einer Erweiterungsmethode.

public static class StockExtender {
    public static List <Quote> GetQuotesByDate(this Stock s, DateTime date)
    {...}
}

Auf diese Weise kann ich dieselben Klassen für die Geschäftslogikverarbeitung und für die Anzeige der Benutzeroberfläche verwenden, ohne die Clientseite mit unnötigem Code zu überladen.

Eine interessante Sache an dieser Lösung ist, dass meine Objektmodellklassen dynamisch mit Mono.Cecil generiert werden. Daher wäre es sehr schwierig, Geschäftslogikmethoden hinzuzufügen, selbst wenn ich dies wollte. Ich habe einen Compiler, der XML-Definitionsdateien liest und diese Stubs-Klassen generiert, die ein Objekt darstellen, das ich in der Datenbank habe. Der einzige Ansatz in diesem Fall besteht darin, sie zu erweitern.


1
Sie könnten
Teilklassen


1

In meinem letzten Projekt habe ich die Erweiterungsmethode verwendet, um Validate () -Methoden an Geschäftsobjekte anzuhängen. Ich habe dies begründet, weil die Geschäftsobjekte serialisierbare Datenübertragungsobjekte sind und in verschiedenen Domänen verwendet werden, da sie allgemeine E-Commerce-Entitäten wie Produkte, Kunden, Händler usw. enthalten. In verschiedenen Domänen können die Geschäftsregeln auch unterschiedlich sein, sodass ich meine gekapselt habe Spät gebundene Validierungslogik in einer Validate-Methode, die der Basisklasse meiner Datenübertragungsobjekte zugeordnet ist. Hoffe das macht Sinn :)


1

Ein Fall, in dem Erweiterungsmethoden sehr nützlich waren, war eine Clientanwendung, die ASMX-Webdienste verwendet. Aufgrund der Serialisierung enthalten die Rückgabetypen von Webmethoden keine Methoden (nur die öffentlichen Eigenschaften dieser Typen sind auf dem Client verfügbar).

Mithilfe von Erweiterungsmethoden konnten Funktionen (auf der Clientseite) zu den von Webmethoden zurückgegebenen Typen hinzugefügt werden, ohne dass ein weiteres Objektmodell oder zahlreiche Wrapper-Klassen auf der Clientseite erstellt werden müssen.


1

Erweiterungsmethoden können verwendet werden, um eine Art Mixin in C # zu erstellen .

Dies bietet wiederum eine bessere Trennung der Bedenken für orthogonale Konzepte. Schauen Sie sich diese Antwort als Beispiel an.

Dies kann auch verwendet werden, um Rollen in C # zu aktivieren , einem Konzept, das für die DCI-Architektur von zentraler Bedeutung ist .


1

Denken Sie auch daran, dass Erweiterungsmethoden hinzugefügt wurden, um die Lesbarkeit der Linq-Abfrage zu verbessern, wenn sie in ihrem C # -Stil verwendet wird.

Diese beiden Affekte sind absolut gleichwertig, aber der erste ist weitaus besser lesbar (und die Lücke in der Lesbarkeit würde sich natürlich mit mehr verketteten Methoden vergrößern).

int n1 = new List<int> {1,2,3}.Where(i => i % 2 != 0).Last();

int n2 = Enumerable.Last(Enumerable.Where(new List<int> {1,2,3}, i => i % 2 != 0));

Beachten Sie, dass die vollständig qualifizierte Syntax sogar wie folgt lauten sollte:

int n1 = new List<int> {1,2,3}.Where<int>(i => i % 2 != 0).Last<int>();

int n2 = Enumerable.Last<int>(Enumerable.Where<int>(new List<int> {1,2,3}, i => i % 2 != 0));

Zufällig müssen die Typparameter von Whereund Lastmüssen nicht explizit erwähnt werden, da sie dank des Vorhandenseins des ersten Parameters dieser beiden Methoden abgeleitet werden können (der Parameter, der durch das Schlüsselwort eingeführt wird thisund sie zu Erweiterungsmethoden macht).

Dieser Punkt ist offensichtlich (unter anderem) ein Vorteil der Erweiterungsmethoden, und Sie können ihn in jedem ähnlichen Szenario nutzen, in dem es um die Verkettung von Methoden geht.

Insbesondere ist es die elegantere und überzeugendere Art, eine Basisklassenmethode zu finden, die von jeder Unterklasse aufgerufen werden kann und einen stark typisierten Verweis auf diese Unterklasse (mit dem Unterklassentyp) zurückgibt.

Beispiel (ok, dieses Szenario ist total kitschig): Nach einer guten Nacht öffnet ein Tier die Augen und schreit dann; Jedes Tier öffnet die Augen auf die gleiche Weise, während ein Hund bellt und eine Ente kwaks.

public abstract class Animal
{
    //some code common to all animals
}

public static class AnimalExtension
{
    public static TAnimal OpenTheEyes<TAnimal>(this TAnimal animal) where TAnimal : Animal
    {
        //Some code to flutter one's eyelashes and then open wide
        return animal; //returning a self reference to allow method chaining
    }
}

public class Dog : Animal
{
    public void Bark() { /* ... */ }
}

public class Duck : Animal
{
    public void Kwak() { /* ... */ }
}

class Program
{
    static void Main(string[] args)
    {
        Dog Goofy = new Dog();
        Duck Donald = new Duck();
        Goofy.OpenTheEyes().Bark(); //*1
        Donald.OpenTheEyes().Kwak(); //*2
    }
}

Konzeptionell OpenTheEyessollte es sich um eine AnimalMethode handeln, die jedoch eine Instanz der abstrakten Klasse zurückgibt Animal, die bestimmte Unterklassenmethoden wie Barkoder Duckoder was auch immer nicht kennt . Die 2 als * 1 und * 2 kommentierten Zeilen würden dann einen Kompilierungsfehler auslösen.

Dank der Erweiterungsmethoden können wir jedoch eine Art "Basismethode haben, die den Unterklassentyp kennt, auf dem sie aufgerufen wird".

Beachten Sie, dass eine einfache generische Methode die Arbeit hätte erledigen können, aber auf eine viel umständlichere Weise:

public abstract class Animal
{
    //some code common to all animals

    public TAnimal OpenTheEyes<TAnimal>() where TAnimal : Animal
    {
        //Some code to flutter one's eyelashes and then open wide
        return (TAnimal)this; //returning a self reference to allow method chaining
    }
}

Diesmal kein Parameter und damit keine mögliche Rückgabe des Rückgabetyps. Der Anruf kann nichts anderes sein als:

Goofy.OpenTheEyes<Dog>().Bark();
Donald.OpenTheEyes<Duck>().Kwak();

... was den Code sehr wiegen kann, wenn mehr Verkettung erforderlich ist (insbesondere in dem Wissen, dass der Typparameter immer in <Dog>Goofys Zeile und <Duck>in Donalds Zeile steht ...)


1
Zum ersten Mal habe ich "kwak" gesehen. Ist dies eine Schreibweise, die in einem anderen Land üblich ist? Der einzige Weg, wie ich es jemals geschrieben habe, ist "Quacksalber".
Brent Rittenhouse

0

Ich kann nur ein Wort dazu sagen: WARTUNGSFÄHIGKEIT Dies ist der Schlüssel für die Verwendung von Erweiterungsmethoden


4
Ich denke, Sie brauchen vielleicht mehr als ein Wort, weil ich nicht verstehe, was das bedeutet.
Outlaw Programmer

2
Ich würde tatsächlich sagen, dass dies ein Argument gegen Verlängerungsmethoden ist. Eines der Risiken von Erweiterungsmethoden besteht darin, dass sie überall sein können und von jedem erstellt werden. Wildgrow kann passieren, wenn es nicht sorgfältig verwendet wird.
Boris Callens

Sie können alle Referenzen leicht finden, wenn Sie EM verwenden. Um eine Methode global zu ändern, können Sie dies auch nur von einem Ort aus tun
Tamir

0

Ich denke, Erweiterungsmethoden helfen dabei, Code zu schreiben, der klarer ist.

Anstatt eine neue Methode in Ihre Klasse einzufügen, wie Ihr Freund vorgeschlagen hat, fügen Sie sie in den ExtensionMethods-Namespace ein. Auf diese Weise erhalten Sie ein logisches Ordnungsgefühl für Ihre Klasse. Methoden, die sich nicht direkt mit Ihrer Klasse befassen, werden sie nicht überladen.

Ich bin der Meinung, dass Erweiterungsmethoden Ihren Code klarer und besser organisiert machen.


0

Es ermöglicht Ihrem Editor / Ihrer IDE, Vorschläge automatisch zu vervollständigen.


0

Ich liebe sie für das Erstellen von HTML. Häufig gibt es Abschnitte, die wiederholt verwendet oder rekursiv generiert werden, wenn eine Funktion nützlich ist, aber sonst den Programmfluss unterbrechen würde.

        HTML_Out.Append("<ul>");
        foreach (var i in items)
            if (i.Description != "")
            {
                HTML_Out.Append("<li>")
                    .AppendAnchor(new string[]{ urlRoot, i.Description_Norm }, i.Description)
                    .Append("<div>")
                    .AppendImage(iconDir, i.Icon, i.Description)
                    .Append(i.Categories.ToHTML(i.Description_Norm, urlRoot)).Append("</div></li>");
            }

        return HTML_Out.Append("</ul>").ToString();

Es gibt auch Situationen, in denen ein Objekt eine benutzerdefinierte Logik benötigt, um für HTML-Ausgabeerweiterungsmethoden vorbereitet zu werden. Mit dieser Funktion können Sie diese Funktionalität hinzufügen, ohne Präsentation und Logik innerhalb der Klasse zu mischen.


0

Ich habe festgestellt, dass Erweiterungsmethoden nützlich sind, um verschachtelte generische Argumente abzugleichen.

Das klingt etwas seltsam - aber sagen wir, wir haben eine generische Klasse MyGenericClass<TList>und wir wissen, dass TList selbst generisch ist (z. B. aList<T> ). Ich glaube nicht, dass es eine Möglichkeit gibt, dieses verschachtelte 'T' ohne eine der beiden Erweiterungen aus der Liste zu entfernen Methoden oder statische Hilfsmethoden. Wenn wir nur statische Hilfsmethoden zur Verfügung haben, ist dies (a) hässlich und (b) zwingt uns, die in der Klasse enthaltenen Funktionen an einen externen Speicherort zu verschieben.

Um beispielsweise die Typen in einem Tupel abzurufen und in eine Methodensignatur umzuwandeln, können wir Erweiterungsmethoden verwenden:

public class Tuple { }
public class Tuple<T0> : Tuple { }
public class Tuple<T0, T1> : Tuple<T0> { }

public class Caller<TTuple> where TTuple : Tuple { /* ... */ }

public static class CallerExtensions
{
     public static void Call<T0>(this Caller<Tuple<T0>> caller, T0 p0) { /* ... */ }

     public static void Call<T0, T1>(this Caller<Tuple<T0, T1>> caller, T0 p0, T1 p1) { /* ... */ }
}

new Caller<Tuple<int>>().Call(10);
new Caller<Tuple<string, int>>().Call("Hello", 10);

Ich bin mir jedoch nicht sicher, wo die Trennlinie liegen soll - wann sollte eine Methode eine Erweiterungsmethode sein und wann sollte sie eine statische Hilfsmethode sein? Irgendwelche Gedanken?


0

Ich habe Eingabezonen auf meinem Bildschirm und alle müssen ein Standardverhalten implementieren, unabhängig von ihrem genauen Typ (Textfelder, Kontrollkästchen usw.). Sie können keine gemeinsame Basisklasse erben, da jeder Typ der Eingabezone bereits von einer bestimmten Klasse (TextInputBox usw.) abgeleitet ist.

Vielleicht könnte ich durch Aufsteigen in der Vererbungshierarchie einen gemeinsamen Vorfahren wie WebControl finden, aber ich habe die Framework-Klasse WebControl nicht entwickelt und sie enthüllt nicht, was ich brauche.

Mit der Erweiterungsmethode kann ich:

1) Erweitern Sie die WebControl-Klasse und erhalten Sie dann mein einheitliches Standardverhalten für alle meine Eingabeklassen

2) Alternativ können Sie alle meine Klassen von einer Schnittstelle ableiten, z. B. IInputZone, und diese Schnittstelle mit Methoden erweitern. Ich kann jetzt Erweiterungsmethoden für die Schnittstelle in allen meinen Eingabezonen aufrufen. Ich habe so eine Art Mehrfachvererbung erreicht, da meine Eingabezonen bereits von mehreren Basisklassen abgeleitet sind.


0

Es gibt so viele großartige Beispiele für Erweiterungsmethoden, insbesondere für IEnumerables, wie oben beschrieben.

zB wenn ich eine IEnumerable<myObject>habe kann ich eine Methode erstellen und erweitern fürIEnumerable<myObject>

mylist List<myObject>;

... die Liste erstellen

mylist.DisplayInMyWay();

Ohne Erweiterung müssten Methoden aufrufen:

myDisplayMethod(myOldArray); // can create more nexted brackets.

Ein weiteres gutes Beispiel ist das blitzschnelle Erstellen einer zirkulären verknüpften Liste!

Ich kann es gutschreiben!

kreisförmig verknüpfte Liste mit Erweiterungsmethoden

Kombinieren Sie diese nun und verwenden Sie den Code für Erweiterungsmethoden wie folgt.

myNode.NextOrFirst().DisplayInMyWay();

eher, als

DisplayInMyWay(NextOrFirst(myNode)).

Verwenden von Erweiterungsmethoden Es ist übersichtlicher und leichter zu lesen und objektorientierter. auch ganz in der Nähe von:

myNode.Next.DoSomething()

Zeigen Sie das Ihrem Kollegen! :) :)

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.