Domanda

Sto tentando di utilizzare metodi di estensione per aggiungere un sovraccarico dell'operatore alla classe C # StringBuilder . In particolare, dato StringBuilder sb , vorrei che sb + = " text " diventasse equivalente a sb.Append (" ; il testo ".)

Ecco la sintassi per la creazione di un metodo di estensione per StringBuilder :

public static class sbExtensions
{
    public static StringBuilder blah(this StringBuilder sb)
    {
        return sb;
    }
} 

Aggiunge correttamente il metodo di estensione blah a StringBuilder .

Sfortunatamente, il sovraccarico dell'operatore non sembra funzionare:

public static class sbExtensions
{
    public static StringBuilder operator +(this StringBuilder sb, string s)
    {
        return sb.Append(s);
    }
} 

Tra le altre questioni, la parola chiave this non è consentita in questo contesto.

È possibile aggiungere sovraccarichi all'operatore tramite metodi di estensione? In tal caso, qual è il modo corretto di procedere?

È stato utile?

Soluzione

Questo non è attualmente possibile, poiché i metodi di estensione devono essere in classi statiche e le classi statiche non possono avere sovraccarichi dell'operatore.

Mads Torgersen, C # Language PM dice:

  

... per la versione di Orcas abbiamo deciso di farlo   adottare un approccio cauto e aggiungere   solo metodi di estensione regolari, come   al contrario delle proprietà di estensione,   eventi, operatori, metodi statici, ecc   ecc. I metodi di estensione regolari erano   ciò di cui avevamo bisogno per LINQ e loro avevano   un design sintatticamente minimale che   non potrebbe essere facilmente imitato per alcuni   degli altri membri.

     

Stiamo diventando sempre più consapevoli   che altri tipi di membri di estensione   potrebbe essere utile, e così torneremo   a questo problema dopo Orcas. No   garanzie, però!

Modifica:

Ho appena notato, Mads ha scritto di più nello stesso articolo :

  

Mi dispiace segnalare che non lo faremo   fare questo nella prossima versione. Noi   ha preso molto i membri dell'estensione   seriamente nei nostri piani e speso a   molto sforzo nel tentativo di ottenerli   giusto, ma alla fine non siamo riusciti a ottenere   è abbastanza liscio, e ha deciso di dare   modo per altre caratteristiche interessanti.

     

Questo è ancora sul nostro radar per il futuro   stampa. Ciò che sarà di aiuto è se otteniamo   una buona quantità di scenari avvincenti   che può aiutare a guidare il design giusto.


Questa funzione è attualmente disponibile (potenzialmente) per C # 8.0. Mads talk un po 'di più sull'implementazione qui .

Altri suggerimenti

Se controlli i luoghi in cui desideri utilizzare questo "operatore di estensione" (che normalmente esegui comunque con i metodi di estensione), puoi fare qualcosa del genere:

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 dichiara un operatore di conversione implicita da un StringBuilder e dichiara l'operatore + desiderato. In questo modo, StringBuilder può essere passato a ReceiveImportantMessage , che verrà silenziosamente convertito in StringBuilderWrapper , dove + operatore può essere utilizzato.

Per rendere questo fatto più trasparente per i chiamanti, puoi dichiarare ReceiveImportantMessage come prendere un StringBuilder e usare un codice come questo:

  private static void ReceiveImportantMessage(StringBuilder sb) {
    StringBuilderWrapper sbw = sb;
    sbw += "Hello World!";
  }

Oppure, per usarlo in linea dove stai già usando un StringBuilder , puoi semplicemente farlo:

 StringBuilder sb = new StringBuilder();
 StringBuilderWrapper sbw = sb;
 sbw += "Hello World!";
 Console.WriteLine(sb.ToString());

Ho creato un post sull'utilizzo di un approccio simile a rendere IComparable più comprensibile.

Sembra che questo non sia attualmente possibile - c'è un problema di feedback aperto che richiede questa funzionalità su Microsoft Connect:

http://connect.microsoft.com/VisualStudio/feedback/ ViewFeedback.aspx? FeedbackID = 168.224

suggerendo che potrebbe apparire in una versione futura ma non è implementato per la versione corrente.

Sebbene non sia possibile eseguire gli operatori, è sempre possibile creare i metodi Aggiungi (o Concat), Sottrai e Confronta ....

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! Stavo cercando "sovraccarico dell'operatore di estensione" con esattamente lo stesso desiderio, per sb + = (cosa).

Dopo aver letto le risposte qui (e visto che la risposta è "no"), per le mie esigenze particolari, sono andato con un metodo di estensione che combina sb.AppendLine e sb.AppendFormat e sembra più ordinato di entrambi.

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

}

E così,

sb.Line("the first thing is {0}",first);
sb.Line("the second thing is {0}", second);

Non è una risposta generale, ma può essere di interesse per i futuri ricercatori che guardano questo tipo di cose.

È possibile rigg con un involucro ed estensioni ma impossibile farlo correttamente. Finisci con la spazzatura che sconfigge totalmente lo scopo. Ho un post qui da qualche parte che lo fa, ma è inutile.

Btw Tutte le conversioni numeriche creano immondizia nel generatore di stringhe che deve essere corretto. Ho dovuto scrivere un wrapper per quello che funziona e lo uso. Vale la pena esaminarlo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top