Возможно ли определить метод оператора расширения?
Можно ли определить метод расширения, который в то же время является оператором?
Я хочу, чтобы фиксированный класс добавлял возможность использовать известный оператор, который фактически не может быть применен.
Для этого конкретного случая я хочу сделать это:
somestring++; //i really know that this string contains a numeric value
И я не хочу распространять типы конверсий для всего кода.
Я знаю, что я мог бы создать класс-оболочку над строкой и определить этот оператор, но я хочу знать, возможно ли подобное, чтобы избежать поиска и замены каждого объявления строки с помощью MySpecialString.
Отредактировано: поскольку большинство из них говорят, что строка запечатана, поэтому вывод невозможен, поэтому я изменяю "полученный" на "обертку", свою ошибку.
Ответы
Ответ 1
Нет, это невозможно сделать из-за пределов класса. Оператор ++
должен быть определен внутри класса, который увеличивается. Вы можете создать свой собственный класс, который будет конвертирован из строки и будет иметь перегрузку ++
, или вы можете забыть об этой идее и использовать обычные методы.
Ответ 2
Это невозможно в С#, но почему не стандартный метод расширения?
public static class StringExtensions {
public static string Increment(this string s) {
....
}
}
Я думаю, что somestring.Increment()
еще более читабельна, так как вы не путаете людей, которые действительно не ожидали увидеть ++
применительно к строке.
Ответ 3
Ярким примером того, где это было бы полезно, является возможность расширения класса TimeSpan для включения * и/операторов.
Это то, что идеально работает...
public static class TimeSpanHelper
{
public static TimeSpan operator *(TimeSpan span, double factor)
{
return TimeSpan.FromMilliseconds(span.TotalMilliseconds * factor);
}
public static TimeSpan operator *(double factor, TimeSpan span) // * is commutative
{
return TimeSpan.FromMilliseconds(span.TotalMilliseconds * factor);
}
public static TimeSpan operator /(TimeSpan span, double sections)
{
return TimeSpan.FromMilliseconds(span.TotalMilliseconds / factor);
}
public static double operator /(TimeSpan span, TimeSpan period)
{
return span.TotalMilliseconds / period.TotalMilliseconds);
}
}
Ответ 4
Нет, у вас не может быть метода расширения, который также является оператором. Методы расширения могут быть объявлены только в статических классах, которые не могут иметь экземпляры и в соответствии с спецификацией С#,
Пользовательские декларации операторов всегда требуют, чтобы хотя бы один из параметров имел тип класса или структуры, содержащий декларацию оператора. [7.3.2]
Следовательно, метод расширения также не может быть перегруженным оператором.
Кроме того, вы не можете переопределить System.String, так как это запечатанный класс.
Ответ 5
Строковый класс запечатан в С#, поэтому создание производного по строкам класса фактически невозможно.
Говоря, что метод расширения, конечно, будет работать очень хорошо (как и стандартный статический метод в классе-помощнике), но он не будет оператором, просто обычным методом.
Ответ 6
В настоящее время это не поддерживается, потому что методы расширения определены в отдельном статическом классе, а статические классы не могут иметь переопределения операторов.
Ответ 7
Это все правда, но было бы неплохо, если бы M $добавила эту функциональность в будущем. Иногда в структуре просто отсутствуют вещи, и расширение может помочь подключить разрыв (или устранить проблему), иногда это могут быть операторы.
Пример. Чтобы сравнить IP-адреса, вы должны использовать метод Equals для прямого сравнения (конечно, части структуры также можно сравнить, как и байты адреса отдельно, но это другая история). Однако использование оператора == всегда возвращает false на уровне объекта (т.е. Не преобразовывая их в строки и т.д.). Как трудно помещать вызов метода Equals внутри вызова оператора == (это риторический), но мы не можем этого сделать. Это непоследовательно и место для ошибок в ползучести (обратите внимание, что это не подводит, просто всегда приравнивается к false, а Equals - нет).
Ответ 8
Я бы сказал, что вы должны использовать класс-оболочку, даже если вы могли бы написать оператор расширения.
//i really know that this string contains a numeric value
- это именно та ситуация, в которой была изобретена безопасность типа.
Другой способ взглянуть на это состоит в том, что, написав этот оператор, вы нарушили множество других функций и операторов, которые работают с классом string
, поскольку они не обязательно сохраняют свойство содержать числовое значение. Используя класс-оболочку, а не производный класс, вы только повторно реализуете те функции string
, которые имеют смысл для числовых строк.
Ответ 9
i был в очень похожей ситуации, описанной вами: мне нужно было увеличить текст (с уверенным числовым значением) в текстовом поле Windows Forms.
Я понимаю вашу потребность, как вы описали
SomeString++;//Я действительно знаю, что эта строка содержит числовое значение
Моя душа - это что-то вроде того, что, по моему мнению, близко к вашему описанию
somestring = (incrementable) somestring + 1
Все, что мне нужно было сделать, это
- создание класса
incrementable
- определяющий в нем явный оператор (чтобы преобразовать
string
в incrementable
)
- определение неявного оператора в нем (чтобы преобразовать
incrementable
обратно в string
)
- для
+
(знак плюс)
Вот как мой класс выглядит полностью
public class incrementable
{
public string s; // For storing string value that holds the number
public incrementable(string _s)
{
s = _s;
}
public static explicit operator incrementable(string tmp)
{
return new incrementable(tmp);
}
public static implicit operator string(incrementable tmp)
{
return tmp.s;
}
public static incrementable operator +(incrementable str, int inc) // This will work flawlessly like `somestring = (incrementable)somestring + 1`
=> new incrementable((Convert.ToInt32(str.s) + inc).ToString());
public static incrementable operator ++(incrementable str) // Unfortunately won't work, see below
=> new incrementable((Convert.ToInt32(str.s) + 1).ToString());
}
К сожалению, мне просто не удалось улучшить мой класс с помощью унарного оператора ++
. Причиной против использования неявного преобразования, такого как ((incrementable)somestring)++
, является то, что он приведет к ошибке, говоря The operand of an increment or decrement operator must be a variable, property or indexer
, следовательно, не может быть результатом этого каста.
В любом случае, надеюсь, что это поможет!
Ответ 10
Как показано в других ответах, это нельзя сделать напрямую. Но что, если вам это нужно, скажем, вы хотите улучшить StringBuilder как
void Main()
{
var log = (StringBuilder)"Hello ";
log += "World!";
log += "\nThis example shows how to extend StringBuilder";
log.ToString().Dump();
}
как этого добиться (т.е. использовать оператор +
вместо sb.Append(str);
)?
Ответ:
В этом случае вы не можете сделать это напрямую, но вы можете сделать следующее:
Запустите его в DotNetFiddle
void Main()
{
var log = (StrBuilder)"Hello "; // same as: "Hello ".ToStrBuilder();
log += "World!";
log += "\nThis example shows how to extend StringBuilder";
log.ToString().Dump();
}
public static class Extensions
{
public static StrBuilder ToStrBuilder(this string str)
{
return new StrBuilder(str);
}
}
public class StrBuilder
{
private StringBuilder sb;
public StrBuilder()
{
sb = new StringBuilder();
}
public StrBuilder(string strB)
{
sb = new StringBuilder(strB);
}
public static implicit operator StrBuilder(string self)
{
return new StrBuilder(self);
}
public static StrBuilder operator +(StrBuilder sbA, string strB)
{
return sbA.Append(strB);
}
public StrBuilder Append(string strB)
{
sb.Append(strB);
return this;
}
public override string ToString()
{
return sb.ToString();
}
}
Примечание: Вы не можете наследовать от StringBuilder, потому что это запечатанный класс, но вы можете написать класс, который "упаковывает" StringBuilder, то есть, что здесь делается (благодаря ответу IanNorton относительно неявного преобразования).