webentwicklung-frage-antwort-db.com.de

Operatorüberladung mit C # -Erweiterungsmethoden

Ich versuche, Erweiterungsmethoden zu verwenden, um der Klasse C # StringBuilder eine Operatorenüberladung hinzuzufügen. Bei StringBuildersb möchte ich, dass sb += "text"sb.Append("text") entspricht.

Hier ist die Syntax zum Erstellen einer Erweiterungsmethode für StringBuilder:

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

Die Erweiterungsmethode blah wurde erfolgreich zu StringBuilder hinzugefügt.

Leider scheint das Überladen von Operatoren nicht zu funktionieren:

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

Unter anderem ist das Schlüsselwort this in diesem Zusammenhang nicht zulässig.

Sind das Hinzufügen von Operatorüberladungen über Erweiterungsmethoden möglich? Wenn ja, wie ist die richtige Vorgehensweise?

165
Jude Allred

Dies ist derzeit nicht möglich, da Erweiterungsmethoden in statischen Klassen vorliegen müssen und statische Klassen keine Operatorüberladungen aufweisen können.

Mads Torgersen, C # Sprache PM sagt:

... für das Orcas-Release entschieden wir uns, vorsichtig vorzugehen und nur reguläre Erweiterungsmethoden hinzuzufügen, im Gegensatz zu Erweiterungseigenschaften, Ereignissen, Operatoren, statischen Methoden usw. Für LINQ benötigten wir reguläre Erweiterungsmethoden Ein syntaktisch minimales Design, das für einige der anderen Mitgliedsarten nicht einfach nachzuahmen ist.

Wir werden uns zunehmend bewusst, dass andere Arten von Erweiterungsmitgliedern nützlich sein könnten, und werden daher nach Orcas auf dieses Problem zurückkommen. Keine Garantie!

Bearbeiten:

Mir ist gerade aufgefallen, Mads hat im selben Artikel mehr geschrieben:

Es tut mir leid, Ihnen mitteilen zu müssen, dass wir dies in der nächsten Version nicht tun werden. Wir haben die Erweiterungsmitglieder in unseren Plänen sehr ernst genommen und viel Mühe darauf verwendet, sie in Ordnung zu bringen, aber am Ende konnten wir es nicht glatt genug hinbekommen und beschlossen, anderen interessanten Funktionen Platz zu machen.

Dies ist immer noch auf unserem Radar für zukünftige Versionen. Was helfen wird, ist, wenn wir eine Menge überzeugender Szenarien erhalten, die helfen können, das richtige Design zu entwickeln.


Diese Funktion ist derzeit (möglicherweise) für C # 8.0 auf dem Tisch. Mads spricht hier etwas mehr über die Implementierung .

147
Jacob Krall

Wenn Sie die Stellen steuern, an denen Sie diesen "Erweiterungsoperator" verwenden möchten (was Sie normalerweise sowieso mit Erweiterungsmethoden tun), können Sie Folgendes tun:

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

} 

Die Klasse StringBuilderWrapper deklariert einen impliziten Konvertierungsoperator aus einem StringBuilder und deklariert den gewünschten + Operator. Auf diese Weise kann ein StringBuilder an ReceiveImportantMessage übergeben werden, das stillschweigend in ein StringBuilderWrapper konvertiert wird, in dem das + Operator kann verwendet werden.

Um diese Tatsache für Anrufer transparenter zu machen, können Sie ReceiveImportantMessage als StringBuilder deklarieren und einfach den folgenden Code verwenden:

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

Oder, um es inline zu verwenden, wo Sie bereits ein StringBuilder verwenden, können Sie dies einfach tun:

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

Ich habe einen Beitrag über die Verwendung eines ähnlichen Ansatzes erstellt, um IComparable verständlicher zu machen.

55
Jordão

Dies ist anscheinend derzeit nicht möglich. Es gibt ein offenes Feedback-Problem, bei dem genau diese Funktion in Microsoft Connect angefordert wird:

http://connect.Microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=168224

ein Hinweis darauf, dass es in einer zukünftigen Version erscheinen könnte, aber für die aktuelle Version nicht implementiert ist.

8
Dylan Beattie

Hah! Ich habe mit genau dem gleichen Wunsch nach "Extension Operator Overloading" gesucht, für sb + = (thing).

Nachdem ich die Antworten hier gelesen hatte (und festgestellt hatte, dass die Antwort "Nein" lautet), entschied ich mich für eine Erweiterungsmethode, die sb.AppendLine und sb.AppendFormat kombiniert und ordentlicher aussieht als beide.

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

}

Und so,

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

Keine generelle Antwort, kann aber für zukünftige Suchende von Interesse sein, die sich solche Dinge ansehen.

1
david van brink

Obwohl es nicht möglich ist, die Operatoren auszuführen, können Sie immer nur die Methoden Add (oder Concat), Subtract und Compare erstellen.

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


}
1
Chuck Rostance

Es ist möglich, es mit einem Wrapper und Erweiterungen zu versehen, aber es ist unmöglich, es richtig zu machen. Sie enden mit Müll, der den Zweck völlig zunichte macht. Ich habe irgendwo hier oben einen Post, der das macht, aber es ist wertlos.

Übrigens: Bei allen numerischen Konvertierungen entsteht im Zeichenfolgengenerator ein Fehler, der behoben werden muss. Ich musste einen Wrapper für das schreiben, was funktioniert und ich benutze es. Das ist es wert, durchgesehen zu werden.

0
will motil