Quels avantages des méthodes d'extension avez-vous trouvés? [fermé]

84

Un "non-croyant" de C # me demandait quel était le but des méthodes d'extension. J'ai expliqué que vous pouviez ensuite ajouter de nouvelles méthodes aux objets déjà définis, en particulier lorsque vous ne possédez pas / ne contrôlez pas la source de l'objet d'origine.

Il a évoqué "Pourquoi ne pas simplement ajouter une méthode à votre propre classe?" Nous avons tourné en rond (dans le bon sens). Ma réponse générale est que c'est un autre outil dans la ceinture à outils, et sa réponse est que c'est un gaspillage inutile d'outil ... mais j'ai pensé que j'obtiendrais une réponse plus «éclairée».

Quels sont les scénarios dans lesquels vous avez utilisé des méthodes d'extension que vous ne pouviez pas (ou n'auriez pas dû) utiliser une méthode ajoutée à votre propre classe?

Jerry
la source
2
Je pense qu'il y a certainement des points valables que les gens peuvent faire (et ont fait) pour soutenir les méthodes d'extension ... mais il n'y a certainement aucun scénario où l'on " n'aurait pas pu" utiliser des méthodes statiques à la place des méthodes d'extension. Les méthodes d'extension ne sont en réalité que des méthodes statiques, accessibles d'une manière différente. Juste quelque chose à garder à l'esprit.
Dan Tao
@DanTao, sur une note plus légère, la seule chose qui rend irremplaçable l'appel par la méthode d'extension est leur nom même. Extensions.To(1, 10)n'a pas de sens et 1.To(10)est descriptif. Bien sûr, je comprends l'aspect technique dont vous parlez, simplement en le disant. En fait, il existe des scénarios où l'on " n'aurait pas pu" utiliser l'approche d'extension à la place des méthodes statiques, la réflexion par exemple, un autre cas estdynamic .
nawfal

Réponses:

35

Je pense que les méthodes d'extension aident beaucoup lors de l'écriture de code, si vous ajoutez des méthodes d'extension aux types de base, vous les obtiendrez rapidement dans l'intellisense.

J'ai un fournisseur de format pour formater une taille de fichier . Pour l'utiliser, j'ai besoin d'écrire:

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

Créer une méthode d'extension que je peux écrire:

Console.WriteLine(fileSize.ToFileSize());

Plus propre et plus simple.

Eduardo Campañó
la source
4
un nom plus descriptif pour votre méthode d'extension la rendrait encore plus propre. par exemple fileSize.ToFormattedString ();
David Alpert
1
mmm, ToFormattedFizeSize () peut-être, c'est une méthode d'extension pour un type Long, ToFormattedString () n'est pas un nom descriptif
Eduardo Campañó
3
point fait, cependant. quand je lis fileSize.ToFileSize () je demande pourquoi la duplication? que fait-il réellement? Je sais que ce n'est qu'un exemple, mais les noms descriptifs aident à le rendre clair et simple.
David Alpert
1
vous avez raison car avec les tests, il est très important de choisir le bon nom
Eduardo Campañó
5
Cependant, cela ne répond pas vraiment directement à la question, car l'exemple que vous avez fourni n'a pas besoin d'être une méthode d'extension. Vous auriez pu avoir LongToFileSize(fileSize), ce qui est tout aussi concis et sans doute tout aussi clair.
Dan Tao
83

Le seul avantage des méthodes d'extension est la lisibilité du code. C'est ça.

Les méthodes d'extension vous permettent de faire ceci:

foo.bar();

au lieu de cela:

Util.bar(foo);

Maintenant, il y a beaucoup de choses en C # qui sont comme ça. En d'autres termes, il existe de nombreuses fonctionnalités en C # qui semblent insignifiantes et n'ont pas de grands avantages en elles-mêmes. Cependant, une fois que vous commencez à combiner ces fonctionnalités, vous commencez à voir quelque chose d'un peu plus grand que la somme de ses parties. LINQ bénéficie grandement des méthodes d'extension car les requêtes LINQ seraient presque illisibles sans elles. LINQ serait possible sans méthodes d'extension, mais pas pratique.

Les méthodes d'extension ressemblent beaucoup aux classes partielles de C #. En eux-mêmes, ils ne sont pas très utiles et semblent insignifiants. Mais lorsque vous commencez à travailler avec une classe qui a besoin de code généré, les classes partielles commencent à avoir beaucoup plus de sens.

Andrew Hare
la source
1
Cela devient encore plus important si vous utilisez des méthodes chaînées comme x.Foo (quelque chose) .Bar (quelque chose d'autre) .Baz (encore quelque chose). Ceci est le plus répandu dans les méthodes d'extension IEnumerable <> et augmente considérablement la lisibilité
ShuggyCoUk
2
Ce que je n'obtiens pas, c'est que foo.bar () me suggère que bar () est une méthode de foo. Alors quand ça ne marche pas, je finis par chercher au mauvais endroit. Je ne suis pas sûr que ce soit réellement une amélioration de la lisibilité pour moi.
Martin Brown
3
Un clic droit sur la barre () dans VS IDE et choisir Goto the Definition vous amènerait au bon endroit.
Jeff Martin
9
Le seul avantage de 98% des constructions de langage est la lisibilité du code. Tout ce qui passe par un opérateur de succursale, une étiquette, un goto et un incrément est là pour vous rendre la vie un peu plus facile.
Giovanni Galbo
2
Ce n'est pas tout à fait vrai, dans certaines situations, les méthodes d'extension sont le seul moyen d'étendre une classe. Outre les classes scellées, je les utilise dans une situation assez unique. Voir mon message ci-dessous.
Edwin Jarvis
34

N'oubliez pas l'outillage! Lorsque vous ajoutez une méthode d'extension M sur le type Foo, vous obtenez 'M' dans la liste intellisense de Foo (en supposant que la classe d'extension est dans la portée). Cela rend 'M' beaucoup plus facile à trouver que MyClass.M (Foo, ...).

En fin de compte, ce n'est que du sucre syntaxique pour les méthodes ailleurs-statiques, mais comme l'achat d'une maison: «emplacement, emplacement, emplacement! S'il se bloque sur le type, les gens le trouveront!

Brian
la source
2
Il y a aussi un léger inconvénient à cela: les méthodes d'extension (telles que celles de System.Linq remplissent la saisie semi-automatique IntelliSense avec une liste plus longue, ce qui rend la navigation un peu plus difficile.
Jared Updike
@Jared: ... mais seulement si vous avez importé l'espace de noms où résident les méthodes d'extension, vous avez donc en fait un petit degré de contrôle sur cette "pollution IntelliSense". Deuxièmement, n'oublions pas qu'il existe des classes dans la BCL (telles que String) qui viennent avec une liste assez longue de méthodes d'instance, donc ce problème n'est pas spécifique aux méthodes d'extension.
stakx - ne contribue plus le
29

Deux autres avantages des méthodes d'extension que j'ai rencontrés:

  • Une interface fluide peut être encapsulée dans une classe statique de méthodes d'extension, réalisant ainsi une séparation des préoccupations entre la classe principale et ses extensions fluides; J'ai vu cela atteindre une plus grande maintenabilité.
  • Les méthodes d'extension peuvent être suspendues aux interfaces, vous permettant ainsi de spécifier un contrat (via une interface) et une série associée de comportements basés sur l'interface (via des méthodes d'extension), offrant à nouveau une séparation des préoccupations. Un exemple sont les méthodes extension de Linq aiment Select(...), Where(...)etc. Hung hors l' IEnumerable<T>interface.
David Alpert
la source
1
Pouvez-vous citer quelques exemples de code pour les deux points afin de les aider à mieux comprendre? Cela semble être un point de vue intéressant.
RBT
ouais un exemple pour le 2ème point serait bien.
Ini
26

Certaines des meilleures utilisations que j'ai eues des méthodes d'extension sont la possibilité de:

  1. Étendez les fonctionnalités sur des objets tiers (qu'ils soient commerciaux ou internes à mon entreprise mais gérés par un groupe distinct), qui dans de nombreux cas seront marqués comme sealed.
  2. Créer des fonctionnalités par défaut pour les interfaces sans avoir à implémenter une classe abstraite

Prenons par exemple IEnumerable<T>,. Bien qu'il soit riche en méthodes d'extension, j'ai trouvé ennuyeux qu'il n'implémente pas de méthode ForEach générique. Alors, j'ai fait le mien:

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

Voila, tous mes IEnumerable<T>objets quel que soit le type d'implémentation, et que je l'ai écrit ou non ou que quelqu'un d'autre ait maintenant une ForEachméthode en ajoutant une instruction "using" appropriée dans mon code.

Jon Limjap
la source
3
+1 J'adore cette extension, j'en ai écrit une comme elle. Tellement très utile
Maslow
10
Notez que la méthode doit être statique. Je suggère de lire blogs.msdn.com/ericlippert/archive/2009/05/18/... avant de décider d'utiliser cette extension.
TrueWill
Raison pour laquelle la mise en œuvre de la méthode d'extension ForEach sur IEnumerable n'est pas appréciée - blogs.msdn.microsoft.com/ericlippert/2009/05/18
RBT
12

L'une des bonnes raisons d'utiliser des méthodes d'extension est LINQ. Sans les méthodes d'extension, une grande partie de ce que vous pouvez faire dans LINQ serait très difficile. Les méthodes d'extension Where (), Contains (), Select signifient que beaucoup plus de fonctionnalités sont ajoutées aux types existants sans changer leur structure.

Ray Booysen
la source
4
ce n'est pas «l'un des», c'est LA raison des méthodes d'extension.
gbjbaanb
3
Comment? C'est l'une des nombreuses raisons d'avoir des méthodes d'extension, pas la seule exigence. Je peux utiliser des méthodes d'extension sans utiliser LINQ.
Ray Booysen
Je pense qu'il voulait dire que c'était la raison pour laquelle ils ont été créés, mais oui, il donne l'impression qu'ils sont la seule bonne utilisation pour eux.
Brent Rittenhouse
9

Il existe de nombreuses réponses sur les avantages des méthodes d'extensions; que diriez-vous de remédier aux inconvénients ?

Le plus gros inconvénient est qu'il n'y a pas d'erreur ou d'avertissement du compilateur si vous avez une méthode régulière et une méthode d'extension avec la même signature dans le même contexte.

Supposons que vous créez une méthode d'extension s'appliquant à une classe particulière. Ensuite, quelqu'un crée une méthode avec une signature identique sur cette classe elle-même.

Votre code se compilera et vous n'obtiendrez peut-être même pas d'erreur d'exécution. Mais vous n'utilisez plus le même code qu'avant.

Ryan Lundy
la source
1
4. Réfléchissez à deux fois avant d'étendre les types que vous ne possédez pas . Si vous n'écrivez des méthodes d'extension que pour les types que vous possédez, vous n'aurez jamais à vous soucier de la rupture de vos extensions par les modifications apportées au type en cours d'extension. D'un autre côté, si vous étendez d'autres types de peuples, vous êtes essentiellement à leur merci.
DavidRR
1
... Alternativement, vous pouvez minimiser ce risque en choisissant des noms qui ne seront probablement pas utilisés par quelqu'un d'autre, ou en minimisant le nombre total de méthodes d'extension que vous définissez (c'est-à-dire en réduisant la surface). Une technique pour ce faire peut être d'écrire une méthode d'extension qui convertit l'objet sous-jacent en un type différent que vous contrôlez.
DavidRR
Méthodes d'extension (Guide de programmation C #) : En général, vous appellerez probablement des méthodes d'extension beaucoup plus souvent que la vôtre.
DavidRR
8

Interfaces fluides et sensibilité au contexte comme démontré par Greg Young sur CodeBetter

cgreeno
la source
4

Mon argument personnel pour les méthodes d'extension est qu'elles s'intègrent très bien dans une conception POO: considérez la méthode simple

bool empty = String.IsNullOrEmpty (myString)

en comparaison à

bool empty = myString.IsNullOrEmpty ();
Bluenuance
la source
Je ne vois pas ce que votre exemple a à voir avec la POO. Que voulez-vous dire?
Andrew Hare
1
il "semble" que la méthode appartient à l'objet
Bluenuance
3
Ceci est un mauvais exemple (peut lancer NullReferenceException) mais il est sur la bonne voie. Un meilleur exemple pourrait être de remplacer Math.abs (-4) par quelque chose comme -4.abs ();
Programmeur hors
15
à ma connaissance (et à mon expérience, si ma mémoire est bonne), myString.IsNullOrEmpty () n'a pas besoin de lancer une exception NullReferenceException car les méthodes d'extension ne nécessitent pas d'instance d'objet pour se déclencher.
David Alpert
1
Personnellement, je ne suis pas fan des méthodes d'extension destinées à fonctionner avec une instance nulle - cela ressemble à une chose pour le lecteur, mais fait autre chose.
Mark Simpson
4

Il y a des tas de bonnes réponses ci-dessus sur ce que les méthodes d'extension vous permettent de faire.

Ma réponse courte est - ils éliminent presque le besoin d'usines.

Je ferai juste remarquer qu'ils ne sont pas un nouveau concept et que l'une des plus grandes validations d'entre eux est qu'ils sont une fonctionnalité qui tue dans Objective-C ( catégories ). Ils ajoutent tellement de flexibilité au développement basé sur un cadre que NeXT avait les modélisateurs financiers de la NSA et de Wall Street comme principaux utilisateurs.

REALbasic les implémente également en tant que méthodes étendues et elles ont été d'une utilisation similaire pour simplifier le développement.

Andy Dent
la source
4

Je voudrais soutenir les autres réponses ici qui mentionnent une meilleure lisibilité du code comme une raison importante derrière les méthodes d'extension. Je vais le démontrer avec deux aspects de ceci: le chaînage de méthodes par rapport aux appels de méthodes imbriqués et l'encombrement d'une requête LINQ avec des noms de classe statiques sans signification.


Prenons cette requête LINQ comme exemple:

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

Les deux Whereet Selectsont des méthodes d'extension, définies dans la classe statique Enumerable. Ainsi, si les méthodes d'extension n'existaient pas, et qu'il s'agissait de méthodes statiques normales, la dernière ligne de code devrait essentiellement ressembler à ceci:

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

Voyez à quel point cette requête vient d'être plus méchante.


Deuxièmement, si vous vouliez maintenant introduire votre propre opérateur de requête, vous n'auriez naturellement aucun moyen de le définir dans la Enumerableclasse statique, comme tous les autres opérateurs de requête standard, car il Enumerableest dans le framework et vous n'avez aucun contrôle sur cette classe. Par conséquent, vous devez définir votre propre classe statique contenant des méthodes d'extension. Vous pourriez alors recevoir des requêtes telles que celle-ci:

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.
stakx - ne contribue plus
la source
3

Il est vrai que vous pouvez ajouter votre méthode (d'extension) directement dans votre classe. Mais toutes les classes ne sont pas écrites par vous. Les classes de la bibliothèque principale ou des bibliothèques tierces sont souvent fermées et il serait impossible d'obtenir le sucre syntatique sans méthodes d'extension. Mais rappelez-vous, les méthodes d'extension sont comme les méthodes autonomes (statiques) par exemple. c ++

Schildmeijer
la source
3

Les méthodes d'extension peuvent également aider à garder vos classes et dépendances de classe propres. Par exemple, vous pouvez avoir besoin d'une méthode Bar () pour la classe Foo partout où Foo est utilisé. Toutefois, vous pouvez souhaiter une méthode .ToXml () dans un autre assembly et uniquement pour cet assembly. Dans ce cas, vous pouvez ajouter les dépendances System.Xml et / ou System.Xml.Linq nécessaires dans cet assembly et non dans l'assembly d'origine.

Avantages: les dépendances dans votre assembly de classe de définition sont réduites au strict nécessaire et les autres assemblys consommateurs ne pourront pas utiliser la méthode ToXml (). Voir cette présentation PDC pour plus de références.

user29439
la source
3

Je suis d'accord que les méthodes d'extension augmentent la lisibilité du code, mais ce n'est vraiment rien d'autre que des méthodes d'assistance statiques.

IMO utilisant des méthodes d'extension pour ajouter un comportement à vos classes peut être:

Confus: les programmeurs pourraient croire que les méthodes font partie du type étendu, ne comprenant donc pas pourquoi les méthodes ont disparu lorsque l'espace de noms d'extension n'est pas importé.

Un anti-modèle: vous décidez d'ajouter un comportement aux types dans votre framework à l'aide de méthodes d'extension, puis de les envoyer à une personne qui les teste unitaire. Maintenant, il est coincé avec un cadre contenant un tas de méthodes qu'il ne peut pas simuler.

HaraldV
la source
Ce n'est pas vrai qu'un développeur est coincé avec un tas de méthodes qu'il ne peut pas simuler. Ces méthodes d'extension appellent finalement une méthode sur la classe / l'interface qu'elles étendent et cette méthode peut être interceptée étant donné qu'elle est virtuelle.
Patrik Hägne
1
Eh bien, cela dépend de ce qui est fait dans la méthode d'extension. Disons que vous utilisez les méthodes d'extension fournies sur une interface, sans même savoir qu'il s'agit de méthodes d'extension. Ensuite, vous ne ferez pas semblant d'appeler une méthode à une interface, mais vous vous rendez compte que vous invoquez en fait une méthode statique. Un appel de méthode statique ne peut pas être intercepté par une API de simulation basée sur un proxy, votre seule option est donc de réfléchir à la méthode d'extension pour savoir quelles méthodes simuler réellement. Toujours antipattern lorsqu'il est combiné avec les tests unitaires IMO.
HaraldV
2

Les méthodes d'extension sont en réalité l'incorporation .NET du refactor «Introduce Foreign Method» du livre de Martin Fowler (jusqu'à la signature de la méthode). Ils présentent essentiellement les mêmes avantages et inconvénients. Dans la section sur ce refactor, il dit qu'il s'agit d'une solution de contournement lorsque vous ne pouvez pas modifier la classe qui devrait vraiment posséder la méthode.

Jason Punyon
la source
2
+1, mais notez que vous pouvez également utiliser des méthodes d'extension avec des interfaces.
TrueWill
2

Je vois principalement les méthodes d'extension comme une admission qu'elles n'auraient peut-être pas dû interdire les fonctions libres.

Dans la communauté C ++, il est souvent considéré comme une bonne pratique POO de préférer les fonctions non membres libres aux membres, car ces fonctions ne cassent pas l'encapsulation en accédant aux membres privés dont elles n'ont pas besoin. Les méthodes d'extension semblent être un moyen détourné d'atteindre la même chose. Autrement dit, une syntaxe plus propre pour les fonctions statiques qui n'ont pas accès aux membres privés.

Les méthodes d'extension ne sont rien de plus que du sucre syntaxique, mais je ne vois aucun mal à les utiliser.

jalf
la source
2
  • Intellisense sur l'objet lui-même au lieu d'avoir à appeler une fonction utilitaire laide
  • Pour les fonctions de conversion, vous pouvez changer "XToY (X x)" en "ToY (this X x)", ce qui donne un joli x.ToY () au lieu d'un laid XToY (x).
  • Étendez les cours sur lesquels vous n'avez aucun contrôle
  • Étendez les fonctionnalités des classes lorsqu'il n'est pas souhaitable d'ajouter des méthodes aux classes elles-mêmes. Par exemple, vous pouvez garder les objets métier simples et sans logique, et ajouter une logique métier spécifique avec des dépendances laides dans les méthodes d'extension
Davogones
la source
2

Je les utilise pour réutiliser mes classes de modèle objet. J'ai un tas de classes qui représentent des objets que j'ai dans une base de données. Ces classes sont utilisées côté client uniquement pour afficher les objets de sorte que l'utilisation de base accède aux propriétés.

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

En raison de ce modèle d'utilisation, je ne veux pas avoir de méthodes de logique métier dans ces classes, donc je fais de chaque logique métier une méthode d'extension.

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

De cette façon, je peux utiliser les mêmes classes pour le traitement de la logique métier et pour l'affichage de l'interface utilisateur sans surcharger le côté client avec du code inutile.

Une chose intéressante à propos de cette solution est que mes classes de modèle objet sont générées de manière dynamique à l'aide de Mono.Cecil , il serait donc très difficile d'ajouter des méthodes de logique métier même si je le voulais. J'ai un compilateur qui lit les fichiers de définition XML et génère ces classes de stubs représentant un objet que j'ai dans la base de données. La seule approche dans ce cas est de les étendre.

Edwin Jarvis
la source
1
Vous pouvez utiliser des cours partiels pour cela ...
JJoos
1

Dans mon dernier projet, j'ai utilisé la méthode d'extension pour attacher les méthodes Validate () aux objets métier. J'ai justifié cela parce que les objets métier étaient des objets de transfert de données sérialisables et seront utilisés dans différents domaines car ils concernaient des entités de commerce électronique générales telles que produit, client, commerçant, etc. logique de validation à liaison tardive dans une méthode Validate attachée à la classe de base de mes objets de transfert de données. J'espère que cela a du sens :)

Athènes
la source
1

Un cas où les méthodes d'extension étaient très utiles était dans une application client qui utilise les services Web ASMX. En raison de la sérialisation, les types de retour des méthodes Web ne contiennent aucune méthode (seules les propriétés publiques de ces types sont disponibles sur le client).

Les méthodes d'extension permettaient d'ajouter des fonctionnalités (côté client) aux types renvoyés par les méthodes Web sans avoir à créer encore un autre modèle d'objet ou de nombreuses classes wrapper côté client.

M4N
la source
1

Les méthodes d'extension peuvent être utilisées pour créer une sorte de mixin en C #.

Ceci, à son tour, fournit une meilleure séparation des préoccupations pour les concepts orthogonaux. Jetez un œil à cette réponse à titre d'exemple.

Cela peut également être utilisé pour activer les rôles en C #, un concept central de l' architecture DCI .

Jordão
la source
1

Rappelez-vous également que les méthodes d'extension ont été ajoutées pour aider les requêtes Linq à être plus lisibles lorsqu'elles sont utilisées dans leur style C #.

Ces 2 affectations sont absolument équivalentes, mais la première est beaucoup plus lisible (et l'écart de lisibilité augmenterait bien sûr avec plus de méthodes enchaînées).

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

Notez que la syntaxe complète devrait même être:

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

Par hasard, les paramètres de type de Whereet Lastn'ont pas besoin d'être explicitement mentionnés car ils peuvent être déduits grâce à la présence du premier paramètre de ces deux méthodes (le paramètre qui est introduit par le mot-cléthis et en fait des méthodes d'extension).

Ce point est évidemment un avantage (entre autres) des méthodes d'extension, et vous pouvez en profiter dans tous les scénarios similaires où le chaînage de méthodes est impliqué.

Surtout, c'est la façon la plus élégante et convaincante que j'ai trouvée d'avoir une méthode de classe de base invocable par n'importe quelle sous-classe et de renvoyer une référence fortement typée à cette sous-classe (avec le type de sous-classe).

Exemple (ok, ce scénario est totalement ringard): après une bonne nuit, un animal ouvre les yeux puis pousse un cri; chaque animal ouvre les yeux de la même manière, tandis qu'un chien aboie et un canard 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
    }
}

Conceptuellement, OpenTheEyesdevrait être une Animalméthode, mais elle retournerait alors une instance de la classe abstraite Animal, qui ne connaît pas les méthodes de sous-classe spécifiques comme Barkou Duckou autre. Les 2 lignes commentées * 1 et * 2 soulèveraient alors une erreur de compilation.

Mais grâce aux méthodes d'extension, on peut avoir une sorte de "méthode de base qui connaît le type de sous-classe sur lequel elle est appelée".

Notez qu'une méthode générique simple aurait pu faire le travail, mais d'une manière beaucoup plus délicate:

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

Cette fois, pas de paramètre et donc pas d'inférence de type de retour possible. L'appel ne peut être rien d'autre que:

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

... qui peut peser beaucoup sur le code si plus de chaînage est impliqué (surtout en sachant que le paramètre type sera toujours <Dog>sur la ligne de Goofy et <Duck>sur celle de Donald ...)

Ssithra
la source
1
La première fois que j'ai vu "kwak". Est-ce une orthographe courante dans un autre pays? La seule façon dont je l'ai vu orthographié est «charlatan».
Brent Rittenhouse
0

Je n'ai qu'un mot à dire à ce sujet: MAINTAINABILITY c'est la clé pour l'utilisation des méthodes d'extension

Tamir
la source
4
Je pense que vous pourriez avoir besoin de plus d'un mot parce que je ne comprends pas ce que cela signifie.
Programmeur hors
2
Je dirais en fait que c'est un argument contre les méthodes d'extention. L'un des risques des méthodes d'extention est qu'elles peuvent être partout, créées par tout le monde. Wildgrow peut se produire s'il n'est pas utilisé avec précaution.
Boris Callens
Vous pouvez trouver toutes les références facilement, lorsque vous utilisez EM. De plus, afin de changer globalement une méthode, vous pouvez le faire à partir d'un seul endroit
Tamir
0

Je pense que les méthodes d'extension aident à écrire un code plus clair.

Au lieu de mettre une nouvelle méthode dans votre classe, comme votre ami l'a suggéré, vous la placez dans l'espace de noms ExtensionMethods. De cette façon, vous maintenez un sens logique de l'ordre dans votre classe. Les méthodes qui ne traitent pas vraiment directement avec votre classe ne l'encombreront pas.

Je pense que les méthodes d'extension rendent votre code plus clair et mieux organisé.

Alex Baranosky
la source
0

Il permet à votre éditeur / IDE de faire des suggestions d'auto-complétion intelligentes.

Dennis C
la source
0

Je les adore pour créer du HTML. Il y a souvent des sections qui sont utilisées à plusieurs reprises, ou générées de manière récursive où une fonction est utile mais qui autrement interromprait le déroulement du programme.

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

Il existe également des situations où un objet a besoin d'une logique personnalisée pour être préparé pour les méthodes d'extension de sortie HTML vous permettant d'ajouter cette fonctionnalité sans mélanger la présentation et la logique dans la classe.

Kelly Gendron
la source
0

J'ai trouvé que les méthodes d'extension sont utiles pour faire correspondre des arguments génériques imbriqués.

Cela semble un peu bizarre - mais disons que nous avons une classe générique MyGenericClass<TList>, et nous savons que TList lui-même est générique (par exemple, unList<T> ), je ne pense pas qu'il y ait un moyen de déterrer ce 'T' imbriqué de la liste sans aucune extension méthodes ou méthodes d'assistance statiques. Si nous n'avons que des méthodes d'assistance statiques à notre disposition, c'est (a) moche, et (b) nous forcera à déplacer les fonctionnalités appartenant à la classe vers un emplacement externe.

par exemple pour récupérer les types dans un tuple et les convertir en une signature de méthode, nous pouvons utiliser des méthodes d'extension:

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

Cela dit, je ne sais pas où devrait être la ligne de démarcation - quand une méthode devrait-elle être une méthode d'extension, et quand devrait-elle être une méthode d'assistance statique? Des pensées?

Andy
la source
0

J'ai des zones de saisie sur mon écran, et tous doivent implémenter un comportement standard quels que soient leurs types exacts (zones de texte, cases à cocher, etc.). Ils ne peuvent pas hériter d'une classe de base commune car chaque type de zone d'entrée dérive déjà d'une classe spécifique (TextInputBox, etc.)

Peut-être qu'en montant dans la hiérarchie d'héritage, je pourrais trouver un ancêtre commun comme par exemple WebControl, mais je n'ai pas développé la classe de cadre WebControl et elle n'expose pas ce dont j'ai besoin.

Avec la méthode d'extension, je peux:

1) étendre la classe WebControl, puis obtenir mon comportement standard unifié sur toutes mes classes d'entrée

2) alternativement, faire dériver toutes mes classes d'une interface, disons IInputZone, et étendre cette interface avec des méthodes. Je vais maintenant pouvoir appeler des méthodes d'extensions liées à l'interface sur toutes mes zones de saisie. J'ai ainsi réalisé une sorte d'héritage multiple puisque mes zones d'entrée sont déjà dérivées de plusieurs classes de base.

Ssithra
la source
0

Il y a tellement d'excellents exemples de méthodes d'extension ... en particulier sur IEnumerables comme indiqué ci-dessus.

Par exemple, si j'ai une IEnumerable<myObject>méthode Je peux créer et une extension pourIEnumerable<myObject>

mylist List<myObject>;

... créer la liste

mylist.DisplayInMyWay();

Sans les méthodes d'extension auraient à appeler:

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

Un autre bon exemple est la création d'une liste liée circulaire en un éclair!

Je peux «m'en attribuer le mérite!

liste chaînée circulaire utilisant des méthodes d'extension

Maintenant, combinez-les et utilisez le code des méthodes d'extension comme suit.

myNode.NextOrFirst().DisplayInMyWay();

plutôt que

DisplayInMyWay(NextOrFirst(myNode)).

utilisation des méthodes d'extension Il est plus net et plus facile à lire et plus orienté objet. aussi très proche de:

myNode.Next.DoSomething()

Montrez cela à votre collègue! :)

Gregor
la source