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 ailleurs - quelqu'un peut-il expliquer le but du "ceci"? Je pensais qu'en déclarant quelque chose de public statique, cela signifiait que la classe n'avait pas besoin d'être instanciée - alors qu'est-ce que "ceci" dans ce cas?
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 un code partiel, un compilateur partiel "magique", où le compilateur à l'aide d'intellisense dans Visual Studio fait apparaître que votre méthode d'extension est réellement disponible en tant que 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 classe est juste ma convention de nommage, 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 l'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 saisissez GobbleGobble manuellement et utilisez le Ctrl+. raccourci, il 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éplace 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 modificateur this
, et le reste doit être spécifié comme faisant partie 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 grâce à 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 représente 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:
Après les méthodes d'extension, je les utilise comme des fous .. 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 j'utilise cela 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>();
Il est utilisé pour les méthodes d'extension. Fondamentalement, vous "collez" le nom d'utilisateur à l'objet htmlHelper pour pouvoir dire:
new HtmlHelper().HelperName(...more regular params);
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, supposons que vous ayez 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 ça ...
string allAs = "aaaA";
int count = allAs.CountAllAs();
... sont un moyen fantastique d'inclure des fonctionnalités comme si vous utilisiez le motif décorateur , mais sans la peine 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 de commande cet 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.