2008-10-05 2 views
139

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

Вот синтаксис для создания метода расширения для 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 не допускается в данном контексте.

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

+3

Хотя это сначала кажется классной идеей, рассмотрите var otherSb = sb + "hi"; – hatchet 2012-06-08 19:24:01

ответ

121

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

Мадс Torgersen, C# Язык PM говорит:

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

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

Edit:

Я просто заметил, Мадс писал еще в same article:

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

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


This feature is currently on the table (potentially) for C# 8.0. Мадс говорит немного больше о его осуществлении here.

+4

Если у вас есть хорошие новости, любой комментарий здесь оценили. – pylover 2012-07-19 22:33:25

+0

Эта страница с тех пор снята; этот вопрос все еще не решен. – 2012-12-28 19:11:11

+12

Слишком плохо. Я просто хотел добавить оператора для умножения TimeSpan на скалярное значение ... :( – 2013-01-10 23:57:45

8

Оказывается это не возможно в настоящее время - есть открытый вопрос обратной связи с просьбой этой самой функции на Microsoft Connect:

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

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

50

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

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 класса объявляет implicit conversion operator от 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()); 

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

1

Хотя это не возможно сделать операторы, вы всегда можете просто создать Добавить (или Concat), вычитание и сравнение методов ....

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

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

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

0

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

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

Смежные вопросы