c# - sobreescritura - sobrecarga de metodos en programacion orientada a objetos
Sobrecarga del operador con métodos de extensión C# (6)
Estoy intentando usar métodos de extensión para agregar una sobrecarga de operador a la clase C # StringBuilder
. Específicamente, dado StringBuilder
sb
, me gustaría que sb += "text"
sea equivalente a sb.Append("text")
.
Aquí está la sintaxis para crear un método de extensión para StringBuilder
:
public static class sbExtensions
{
public static StringBuilder blah(this StringBuilder sb)
{
return sb;
}
}
Agrega con éxito el método de extensión blah
a StringBuilder
.
Desafortunadamente, la sobrecarga del operador no parece funcionar:
public static class sbExtensions
{
public static StringBuilder operator +(this StringBuilder sb, string s)
{
return sb.Append(s);
}
}
Entre otros problemas, la palabra clave this
no está permitida en este contexto.
¿Es posible agregar sobrecargas del operador a través de métodos de extensión? Si es así, ¿cuál es la forma correcta de hacerlo?
Aunque no es posible hacer los operadores, siempre puedes simplemente crear los métodos Add (o Concat), Substract y 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;
}
}
}
Es posible colgarlo con un envoltorio y extensiones pero imposible hacerlo correctamente. Usted termina con basura que totalmente derrota el propósito. Tengo un mensaje en algún lado aquí que lo hace, pero es inútil.
Por cierto, todas las conversiones numéricas crean basura en el generador de cadenas que debe corregirse. Tuve que escribir un contenedor para eso que funciona y lo uso. Eso vale la pena leerlo.
Esto no es posible actualmente, porque los métodos de extensión deben estar en clases estáticas, y las clases estáticas no pueden tener sobrecargas de operador.
Mads Torgersen, C # Language PM dice:
... para el lanzamiento de Orcas decidimos tomar el enfoque cauteloso y agregar solo métodos de extensión regulares, en oposición a las propiedades de extensión, eventos, operadores, métodos estáticos, etc. etc. Los métodos de extensión regular eran lo que necesitábamos para LINQ, y tenían un diseño sintácticamente mínimo que no se podía imitar fácilmente para algunos de los otros tipos de miembros.
Estamos cada vez más conscientes de que otros tipos de miembros de extensión podrían ser útiles, por lo que volveremos sobre este tema después de Orcas. ¡Sin garantías, sin embargo!
Editar:
Me acabo de dar cuenta, Mads escribió más en el mismo artículo :
Lamento informar que no haremos esto en el próximo lanzamiento. Nos tomamos muy en serio a los miembros de la extensión en nuestros planes, y nos esforzamos mucho para tratar de hacerlo bien, pero al final no pudimos hacerlo lo suficientemente fluido y decidimos ceder el paso a otras características interesantes.
Esto todavía está en nuestro radar para lanzamientos futuros. Lo que ayudará es si obtenemos una buena cantidad de escenarios convincentes que pueden ayudar a impulsar el diseño correcto.
Esta característica está actualmente en la mesa (potencialmente) para C # 8.0. Mads habla un poco más sobre implementarlo here .
Hah! Estaba buscando "sobrecarga del operador de extensión" exactamente con el mismo deseo, para sb + = (cosa).
Después de leer las respuestas aquí (y ver que la respuesta es "no"), para mis necesidades particulares, opté por un método de extensión que combina sb.AppendLine y sb.AppendFormat, y se ve más ordenado que cualquiera de los dos.
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);
}
}
Y entonces,
sb.Line("the first thing is {0}",first);
sb.Line("the second thing is {0}", second);
No es una respuesta general, pero puede ser de interés para los futuros buscadores que miran este tipo de cosas.
Parece que esto no es posible actualmente: hay un problema de comentarios abiertos que solicita esta característica en Microsoft Connect:
http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=168224
sugiriendo que podría aparecer en una versión futura pero no se implementa para la versión actual.
Si controla los lugares donde desea utilizar este "operador de extensión" (que normalmente hace con los métodos de extensión de todos modos), puede hacer algo como esto:
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 clase StringBuilderWrapper
declara un operador de conversión implícito de un StringBuilder
y declara el operador +
deseado. De esta forma, un StringBuilder
se puede pasar a ReceiveImportantMessage
, que se convertirá silenciosamente a StringBuilderWrapper
, donde se puede usar el operador +
.
Para que este hecho sea más transparente para las personas que llaman, puede declarar que ReceiveImportantMessage
toma un StringBuilder
y simplemente use un código como este:
private static void ReceiveImportantMessage(StringBuilder sb) {
StringBuilderWrapper sbw = sb;
sbw += "Hello World!";
}
O bien, para usarlo en línea donde ya está usando un StringBuilder
, simplemente puede hacer esto:
StringBuilder sb = new StringBuilder();
StringBuilderWrapper sbw = sb;
sbw += "Hello World!";
Console.WriteLine(sb.ToString());
Creé una publicación sobre el uso de un enfoque similar para hacer que IComparable
más comprensible.