«This» dans le paramètre de fonction

88

En regardant quelques exemples de code pour HtmlHelpers, et je vois des déclarations qui ressemblent à:

public static string HelperName(this HtmlHelper htmlHelper, ...more regular params )

Je ne me souviens pas avoir vu ce type de construction nulle part ailleurs - quelqu'un peut-il expliquer le but du «ceci»? Je pensais qu'en déclarant quelque chose de public static signifiait que la classe n'avait pas besoin d'être instanciée - alors qu'est-ce que «ceci» dans ce cas?

Chris
la source

Réponses:

212

Il s'agit de la syntaxe de déclaration des méthodes d'extension, une nouvelle fonctionnalité de C # 3.0.

Une méthode d'extension est une partie code, une partie compilateur "magique", où le compilateur avec l'aide d'intellisense dans Visual Studio fait apparaître que votre méthode d'extension est réellement disponible comme méthode d'instance sur l'objet en question.

Laissez-moi vous donner un exemple.

Il n'y a pas de méthode sur la classe String nommée GobbleGobble, alors créons une méthode d'extension:

public static class StringExtensions
{
    public static void GobbleGobble(this string s)
    {
        Console.Out.WriteLine("Gobble Gobble, " + s);
    }
}

Le nom de la classe est juste ma convention de dénomination, il n'est pas nécessaire de le nommer comme ça, mais il doit être statique, tout comme la méthode.

Après avoir déclaré la méthode ci-dessus, vous pouvez, dans Visual Studio, taper ceci:

String s = "Turkey Baster!";
s.

après le point, attendez intellisense, et notez qu'il existe une méthode GobbleGobble, complétez le code comme ceci:

String s = "Turkey Baster!";
s.GobbleGobble();

Important : La classe dans laquelle la méthode d'extension est déclarée doit être disponible pour le compilateur et le processeur intellisense pour qu'intellisense affiche la méthode. Si vous tapez manuellement GobbleGobble et utilisez le raccourci Ctrl+ ., cela ne vous aidera pas à obtenir les bonnes directives d'utilisation dans le fichier.

Notez que le paramètre de la méthode a disparu. Le compilateur se déplacera silencieusement autour des bits importants, qui sont:

String s = "Turkey Baster!";
s.GobbleGobble();
^     ^
|     +-- the compiler will find this in the StringExtensions class
|
+-- will be used as the first parameter to the method

Ainsi, le code ci-dessus sera transformé par le compilateur en ceci:

String s = "Turkey Baster!";
StringExtensions.GobbleGobble(s);

Donc au moment de l'appel, il n'y a rien de magique, c'est juste un appel à une méthode statique.

Notez que si votre méthode d'extension déclare plus d'un paramètre, seul le premier prend en charge le thismodificateur, et le reste doit être spécifié dans le cadre de l'appel de méthode comme d'habitude:

public static void GobbleGobble(this string value, string extra)
{                                            |              |
    ...                                      |              |
}                                            |              |
                                             |              |
+--------------------------------------------+              |
|                                                           |
v                                                           |
s.GobbleGobble("extra goes here");                          |
                        ^                                   |
                        |                                   |
                        +-----------------------------------+

Les méthodes d'extension ont été ajoutées en partie à cause de Linq, où la syntaxe Linq de C # recherchera des méthodes d'extension correctement nommées pour les objets en jeu, ce qui signifie que vous pouvez "introduire" le support Linq dans n'importe quel type de classe en déclarant simplement la bonne extension méthodes. Bien sûr, la prise en charge complète de Linq demande beaucoup de travail, mais c'est possible.

De plus, les méthodes d'extension en elles-mêmes sont vraiment utiles, alors lisez-les.

Voici quelques liens:

Lasse V. Karlsen
la source
6
Je vais certainement commencer à utiliser le terme "Gobble Gobble Magic".
chris
Youtube a de nouveau rompu le lien, youtube.com/watch?v=Bz_heb9Rz2g , toujours à 1h00 et au-delà.
Lasse V. Karlsen
Ce genre de magie du compilateur rend difficile l'apprentissage d'une langue.
Don Dilanga
8

Après les méthodes d'extension, je les utilise comme un fou ... en voici quelques-unes que j'utilise constamment ...

public static T ChangeType<T>(this object obj)
{
  return (T)Convert.ChangeType(obj, typeof(T));
}

Fonctionne comme ça.

int i = "123".ChangeType<int>();
bool valid = "bool".ChangeType<bool>();
int id = dataSet.Tables[0].Rows[0]["Id"].ChangeType<int>();

Oui, cela apparaît sur chaque objet, peut être ennuyeux, mais comme je l'utilise pour à peu près tous les types de données, cela aide simplement de lui attacher un objet plutôt que de le dupliquer pour chaque type de données possible.

public static string ToXml(this object serializableObject)
{
    var aMemStr = new MemoryStream();
    try
    {
        var serializer = new XmlSerializer(serializableObject.GetType());
        serializer.Serialize(new XmlTextWriter(aMemStr, null), serializableObject);
        return Encoding.UTF8.GetString(aMemStr.ToArray());
    }
    finally { if (aMemStr != null) { aMemStr.Dispose(); } }
}

string xml = dataSet.ToXml();

public static T ToObject<T>(this string xmlString)
{
    var aStream = new MemoryStream(Encoding.UTF8.GetBytes(xmlString));
    try { return (T)new XmlSerializer(typeof(T)).Deserialize(aStream); }
    finally { if (aStream != null) { aStream.Dispose(); aStream = null; } }
}

DataSet dataSet = xml.ToObject<DataSet>();
jaekie
la source
6

Il est utilisé pour les méthodes d'extension. Fondamentalement, vous `` collez '' le Helpername à l'objet htmlHelper pour pouvoir dire:

new HtmlHelper().HelperName(...more regular params);
Henrik Gering
la source
4

Ce serait une méthode d'extension. Ils vous permettent "d'étendre" une classe via des méthodes statiques qui vivent en dehors de la classe d'origine.

Par exemple, disons que vous avez une méthode de chaîne utile que vous utilisez tout le temps ...

public int CountAllAs(string orig)
{
    return orig.ToLowerInvariant().ToArray().Count(c => c == 'a');
}

Et vous l'appelez ...

string allAs = "aaaA";
int count = CountAllAs(allAs);

Ce n'est pas si mal. Mais avec un petit changement, vous pourriez en faire une méthode d'extension et l'appel serait un peu plus joli:

public static int CountAllAs(this string orig)
{
    return orig.ToLowerInvariant().ToArray().Count(c => c == 'a');
}

Et puis appelez-le ...

string allAs = "aaaA";
int count = allAs.CountAllAs();
Justin Niessner
la source
3

Méthodes d'extensions ...

... sont un moyen fantastique d'inclure des fonctionnalités comme si vous utilisiez le modèle de décorateur , mais sans la douleur de refactoriser tout votre code ou d'utiliser un nom différent d'un type commun.

public static class Extensions
{
     public static string RemoveComma(this string value)
     {
         if (value == null) throw new ArgumentNullException("value");
        return value.Replace(",", "");
    }
}  

Vous pouvez donc utiliser ce code, n'importe où dans votre application.

Console.WriteLine(“Hello, My, Friend”.RemoveComma())

>> Hello My Friend

Ainsi, l' attribut this command signifie le type auquel l'extension sera "ajoutée" et vous permet de travailler avec la valeur comme si elle était passée en paramètre.

Fraga
la source