Ескертпе
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Жүйеге кіруді немесе каталогтарды өзгертуді байқап көруге болады.
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Каталогтарды өзгертуді байқап көруге болады.
Определяемый пользователем тип может перегружать предопределенный оператор C#. То есть тип может предоставить пользовательскую реализацию операции в случае одного или обоих операндов этого типа. В разделе "Перегруженные операторы" показано, какие операторы C# можно перегружать.
Используйте ключевое operator слово для объявления оператора. Объявление оператора должно соответствовать следующим правилам:
- Он включает
publicмодификатор. - Унарный оператор имеет один входной параметр. Двоичный оператор имеет два входных параметра. В каждом случае по крайней мере один параметр должен иметь тип
TилиT?, гдеT— это тип, содержащий объявление оператора. - Он включает
staticмодификатор, за исключением операторов составных назначений, таких как+=. - Операторы инкремента (
++) и декремента (--) можно реализовать как статические или экземплярные методы. Операторы методов экземпляра — это новая функция, представленная в C# 14.
В следующем примере определяется упрощенная структура для представления рационального числа. Структура перегружает некоторые арифметические операторы:
public struct Fraction
{
private int numerator;
private int denominator;
public Fraction(int numerator, int denominator)
{
if (denominator == 0)
{
throw new ArgumentException("Denominator cannot be zero.", nameof(denominator));
}
this.numerator = numerator;
this.denominator = denominator;
}
public static Fraction operator +(Fraction operand) => operand;
public static Fraction operator -(Fraction operand) => new Fraction(-operand.numerator, operand.denominator);
public static Fraction operator +(Fraction left, Fraction right)
=> new Fraction(left.numerator * right.denominator + right.numerator * left.denominator, left.denominator * right.denominator);
public static Fraction operator -(Fraction left, Fraction right)
=> left + (-right);
public static Fraction operator *(Fraction left, Fraction right)
=> new Fraction(left.numerator * right.numerator, left.denominator * right.denominator);
public static Fraction operator /(Fraction left, Fraction right)
{
if (right.numerator == 0)
{
throw new DivideByZeroException();
}
return new Fraction(left.numerator * right.denominator, left.denominator * right.numerator);
}
// Define increment and decrement to add 1/den, rather than 1/1.
public static Fraction operator ++(Fraction operand)
=> new Fraction(operand.numerator + 1, operand.denominator);
public static Fraction operator --(Fraction operand) =>
new Fraction(operand.numerator - 1, operand.denominator);
public override string ToString() => $"{numerator} / {denominator}";
// New operators allowed in C# 14:
public void operator +=(Fraction operand) =>
(numerator, denominator ) =
(
numerator * operand.denominator + operand.numerator * denominator,
denominator * operand.denominator
);
public void operator -=(Fraction operand) =>
(numerator, denominator) =
(
numerator * operand.denominator - operand.numerator * denominator,
denominator * operand.denominator
);
public void operator *=(Fraction operand) =>
(numerator, denominator) =
(
numerator * operand.numerator,
denominator * operand.denominator
);
public void operator /=(Fraction operand)
{
if (operand.numerator == 0)
{
throw new DivideByZeroException();
}
(numerator, denominator) =
(
numerator * operand.denominator,
denominator * operand.numerator
);
}
public void operator ++() => numerator++;
public void operator --() => numerator--;
}
public static class OperatorOverloading
{
public static void Main()
{
var a = new Fraction(5, 4);
var b = new Fraction(1, 2);
Console.WriteLine(-a); // output: -5 / 4
Console.WriteLine(a + b); // output: 14 / 8
Console.WriteLine(a - b); // output: 6 / 8
Console.WriteLine(a * b); // output: 5 / 8
Console.WriteLine(a / b); // output: 10 / 4
}
}
Вы можете расширить предыдущий пример, определив неявное преобразование из int в Fraction. Затем перегруженные операторы поддерживают аргументы этих двух типов. То есть можно было бы добавить целое число к дроби и получить дробь в результате.
Вы также используете ключевое слово operator для определения преобразования пользовательского типа. Дополнительные сведения см. в разделе Операторы пользовательского преобразования.
Перегруженные операторы
В следующей таблице показаны операторы, которые могут быть перегружены:
| Операторы | Примечания. |
|---|---|
+x, -x, !x~x++--truefalse |
Операторы true и false должны быть перегружены вместе. |
x + y, x - y, x * y, x / y, x % y,x & y, x | y, x ^ yx << y, , x >> yx >>> y |
|
x == y, , x != yx < yx > yx <= y,x >= y |
Должен быть перегружен в парах следующим образом: == и !=, < и >, <= и >=. |
+=, -=, *=/=%=&=\|=^=<<=>>=>>>= |
Операторы составного присваивания можно перегружать в версиях C# 14 и более поздних. |
Перегруженный оператор составного назначения должен соответствовать следующим правилам:
- Он должен включать модификатор
public. - Он не может включать
staticмодификатор. - Возвращаемый тип должен быть
void. - Объявление должно содержать один параметр, представляющий правую часть составного присваивания.
Начиная с C# 14, операторы инкремента++ и декремента-- можно перегрузить как члены экземпляра. Операторы экземпляров могут повысить производительность, избегая создания нового экземпляра. Оператор экземпляра должен соответствовать этим правилам:
- Он должен включать модификатор
public. - Он не может включать
staticмодификатор. - Возвращаемый тип должен быть
void. - Он не может объявлять какие-либо параметры, даже если эти параметры имеют значение по умолчанию.
Не перегруженные операторы
В следующей таблице показаны операторы, которые не могут быть перегружены:
| Операторы | Альтернативы |
|---|---|
x && y, x || y |
Перегрузите операторы true и false, а также операторы & или |. Дополнительные сведения см. в разделе "Определяемые пользователем условные логические операторы". |
a[i], a?[i] |
Определите индексатор. |
(T)x |
Определите преобразования пользовательских типов, выполняемые выражением приведения. Дополнительные сведения см. в разделе Операторы пользовательского преобразования. |
^x, x = y, x.yx?.yc ? t : fx ?? y??= yx..y, x->y=>f(x)asawaitcheckeduncheckeddefaultdelegateisnameofnewsizeof, , stackallocswitch, typeofwith |
Нет. |
До C# 14 составные операторы не могут быть перегружены. Перегрузка соответствующего двоичного оператора неявно перегружает соответствующий оператор составного назначения.
Разрешение перегрузки оператора
Это важно
Этот раздел относится к C# 14 и более поздним версиям. До C# 14 определяемые пользователем операторы составного присваивания, а также операторы инкремента и декремента экземпляра не допускаются.
Если x классифицируется как переменная в составном выражении назначения, напримерx «op»= y, операторы экземпляра предпочтительнее любого статического оператора.«op» Если перегруженный оператор не объявлен для типа «op»= или x не классифицируется как переменнаяx, используются статические операторы.
Если постфиксный оператор ++ не классифицируется как переменная x используется выражение , экземпляр x++ будет игнорироваться. В противном случае предпочтение отдается экземпляру operator ++. Например
x++; // Instance operator++ preferred.
y = x++; // instance operator++ isn't considered.
Причина этого правила заключается в том, что y должно быть назначено значением xперед его увеличением. Компилятор не может определить, что для определяемой пользователем реализации в эталонном типе.
Для префиксного оператора ++, если x классифицируется как переменная в ++x, оператор экземпляра предпочтительно по сравнению с статическим унарным оператором.
Спецификация языка C#
Дополнительные сведения см. в следующих разделах статьи Спецификация языка C#: