Surcharge d'opérateur avec les méthodes d'extension C #
-
05-07-2019 - |
Question
J'essaie d'utiliser des méthodes d'extension pour ajouter une surcharge d'opérateur à la classe C # StringBuilder
. Plus précisément, étant donné que StringBuilder
sb
, je voudrais que sb + = "texte" soit
devienne équivalent à sb.Append (" ; texte ")
.
Voici la syntaxe pour créer une méthode d'extension pour StringBuilder
:
public static class sbExtensions
{
public static StringBuilder blah(this StringBuilder sb)
{
return sb;
}
}
Il ajoute avec succès la méthode d'extension blah
au StringBuilder
.
Malheureusement, la surcharge de l'opérateur ne semble pas fonctionner:
public static class sbExtensions
{
public static StringBuilder operator +(this StringBuilder sb, string s)
{
return sb.Append(s);
}
}
Parmi les autres problèmes, le mot clé this
n'est pas autorisé dans ce contexte.
L’ajout de surcharges d’opérateurs via des méthodes d’extension est-il possible? Si oui, quelle est la bonne façon de s'y prendre?
La solution
Ceci n'est actuellement pas possible, car les méthodes d'extension doivent être dans des classes statiques et les classes statiques ne peuvent pas avoir de surcharge d'opérateur.
Mads Torgersen, c # langage PM déclare:
... pour la version Orcas, nous avons décidé de adopter une approche prudente et ajouter seulement des méthodes d'extension régulières, comme opposé aux propriétés d'extension, événements, opérateurs, méthodes statiques, etc. etc. Les méthodes d’extension habituelles étaient ce dont nous avions besoin pour LINQ, et ils avaient une conception syntaxiquement minimale ne pouvait pas être facilement imité pour certains des autres types de membres.
Nous prenons de plus en plus conscience que d'autres types de membres d'extension pourrait être utile, et donc nous reviendrons à cette question après Orcas. Non des garanties, cependant!
Modifier:
Je viens de remarquer que Mads a écrit davantage dans le même article :
Je suis désolé d'annoncer que nous ne le ferons pas faire cela dans la prochaine version. nous a pris très membres de l'extension sérieusement dans nos plans, et passé une beaucoup d'efforts essayant de les obtenir droit, mais à la fin nous ne pouvions pas obtenir assez lisse, et a décidé de donner chemin vers d'autres fonctionnalités intéressantes.
Ceci est toujours sur notre radar pour l'avenir communiqués. Ce qui aidera, c'est si nous obtenons une bonne quantité de scénarios convaincants cela peut aider à conduire le bon design.
Cette fonctionnalité est actuellement sur la table (potentiellement) pour le C # 8.0. Entretiens avec Mads un peu plus sur sa mise en œuvre ici .
Autres conseils
Si vous contrôlez les endroits où vous souhaitez utiliser cet " poste opérateur " (ce que vous faites normalement avec les méthodes d’extension de toute façon), vous pouvez faire quelque chose comme ceci:
class Program {
static void Main(string[] args) {
StringBuilder sb = new StringBuilder();
ReceiveImportantMessage(sb);
Console.WriteLine(sb.ToString());
}
// the important thing is to use StringBuilderWrapper!
private static void ReceiveImportantMessage(StringBuilderWrapper sb) {
sb += "Hello World!";
}
}
public class StringBuilderWrapper {
public StringBuilderWrapper(StringBuilder sb) { StringBuilder = sb; }
public StringBuilder StringBuilder { get; private set; }
public static implicit operator StringBuilderWrapper(StringBuilder sb) {
return new StringBuilderWrapper(sb);
}
public static StringBuilderWrapper operator +(StringBuilderWrapper sbw, string s) {
sbw.StringBuilder.Append(s);
return sbw;
}
}
La classe StringBuilderWrapper
déclare un opérateur de conversion implicite depuis un StringBuilder
et déclare l'opérateur +
souhaité. De cette façon, un StringBuilder
peut être passé à ReceiveImportantMessage
, qui sera converti silencieusement en un StringBuilderWrapper
, où +
opérateur peut être utilisé.
Pour rendre ce fait plus transparent pour les appelants, vous pouvez déclarer ReceiveImportantMessage
comme prenant un StringBuilder
et utiliser simplement le code suivant:
private static void ReceiveImportantMessage(StringBuilder sb) {
StringBuilderWrapper sbw = sb;
sbw += "Hello World!";
}
Ou, pour l'utiliser en ligne là où vous utilisez déjà un StringBuilder
, vous pouvez simplement faire ceci:
StringBuilder sb = new StringBuilder();
StringBuilderWrapper sbw = sb;
sbw += "Hello World!";
Console.WriteLine(sb.ToString());
J'ai créé un publication sur l'utilisation d'une approche similaire pour rendre IComparable
plus compréhensible.
Il semble que cela ne soit pas possible actuellement. Un problème de retour d'information demandant cette fonctionnalité sur Microsoft Connect a été ouvert:
http://connect.microsoft.com/VisualStudio/feedback/ ViewFeedback.aspx? FeedbackID = 168224
suggère qu'il apparaisse dans une version ultérieure, mais qu'il ne soit pas implémenté pour la version actuelle.
Même s’il n’est pas possible de faire les opérateurs, vous pouvez toujours créer des méthodes Add (ou Concat), Subtract, et Compare ....
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Whatever.Test
{
public static class Extensions
{
public static int Compare(this MyObject t1, MyObject t2)
{
if(t1.SomeValueField < t2.SomeValueField )
return -1;
else if (t1.SomeValueField > t2.SomeValueField )
{
return 1;
}
else
{
return 0;
}
}
public static MyObject Add(this MyObject t1, MyObject t2)
{
var newObject = new MyObject();
//do something
return newObject;
}
public static MyObject Subtract(this MyObject t1, MyObject t2)
{
var newObject= new MyObject();
//do something
return newObject;
}
}
}
Hah! Je cherchais & surcharge; surcharge de l'opérateur avec exactement le même désir, pour SB + = (chose).
Après avoir lu les réponses ici (et vu que la réponse est "non"), pour mes besoins particuliers, j’ai opté pour une méthode d’extension combinant sb.AppendLine et sb.AppendFormat, et qui a l’air plus soignée que les autres.
public static class SomeExtensions
{
public static void Line(this StringBuilder sb, string format, params object[] args)
{
string s = String.Format(format + "\n", args);
sb.Append(s);
}
}
Et oui,
sb.Line("the first thing is {0}",first);
sb.Line("the second thing is {0}", second);
Ce n’est pas une réponse générale, mais cela pourrait intéresser les futurs chercheurs qui se tournent vers ce genre de choses.
Il est possible de le gréer avec un wrapper et des extensions mais impossible de le faire correctement. Vous vous retrouvez avec des ordures qui vont totalement à l'encontre du but recherché. J'ai un message quelque part ici qui le fait, mais c'est nul.
Btw Toutes les conversions numériques créent des déchets dans le générateur de chaînes qui doivent être corrigés. J'ai dû écrire un emballage pour ce qui fonctionne et je l'utilise. Cela vaut la peine de le lire.