Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
A user-defined type can overload a predefined C# operator. That is, a type can provide the custom implementation of an operation in case one or both of the operands are of that type. The Overloadable operators section shows which C# operators can be overloaded.
Use the operator
keyword to declare an operator. An operator declaration must satisfy the following rules:
- It includes a
public
modifier. - A unary operator has one input parameter. A binary operator has two input parameters. In each case, at least one parameter must have type
T
orT?
whereT
is the type that contains the operator declaration. - It includes the
static
modifier, except for the compound assignment operators, such as+=
. - The increment (
++
) and decrement (--
) operators can be implemented as either static or instance methods.
The following example defines a simplified structure to represent a rational number. The structure overloads some of the arithmetic operators:
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++, operand.denominator);
public static Fraction operator --(Fraction operand) =>
new Fraction(operand.numerator--, 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
}
}
You could extend the preceding example by defining an implicit conversion from int
to Fraction
. Then, overloaded operators would support arguments of those two types. That is, it would become possible to add an integer to a fraction and obtain a fraction as a result.
You also use the operator
keyword to define a custom type conversion. For more information, see User-defined conversion operators.
Overloadable operators
The following table shows the operators that can be overloaded:
Operators | Notes |
---|---|
+x , -x , !x , ~x , ++ , -- , true , false |
The true and false operators must be overloaded together. |
x + y , x - y , x * y , x / y , x % y , x & y , x | y , x ^ y , x << y , x >> y , x >>> y |
|
x == y , x != y , x < y , x > y , x <= y , x >= y |
Must be overloaded in pairs as follows: == and != , < and > , <= and >= . |
+= , -= , *= , /= , %= , &= , \|= , ^= , <<= , >>= , >>>= |
The compound assignment operators can be overloaded in C# 14 and later. |
A compound assignment overloaded operator must follow these rules:
- It must include the
public
modifier. - It can't include the
static
modifier. - The return type must be
void
. - The declaration must include one parameter, which represents the right hand side of the compound assignment.
Beginning with C# 14, the increment (++
) and decrement (--
) operators can be overloaded as instance members. Instance operators can improve performance by avoiding the creation of a new instance. An instance operator must follow these rules:
- It must include the
public
modifier. - It can't include the
static
modifier. - The return type must be
void
. - It can't declare any parameters, even if those parameters have a default value.
Non overloadable operators
The following table shows the operators that can't be overloaded:
Operators | Alternatives |
---|---|
x && y , x || y |
Overload both the true and false operators and the & or | operators. For more information, see User-defined conditional logical operators. |
a[i] , a?[i] |
Define an indexer. |
(T)x |
Define custom type conversions performed by a cast expression. For more information, see User-defined conversion operators. |
^x , x = y , x.y , x?.y , c ? t : f , x ?? y , ??= y ,x..y , x->y , => , f(x) , as , await , checked , unchecked , default , delegate , is , nameof , new , sizeof , stackalloc , switch , typeof , with |
None. |
Before C# 14, the compound operators can't be overloaded. Overloading the corresponding binary operator implicitly overloads the corresponding compound assignment operator.
Operator overload resolution
Important
This section applies to C# 14 and later. Before C# 14, user-defined compound assignment operators and instance increment and decrement operators aren't allowed.
If x
is classified as a variable in a compound assignment expression such as x «op»= y
, instance operators are preferred over any static operator for «op»
. If an overloaded «op»=
operator isn't declared for the type of x
or x
isn't classified as a variable, the static operators are used.
For the postfix operator ++
, if x
isn't classified as a variable or the expression x++
is used, the instance operator++
is ignored. Otherwise, preference is given to the instance operator ++
. For example,
x++; // Instance operator++ preferred.
y = x++; // instance operator++ isn't considered.
The reason for this rule is that y
should be assigned to the value of x
before it's incremented. The compiler can't determine that for a user-defined implementation in a reference type.
For the prefix operator ++
, if x
is classified as a variable in ++x
, the instance operator is preferred over a static unary operator.
C# language specification
For more information, see the following sections of the C# language specification: