Перегрузка операторов с помощью методов расширения C#

StackOverflow https://stackoverflow.com/questions/172658

Вопрос

Я пытаюсь использовать методы расширения, чтобы добавить перегрузку оператора в С#. 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 в данном контексте не допускается.

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

Это было полезно?

Решение

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

Мадс Торгерсен, руководитель проекта по языку C#, говорит:

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

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

Редактировать:

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

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

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


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

Другие советы

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

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 более понятным.

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

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

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

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


}

Ха!Я искал «перегрузку оператора расширения» с точно таким же желанием, для 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);

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top