Перегрузка оператора с помощью методов расширения С#
Я пытаюсь использовать методы расширения для добавления перегрузки оператора в класс С# 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
не допускается в этом контексте.
Возможно ли добавление перегрузок операторов через методы расширения? Если да, то каков правильный способ сделать это?
Ответы
Ответ 1
В настоящее время это невозможно, поскольку методы расширения должны быть в статических классах, а статические классы не могут иметь перегрузки оператора.
Mads Torgersen, С# Language PM говорит:
... для выпуска Orcas мы решили принять осторожный подход и добавить только регулярные методы расширения, так как противоположные свойствам расширения, события, операторы, статические методы и т.д. и т.д. Регулярные методы расширения что нам нужно для LINQ, и они синтаксически минимальный дизайн, который нельзя было легко подражать других видов участников.
Мы все больше осознаем что другие виды членов расширения может быть полезным, и поэтому мы вернемся к этому вопросу после Орки. нет гарантии, хотя!
Edit:
Я только что заметил, Mads написал больше в той же статье:
Мне жаль сообщить, что мы не будем сделайте это в следующем выпуске. Мы действительно принимали серьезно в наших планах, и провел много усилий, пытаясь получить их право, но в итоге мы не смогли получить он достаточно гладко и решил дать путь к другим интересным особенностям.
Это все еще на нашем радаре для будущего релизы. Что поможет, если мы получим достаточное количество убедительных сценариев что может помочь управлять правильным дизайном.
Эта функция в настоящее время находится в таблице (потенциально) для С# 8.0. Mads говорит немного больше о ее реализации здесь.
Ответ 2
Если вы управляете местами, где вы хотите использовать этот "оператор расширения" (который вы обычно делаете с методами расширения), вы можете сделать что-то вроде этого:
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
более понятным.
Ответ 3
Кажется, что в настоящее время это невозможно - существует проблема с обратной связью, запрашивающая эту функцию в Microsoft Connect:
http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=168224
предполагая, что он может появиться в будущей версии, но не реализован для текущей версии.
Ответ 4
Хотя это невозможно сделать операторам, вы всегда можете просто создавать методы 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;
}
}
}
Ответ 5
Хах! Я искал "перегрузку оператора расширения" с точно таким же желанием, для 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);
Не общий ответ, но может представлять интерес для будущих искателей, рассматривающих такие вещи.
Ответ 6
Возможно его оснастить оболочкой и расширениями, но сделать это невозможно. Вы заканчиваете мусором, который полностью побеждает цель.
У меня есть почта где-то здесь, что делает это, но его ничего не стоит.
Btw
Все числовые преобразования создают мусор в построителе строк, который необходимо исправлять. Мне пришлось написать оболочку для того, что работает, и я использую ее. Это заслуживает внимания.