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?
la source
Extensions.To(1, 10)
n'a pas de sens et1.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
.Réponses:
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:
Plus propre et plus simple.
la source
LongToFileSize(fileSize)
, ce qui est tout aussi concis et sans doute tout aussi clair.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:
au lieu de cela:
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.
la source
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!
la source
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.Deux autres avantages des méthodes d'extension que j'ai rencontrés:
Select(...)
,Where(...)
etc. Hung hors l'IEnumerable<T>
interface.la source
Certaines des meilleures utilisations que j'ai eues des méthodes d'extension sont la possibilité de:
sealed
.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 uneForEach
méthode en ajoutant une instruction "using" appropriée dans mon code.la source
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.
la source
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.
la source
Interfaces fluides et sensibilité au contexte comme démontré par Greg Young sur CodeBetter
la source
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 ();
la source
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.
la source
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
Where
etSelect
sont des méthodes d'extension, définies dans la classe statiqueEnumerable
. 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
Enumerable
classe statique, comme tous les autres opérateurs de requête standard, car ilEnumerable
est 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.
la source
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 ++
la source
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.
la source
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.
la source
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.
la source
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.
la source
la source
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.
la source
Cela permet à C # de mieux prendre en charge les langages dynamiques, LINQ et une douzaine d'autres choses. Consultez l'article de Scott Guthrie .
la source
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 :)
la source
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.
la source
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 .
la source
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
Where
etLast
n'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,
OpenTheEyes
devrait être uneAnimal
méthode, mais elle retournerait alors une instance de la classe abstraiteAnimal
, qui ne connaît pas les méthodes de sous-classe spécifiques commeBark
ouDuck
ou 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:
... 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 ...)la source
Je n'ai qu'un mot à dire à ce sujet: MAINTAINABILITY c'est la clé pour l'utilisation des méthodes d'extension
la source
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é.
la source
Il permet à votre éditeur / IDE de faire des suggestions d'auto-complétion intelligentes.
la source
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.
la source
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?
la source
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.
la source
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>
... créer la liste
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.
plutôt que
utilisation des méthodes d'extension Il est plus net et plus facile à lire et plus orienté objet. aussi très proche de:
Montrez cela à votre collègue! :)
la source