7.2.2 Operator overloading

Visual Studio .NET 2003

All unary and binary operators have predefined implementations that are automatically available in any expression. In addition to the predefined implementations, user-defined implementations can be introduced by including operator declarations in classes and structs (Section 10.9). User-defined operator implementations always take precedence over predefined operator implementations: Only when no applicable user-defined operator implementations exist will the predefined operator implementations be considered.

Although true and false are not used explicitly in expressions, they are considered operators because they are invoked in several expression contexts: Boolean expressions (Section 7.16) and expressions involving the conditional (Section 7.12), and conditional logical operators (Section 7.11).

Only the operators listed above can be overloaded. In particular, it is not possible to overload member access, method invocation, or the =, &&, ||, ?:, checked, unchecked, new, typeof, as, and is operators.

When a binary operator is overloaded, the corresponding assignment operator (if any) is also implicitly overloaded. For example, an overload of operator * is also an overload of operator *=. This is described further in Section 7.13. Note that the assignment operator itself (=) cannot be overloaded. An assignment always performs a simple bit-wise copy of a value into a variable.

Cast operations, such as (T)x, are overloaded by providing user-defined conversions (Section 6.4).

Element access, such as a[x], is not considered an overloadable operator. Instead, user-defined indexing is supported through indexers (Section 10.8).

In expressions, operators are referenced using operator notation, and in declarations, operators are referenced using functional notation. The following table shows the relationship between operator and functional notations for unary and binary operators. In the first entry, op denotes any overloadable unary prefix operator. In the second entry, op denotes the unary postfix ++ and -- operators. In the third entry, op denotes any overloadable binary operator.

Operator notation

Functional notation

opx

operatorop(x)

xop

operatorop(x)

xopy

operatorop(x,y)

User-defined operator declarations always require at least one of the parameters to be of the class or struct type that contains the operator declaration. Thus, it is not possible for a user-defined operator to have the same signature as a predefined operator.

User-defined operator declarations cannot modify the syntax, precedence, or associativity of an operator. For example, the / operator is always a binary operator, always has the precedence level specified in Section 7.2.1, and is always left-associative.

While it is possible for a user-defined operator to perform any computation it pleases, implementations that produce results other than those that are intuitively expected are strongly discouraged. For example, an implementation of operator== should compare the two operands for equality and return an appropriate bool result.

The descriptions of individual operators in Section 7.5 through Section 7.13 specify the predefined implementations of the operators and any additional rules that apply to each operator. The descriptions make use of the terms unary operator overload resolution, binary operator overload resolution, and numeric promotion, definitions of which are found in the following sections.