Перегрузка операторов методами расширения C # - PullRequest
163 голосов
/ 06 октября 2008

Я пытаюсь использовать методы расширения для добавления перегрузки оператора в класс C # StringBuilder. В частности, учитывая StringBuilder sb, я бы хотел, чтобы sb += "text" стал эквивалентным sb.Append("text").

Вот синтаксис для создания метода расширения для StringBuilder:

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

Он успешно добавляет метод расширения blah к StringBuilder.

К сожалению, перегрузка оператора не работает:

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

Среди прочих вопросов ключевое слово this в этом контексте недопустимо.

Возможно ли добавить перегрузки операторов с помощью методов расширения? Если да, то как правильно это сделать?

Ответы [ 6 ]

145 голосов
/ 06 октября 2008

В настоящее время это невозможно, поскольку методы расширения должны быть в статических классах, а статические классы не могут иметь перегрузки операторов.

Мадс Торгерсен, C # Language PM говорит:

... для релиза Orcas мы решили принять осторожный подход и добавить только обычные методы расширения, как в отличие от свойств расширения, события, операторы, статические методы и т. д. и т. д. что нам было нужно для LINQ, и у них было синтаксически минимальный дизайн, который не может быть легко подражать для некоторых других видов членов.

Мы все больше осознаем что другие виды членов расширения может быть полезным, и поэтому мы вернемся на этот вопрос после Orcas. нет гарантии, однако!

Edit:

Я только что заметил, Мэдс написал больше в той же статье :

Мне жаль сообщать, что мы не будем делать это в следующем выпуске. Мы действительно принял членов расширения очень серьезно в наших планах, и провел много усилий, пытаясь получить их верно, но в итоге мы не могли получить это достаточно гладко, и решил дать путь к другим интересным функциям.

Это все еще на нашем радаре для будущего релизы. Что поможет, если мы получим хорошее количество убедительных сценариев это может помочь создать правильный дизайн.


Эта функция в настоящее время находится на рассмотрении (потенциально) для C # 8.0. Мадс говорит немного больше о ее реализации здесь .

54 голосов
/ 03 февраля 2010

Если вы контролируете места, где вы хотите использовать этот «оператор расширения» (что вы обычно делаете с методами расширения), вы можете сделать что-то вроде этого:

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

} 

Класс StringBuilderWrapper объявляет оператор неявного преобразования из StringBuilder , а объявляет требуемый оператор +. Таким образом, StringBuilder может быть передан в ReceiveImportantMessage, который будет молча преобразован в StringBuilderWrapper, где может использоваться оператор +.

Чтобы сделать этот факт более прозрачным для вызывающих, вы можете объявить ReceiveImportantMessage как принимающий StringBuilder и просто использовать код, подобный этому:

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

Или, чтобы использовать его встроенным там, где вы уже используете StringBuilder, вы можете просто сделать это:

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

Я создал пост об использовании аналогичного подхода, чтобы сделать IComparable более понятным.

8 голосов
/ 06 октября 2008

Похоже, что это в настоящее время невозможно - существует проблема с открытым отзывом, запрашивающая эту функцию в Microsoft Connect:

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

предполагает, что он может появиться в будущем выпуске, но не реализован для текущей версии.

1 голос
/ 18 мая 2012

Несмотря на то, что это невозможно сделать операторы, вы всегда можете просто создать методы Add (или Concat), Subtract и 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;    
        }
    }


}
0 голосов
/ 28 января 2017

Его можно оснастить оберткой и расширениями, но невозможно сделать это правильно. Вы заканчиваете мусором, который полностью побеждает цель. У меня где-то здесь есть пост, который делает это, но это бесполезно.

Btw Все числовые преобразования создают мусор в строителе строк, который необходимо исправить. Я должен был написать обертку для того, что работает, и я использую ее. Это стоит изучить.

0 голосов
/ 28 июня 2014

Хах! Я искал "перегрузку оператора расширения" с точно таким же желанием для sb + = (вещь).

Прочитав ответы здесь (и увидев, что ответ «нет»), я выбрал для себя метод расширения, который комбинирует sb.AppendLine и sb.AppendFormat и выглядит более аккуратно, чем любой из них.

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

}

И так,

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

Не общий ответ, но может быть интересен будущим искателям, которые смотрят на подобные вещи.

...