Можно ли определить метод оператора расширения? - PullRequest
12 голосов
/ 02 апреля 2011

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

   somestring++;  //i really know that this string contains a numeric value

И я не хочу распространять преобразования типов для всего кода.Я знаю, что могу создать класс-оболочку над строкой и определить этот оператор, но я хочу знать, возможно ли подобное, чтобы избежать поиска и замены каждого объявления строки на MySpecialString.скажем, строка запечатана, поэтому деривация невозможна, поэтому я изменяю «производный» на «обертку», моя ошибка.

Ответы [ 9 ]

8 голосов
/ 02 апреля 2011

Это невозможно в C #, но почему бы не использовать стандартный метод расширения?

 public static class StringExtensions {
     public static string Increment(this string s) {
          ....
     }
 }

Я думаю, somestring.Increment() еще более читабельно, поскольку вы не путаете людей, которые действительно не ожидают увидеть++ применяется к строке.

5 голосов
/ 26 августа 2014

Яркий пример того, где это было бы полезно, - возможность расширить класс 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);
    }

}
5 голосов
/ 02 апреля 2011

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

Определенные пользователем объявления операторов всегда требуют, чтобы хотя бы один из параметров имел класс или структурный тип, содержащий объявление оператора. [7.3.2]

Поэтому метод расширения также не может быть перегруженным оператором.

Кроме того, вы не можете переопределить System.String , поскольку это запечатанный класс.

5 голосов
/ 02 апреля 2011

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

2 голосов
/ 02 апреля 2011

Строковый класс запечатан в C #, поэтому создание строкового класса на самом деле невозможно .

При этом метод расширения, конечно, будет прекрасно работать (как и стандартный статический метод в классе помощника), но это не будет оператор, просто метод с обычным именем.

1 голос
/ 11 июня 2013

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

//i really know that this string contains a numeric value

- это именно та ситуация, в которой была изобретена безопасность типов.for.

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

1 голос
/ 17 марта 2012

Это все правда, но было бы неплохо, чтобы M $ добавил эту функциональность в будущем. Иногда в фреймворке просто чего-то не хватает, и расширение может помочь устранить пробел (или исправить проблему), иногда это могут быть операторы.

Пример. Чтобы сравнивать IP-адреса, вы должны использовать метод Equals для прямого сравнения (конечно, части структуры также можно сравнивать, как и байты адреса по отдельности - но это уже другая история). Однако использование оператора == всегда возвращает false на уровне объекта (то есть без преобразования их в строки и т. Д.). Насколько сложно поместить вызов метода Equals в вызов оператора == (это риторически), но мы не можем этого сделать. Это несовместимо и является местом, где могут появляться ошибки (обратите внимание, что это не ошибка, просто всегда равно false - тогда как Equals - нет).

1 голос
/ 02 апреля 2011

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

0 голосов
/ 14 июля 2017

Я был в очень похожей ситуации, как вы описали: мне нужно было увеличить текст (точно содержащий числовое значение) в текстовом поле Windows Forms.

Я понимаю ваши потребности, как вы описали

somestring ++;// я действительно знаю, что эта строка содержит числовое значение

Моя душа похожа на ту, которая, как я считаю, близка вашему описанию

somestring = (incrementaltable) somestring+ 1

Все, что мне нужно было сделать, это

  1. создать класс с именем incrementable
  2. , определив в нем явный оператор (чтобы помочь преобразованию string to incrementable)
  3. определение неявного оператора в нем (чтобы помочь преобразованию incrementable обратно в string)
  4. оператора для + (знак плюс)

Вот как выглядит мой класс полностью

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, следовательно, не может быть результатом этого преобразования.

В любом случае, надеюсь, это поможет!

...