Comment étendre une classe avec des méthodes d'extension c #?


98

Les méthodes d'extension peuvent-elles être appliquées à la classe?

Par exemple, étendez DateTime pour inclure une méthode Tomorrow () qui pourrait être appelée comme:

DateTime.Tomorrow();

Je sais que je peux utiliser

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

Ou

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

pour un résultat similaire, mais comment puis-je étendre DateTime pour pouvoir invoquer DateTime.Tomorrow?

Réponses:


70

Vous ne pouvez pas ajouter de méthodes à un type existant à moins que le type existant ne soit marqué comme partiel, vous ne pouvez ajouter que des méthodes qui semblent être membres du type existant via des méthodes d'extension. Dans la mesure où c'est le cas, vous ne pouvez pas ajouter de méthodes statiques au type lui-même car les méthodes d'extension utilisent des instances de ce type.

Rien ne vous empêche de créer votre propre méthode d'assistance statique comme celle-ci:

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

Que vous utiliseriez comme ceci:

DateTime tomorrow = DateTimeHelper.Tomorrow;

6
hein woot? à moins que cela n'ait été mis en œuvre dans les 6 mois suivant cela et la réponse de Kumu ici, cela semble en fait incomplet!
cregox

4
@Cawas que ce n'est pas incomplet, Andrew montre comment faire cela avec un assistant statique, pas avec une méthode d'extension (car il n'y a pas d'instance).
Nick N.

1
Tu as raison, Nick. Je préfère cependant les méthodes d'extension! ;)
cregox


3
Le problème avec ce code est qu'il ne fonctionne que sur DateTime.Now et non sur n'importe quel objet DateTime. En tant qu'utilitaire, on peut vouloir l'utiliser pour déterminer le lendemain d'un jour précédent (ou futur). Sans parler de DateTime.Now est déterminé chaque fois que vous l'appelez ...
MintGrowth

181

Utilisez une méthode d'extension .

Ex:

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

Usage:

DateTime.Now.Tomorrow();

ou

AnyObjectOfTypeDateTime.Tomorrow();

2
La réponse de Shuggy a également éclairci une manière similaire de résoudre ce problème.
cregox

8
N'oubliez pas 'using ExtensionMethods;' en haut de votre document pour cela.
Luke Alderton

Pourquoi ne puis-je pas faire DateTime.Tomorrow ()?
lawphotog

Salut lawphotog, cette extension a besoin d'un objet, ici DateTime est une structure et non un objet.
Kumu

4
Comme mentionné dans les commentaires précédents (ce n'était pas assez clair pour moi apparemment), vous ne pourrez PAS utiliser DateTime.Tomorrow()comme extension les méthodes ne fonctionnent que sur les INSTANCES d'une classe et d'une structure de classe. Pour "étendre" une méthode statique sur une structure de classe, suivez la réponse d'Andrew ou celle de Shuggy .
Alex

18

Les méthodes d'extension sont du sucre syntaxique pour donner aux méthodes statiques dont le premier paramètre est une instance de type T une apparence de méthode d'instance sur T.

En tant que tel, l'avantage est largement perdu lorsque vous créez des `` méthodes d'extension statiques '' car elles serviraient à dérouter le lecteur du code encore plus qu'une méthode d'extension (car elles semblent être pleinement qualifiées mais ne sont pas réellement définies dans cette classe) pour aucun gain syntaxique (pouvoir enchaîner les appels dans un style fluide au sein de Linq par exemple).

Étant donné que vous devriez mettre les extensions dans la portée avec une utilisation de toute façon, je dirais qu'il est plus simple et plus sûr de créer:

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

Et puis utilisez ceci dans votre code via:

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

11

Le plus proche que je puisse obtenir de la réponse est d'ajouter une méthode d'extension dans un System.Typeobjet. Pas joli, mais toujours intéressant.

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

Sinon, IMO Andrew et ShuggyCoUk ont ​​une meilleure implémentation.


Il y a des problèmes avec cette approche. Devoir taper "typeof (...)" n'est pas pratique, et avec intellisense vous verriez des extensions de tous les types. Pourtant, c'est une approche intéressante à laquelle je n'avais pas pensé, +1.
Meta-Knight

@ Meta-Knight True, c'est pourquoi personnellement je préfère la réponse de l'autre. Ma réponse aurait la syntaxe la plus proche de la question OP, mais ce n'est pas la meilleure façon de résoudre ce problème.
Adrian Godong

Typepeut être remplacé par tout autre type requis. Je l'utilise avec Fromet ça marche parfaitement. donc je suppose que cette réponse est générale mais correcte
Katia

3

Je ferais la même chose que Kumu

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

mais appelez-le comme ce nouveau DateTime () .Tomorrow ();

Je pense que cela fait plus de vues que DateTime.Now.Tomorrow ();


1
Et vous avez manqué une chance de l'écrire comme un commentaire sur la réponse de Kumu! : P
cregox

3

Ils permettent d'étendre les types existants en ajoutant de nouvelles méthodes sans aucune modification nécessaire au type. L'appel de méthodes à partir d'objets de type étendu dans une application à l'aide de la syntaxe de méthode d'instance est connu sous le nom de méthodes «d'extension». Les méthodes d'extension ne sont pas des membres d'instance sur le type. Le point clé à retenir est que les méthodes d'extension, définies comme des méthodes statiques, ne sont dans la portée que lorsque l'espace de noms est explicitement importé dans le code source de votre application via la directive using. Même si les méthodes d'extension sont définies comme des méthodes statiques, elles sont toujours appelées à l'aide de la syntaxe d'instance.

Consultez l'exemple complet ici http://www.dotnetreaders.com/articles/Extension_methods_in_C-sharp.net,Methods_in_C_-sharp/201

Exemple:

class Extension
    {
        static void Main(string[] args)
        {
            string s = "sudhakar";
            Console.WriteLine(s.GetWordCount());
            Console.ReadLine();
        }

    }
    public static class MyMathExtension
    {

        public static int GetWordCount(this System.String mystring)
        {
            return mystring.Length;
        }
    }

3

Je cherchais quelque chose de similaire - une liste de contraintes sur les classes qui fournissent des méthodes d'extension. Cela semble difficile de trouver une liste concise, alors voici:

  1. Vous ne pouvez rien avoir de privé ou de protégé - champs, méthodes, etc.

  2. Ce doit être une classe statique, comme dans public static class....

  3. Seules les méthodes peuvent être dans la classe et elles doivent toutes être publiques statiques.

  4. Vous ne pouvez pas avoir de méthodes statiques conventionnelles - celles qui n'incluent pas cet argument ne sont pas autorisées.

  5. Toutes les méthodes doivent commencer:

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

Donc, le premier argument est toujours la référence this.

Cela crée un problème implicite - si vous ajoutez des méthodes qui nécessitent un verrou de quelque sorte que ce soit, vous ne pouvez pas vraiment le fournir au niveau de la classe. En règle générale, vous fourniriez un verrou privé au niveau de l'instance, mais il n'est pas possible d'ajouter des champs privés, vous laissant avec des options très gênantes, comme le fournir en tant que statique public sur une classe extérieure, etc. Panneaux le langage C # a eu un mauvais tour dans la conception de ceux-ci .

La solution de contournement consiste à utiliser votre classe de méthode d'extension comme une simple façade à une classe régulière, et toutes les méthodes statiques de votre classe d'extension appellent simplement la classe réelle, probablement en utilisant un Singleton .


2

Malheureusement, vous ne pouvez pas faire ça. Je pense cependant que ce serait utile. Il est plus naturel de taper:

DateTime.Tomorrow

que:

DateTimeUtil.Tomorrow

Avec une classe Util, vous devez vérifier l'existence d'une méthode statique dans deux classes différentes, au lieu d'une.


1

Nous avons amélioré notre réponse avec des explications détaillées.Maintenant, il est plus facile de comprendre la méthode d'extension

Méthode d'extension : C'est un mécanisme par lequel nous pouvons étendre le comportement d'une classe existante sans utiliser le sous-classement ou modifier ou recompiler la classe ou la structure d'origine.

Nous pouvons étendre nos classes personnalisées, nos classes de framework .net, etc.

La méthode d'extension est en fait un type spécial de méthode statique qui est définie dans la classe statique.

Comme la DateTimeclasse est déjà prise ci-dessus, nous n'avons donc pas pris cette classe pour l'explication.

Voici l'exemple

// Ceci est une classe de calculatrice existante qui n'a qu'une seule méthode (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)

    }
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.