Skip to content

Add reference and fundamentals for user defined compound assignment operators #46674

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Jun 12, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion docfx.json
Original file line number Diff line number Diff line change
@@ -60,7 +60,8 @@
"simple-lambda-parameters-with-modifiers.md",
"partial-events-and-constructors.md",
"null-conditional-assignment.md",
"extensions.md"
"extensions.md",
"user-defined-compound-assignment.md"
],
"src": "_csharplang/proposals",
"dest": "csharp/language-reference/proposals",
@@ -691,6 +692,7 @@
"_csharplang/proposals/partial-events-and-constructors.md": "Partial events and constructors",
"_csharplang/proposals/null-conditional-assignment.md": "Null conditional assignment",
"_csharplang/proposals/extensions.md": "Extension members",
"_csharplang/proposals/user-defined-compound-assignment.md": "User-defined compound assignment",
"_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md": "C# compiler breaking changes since C# 10",
"_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 8.md": "C# compiler breaking changes since C# 11",
"_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 9.md": "C# compiler breaking changes since C# 12",
@@ -817,6 +819,7 @@
"_csharplang/proposals/partial-events-and-constructors.md": "This proposal allows partial events and constructors to be declared in partial classes. The event and constructor can be split across class declarations.",
"_csharplang/proposals/null-conditional-assignment.md": "This proposal allows the null conditional operator to be used for the destination of assignment expressions. This allows you to assign a value to a property or field only if the left side is not null.",
"_csharplang/proposals/extensions.md": "This proposal enables new kinds of extension members. These new extension members support extension properties, extension static members, including extension operators.",
"_csharplang/proposals/user-defined-compound-assignment.md": "This proposal introduces user-defined compound assignment operators. Developers can override compound assignment, increment, and decrement operators.",
"_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md": "Learn about any breaking changes since the initial release of C# 10 and included in C# 11",
"_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 8.md": "Learn about any breaking changes since the initial release of C# 11 and included in C# 12",
"_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 9.md": "Learn about any breaking changes since the initial release of C# 12 and included in C# 13",
2 changes: 2 additions & 0 deletions docs/core/whats-new/dotnet-10/overview.md
Original file line number Diff line number Diff line change
@@ -54,6 +54,8 @@ C# 14 introduces several new features and enhancements to improve developer prod
- Support for partial instance constructors and partial events, complementing partial methods and properties introduced in C# 13.
- New `extension` blocks add support for static extension methods, and static and instance extension properties.
- Null-conditional assignment using the `?.` operator.
- User-defined compound assignment operators like `+=` and `-=`.
- User-defined increment (`++`) and decrement (`--`) operators.

For more information, see [What's new in C# 14](../../../csharp/whats-new/csharp-14.md).

16 changes: 8 additions & 8 deletions docs/csharp/language-reference/operators/addition-operator.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: "Addition operators - + and +="
description: "The C# addition operators (`+`, and `+=`) work with operands of numeric, string, or delegate types."
ms.date: 11/22/2024
ms.date: 06/11/2025
f1_keywords:
- "+_CSharpKeyword"
- "+=_CSharpKeyword"
@@ -16,19 +16,19 @@ helpviewer_keywords:
---
# Addition operators - `+` and `+=`

The `+` and `+=` operators are supported by the built-in [integral](../builtin-types/integral-numeric-types.md) and [floating-point](../builtin-types/floating-point-numeric-types.md) numeric types, the [string](../builtin-types/reference-types.md#the-string-type) type, and [delegate](../builtin-types/reference-types.md#the-delegate-type) types.
The built-in [integral](../builtin-types/integral-numeric-types.md) and [floating-point](../builtin-types/floating-point-numeric-types.md) numeric types, the [string](../builtin-types/reference-types.md#the-string-type) type, and [delegate](../builtin-types/reference-types.md#the-delegate-type) types all support the `+` and `+=` operators.

For information about the arithmetic `+` operator, see the [Unary plus and minus operators](arithmetic-operators.md#unary-plus-and-minus-operators) and [Addition operator +](arithmetic-operators.md#addition-operator-) sections of the [Arithmetic operators](arithmetic-operators.md) article.

## String concatenation

When one or both operands are of type [string](../builtin-types/reference-types.md#the-string-type), the `+` operator concatenates the string representations of its operands (the string representation of `null` is an empty string):

[!code-csharp-interactive[string concatenation](snippets/shared/AdditionOperator.cs#AddStrings)]
:::code interactive="try-dotnet-method" language="csharp" source="snippets/shared/AdditionOperator.cs" id="AddStrings":::

[String interpolation](../tokens/interpolated.md) provides a more convenient way to format strings:

[!code-csharp-interactive[string interpolation](snippets/shared/AdditionOperator.cs#UseStringInterpolation)]
:::code interactive="try-dotnet-method" language="csharp" source="snippets/shared/AdditionOperator.cs" id="UseStringInterpolation":::

You can use string interpolation to initialize a constant string when all the expressions used for placeholders are also constant strings.

@@ -38,7 +38,7 @@ Beginning with C# 11, the `+` operator performs string concatenation for UTF-8 l

For operands of the same [delegate](../builtin-types/reference-types.md#the-delegate-type) type, the `+` operator returns a new delegate instance that, when invoked, invokes the left-hand operand and then invokes the right-hand operand. If any of the operands is `null`, the `+` operator returns the value of another operand (which also might be `null`). The following example shows how delegates can be combined with the `+` operator:

[!code-csharp-interactive[delegate combination](snippets/shared/AdditionOperator.cs#AddDelegates)]
:::code interactive="try-dotnet-method" language="csharp" source="snippets/shared/AdditionOperator.cs" id="AddDelegates":::

To perform delegate removal, use the [`-` operator](subtraction-operator.md#delegate-removal).

@@ -62,17 +62,17 @@ Except that `x` is only evaluated once.

The following example demonstrates the usage of the `+=` operator:

[!code-csharp-interactive[+= examples](snippets/shared/AdditionOperator.cs#AddAndAssign)]
:::code interactive="try-dotnet-method" language="csharp" source="snippets/shared/AdditionOperator.cs" id="AddAndAssign":::

You also use the `+=` operator to specify an event handler method when you subscribe to an [event](../keywords/event.md). For more information, see [How to: subscribe to and unsubscribe from events](../../programming-guide/events/how-to-subscribe-to-and-unsubscribe-from-events.md).

## Operator overloadability

A user-defined type can [overload](operator-overloading.md) the `+` operator. When a binary `+` operator is overloaded, the `+=` operator is also implicitly overloaded. A user-defined type can't explicitly overload the `+=` operator.
A user-defined type can [overload](operator-overloading.md) the `+` operator. When a binary `+` operator is overloaded, the `+=` operator is also implicitly overloaded. Beginning with C# 14, a user-defined type can explicitly overload the `+=` operator to provide a more efficient implementation. Typically, a type overloads the `+=` operator because the value can be updated in place, rather than allocate a new instance to hold the result of the addition. If a type doesn't provide an explicit overload, the compiler generates the implicit overload.

## C# language specification

For more information, see the [Unary plus operator](~/_csharpstandard/standard/expressions.md#1292-unary-plus-operator) and [Addition operator](~/_csharpstandard/standard/expressions.md#12105-addition-operator) sections of the [C# language specification](~/_csharpstandard/standard/README.md).
For more information, see the [Unary plus operator](~/_csharpstandard/standard/expressions.md#1292-unary-plus-operator) and [Addition operator](~/_csharpstandard/standard/expressions.md#12105-addition-operator) sections of the [C# language specification](~/_csharpstandard/standard/README.md). For more information on overloading the compound assignment operators in C# 14 and later, see the [user defined compound assignment](~/_csharplang/proposals/user-defined-compound-assignment.md) feature specification.

## See also

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: "Arithmetic operators"
description: "Learn about C# operators that perform multiplication, division, remainder, addition, and subtraction operations with numeric types."
ms.date: 07/25/2022
ms.date: 06/11/2025
author: pkulikov
f1_keywords:
- "++_CSharpKeyword"
@@ -38,9 +38,9 @@ The following operators perform arithmetic operations with operands of numeric t
- Unary [`++` (increment)](#increment-operator-), [`--` (decrement)](#decrement-operator---), [`+` (plus)](#unary-plus-and-minus-operators), and [`-` (minus)](#unary-plus-and-minus-operators) operators
- Binary [`*` (multiplication)](#multiplication-operator-), [`/` (division)](#division-operator-), [`%` (remainder)](#remainder-operator-), [`+` (addition)](#addition-operator-), and [`-` (subtraction)](#subtraction-operator--) operators

Those operators are supported by all [integral](../builtin-types/integral-numeric-types.md) and [floating-point](../builtin-types/floating-point-numeric-types.md) numeric types.
All [integral](../builtin-types/integral-numeric-types.md) and [floating-point](../builtin-types/floating-point-numeric-types.md) numeric types support these operators.

In the case of integral types, those operators (except the `++` and `--` operators) are defined for the `int`, `uint`, `long`, and `ulong` types. When operands are of other integral types (`sbyte`, `byte`, `short`, `ushort`, or `char`), their values are converted to the `int` type, which is also the result type of an operation. When operands are of different integral or floating-point types, their values are converted to the closest containing type, if such a type exists. For more information, see the [Numeric promotions](~/_csharpstandard/standard/expressions.md#1247-numeric-promotions) section of the [C# language specification](~/_csharpstandard/standard/README.md). The `++` and `--` operators are defined for all integral and floating-point numeric types and the [char](../builtin-types/char.md) type. The result type of a [compound assignment expression](#compound-assignment) is the type of the left-hand operand.
The `int`, `uint`, `long`, and `ulong` types define all these operators. The other integral types (`sbyte`, `byte`, `short`, `ushort`, and `char`) define only the `++` and `--` operators. For other operators, when operands are of the integral types `sbyte`, `byte`, `short`, `ushort`, or `char`, their values are converted to the `int` type and the result type is `int`. When operands are of different integral or floating-point types, their values are converted to the closest containing type, if such a type exists. For more information, see the [Numeric promotions](~/_csharpstandard/standard/expressions.md#1247-numeric-promotions) section of the [C# language specification](~/_csharpstandard/standard/README.md). The `++` and `--` operators are defined for all integral and floating-point numeric types and the [char](../builtin-types/char.md) type. The result type of a [compound assignment expression](#compound-assignment) is the type of the left-hand operand.

## Increment operator ++

@@ -114,7 +114,7 @@ For the `float`, `double`, and `decimal` types, the result of the `/` operator i

:::code language="csharp" interactive="try-dotnet-method" source="snippets/shared/ArithmeticOperators.cs" id="FloatingPointDivision":::

If one of the operands is `decimal`, another operand can be neither `float` nor `double`, because neither `float` nor `double` is implicitly convertible to `decimal`. You must explicitly convert the `float` or `double` operand to the `decimal` type. For more information about conversions between numeric types, see [Built-in numeric conversions](../builtin-types/numeric-conversions.md).
If one of the operands is `decimal`, another operand can't be `float` nor `double`, because neither `float` nor `double` is implicitly convertible to `decimal`. You must explicitly convert the `float` or `double` operand to the `decimal` type. For more information about conversions between numeric types, see [Built-in numeric conversions](../builtin-types/numeric-conversions.md).

## Remainder operator %

@@ -136,7 +136,7 @@ For the `float` and `double` operands, the result of `x % y` for the finite `x`
- The absolute value of `z` is the value produced by `|x| - n * |y|` where `n` is the largest possible integer that is less than or equal to `|x| / |y|` and `|x|` and `|y|` are the absolute values of `x` and `y`, respectively.

> [!NOTE]
> This method of computing the remainder is analogous to that used for integer operands, but different from the IEEE 754 specification. If you need the remainder operation that complies with the IEEE 754 specification, use the <xref:System.Math.IEEERemainder%2A?displayProperty=nameWithType> method.
> This method of computing the remainder is analogous to the method used for integer operands, but different from the IEEE 754 specification. If you need the remainder operation that complies with the IEEE 754 specification, use the <xref:System.Math.IEEERemainder%2A?displayProperty=nameWithType> method.

For information about the behavior of the `%` operator with non-finite operands, see the [Remainder operator](~/_csharpstandard/standard/expressions.md#12104-remainder-operator) section of the [C# language specification](~/_csharpstandard/standard/README.md).

@@ -170,13 +170,13 @@ For a binary operator `op`, a compound assignment expression of the form
x op= y
```

is equivalent to
Is equivalent to

```csharp
x = x op y
```

except that `x` is only evaluated once.
Except that `x` is only evaluated once.

The following example demonstrates the usage of compound assignment with arithmetic operators:

@@ -247,7 +247,7 @@ For more information, see remarks at the [System.Double](/dotnet/api/system.doub

## Operator overloadability

A user-defined type can [overload](operator-overloading.md) the unary (`++`, `--`, `+`, and `-`) and binary (`*`, `/`, `%`, `+`, and `-`) arithmetic operators. When a binary operator is overloaded, the corresponding compound assignment operator is also implicitly overloaded. A user-defined type can't explicitly overload a compound assignment operator.
A user-defined type can [overload](operator-overloading.md) the unary (`++`, `--`, `+`, and `-`) and binary (`*`, `/`, `%`, `+`, and `-`) arithmetic operators. When a binary operator is overloaded, the corresponding compound assignment operator is also implicitly overloaded. Beginning with C# 14, a user-defined type can explicitly overload the compound assignment operators (`op=`) to provide a more efficient implementation. Typically, a type overloads these operators because the value can be updated in place, rather than allocating a new instance to store the result of the operation. If a type doesn't provide an explicit overload, the compiler generates the implicit overload.

### User-defined checked operators

@@ -268,10 +268,11 @@ You can use the `checked` modifier only when you overload any of the following o

- Unary `++`, `--`, and `-` operators
- Binary `*`, `/`, `+`, and `-` operators
- Compound assignment `*=`, `/=`, `+=`, and `-=` operators (C# 14 and later)
- [Explicit conversion operators](user-defined-conversion-operators.md)

> [!NOTE]
> The overflow-checking context within the body of a checked operator is not affected by the presence of the `checked` modifier. The default context is defined by the value of the [**CheckForOverflowUnderflow**](../compiler-options/language.md#checkforoverflowunderflow) compiler option. Use the [`checked` and `unchecked` statements](../statements/checked-and-unchecked.md) to explicitly specify the overflow-checking context, as the example at the beginning of this section demonstrates.
> The overflow-checking context within the body of a checked operator isn't affected by the presence of the `checked` modifier. The default context is defined by the value of the [**CheckForOverflowUnderflow**](../compiler-options/language.md#checkforoverflowunderflow) compiler option. Use the [`checked` and `unchecked` statements](../statements/checked-and-unchecked.md) to explicitly specify the overflow-checking context, as the example at the beginning of this section demonstrates.

## C# language specification

@@ -289,6 +290,7 @@ For more information, see the following sections of the [C# language specificati
- [Compound assignment](~/_csharpstandard/standard/expressions.md#12214-compound-assignment)
- [The checked and unchecked operators](~/_csharpstandard/standard/expressions.md#12820-the-checked-and-unchecked-operators)
- [Numeric promotions](~/_csharpstandard/standard/expressions.md#1247-numeric-promotions)
- [User defined compound assignment](~/_csharplang/proposals/user-defined-compound-assignment.md)

## See also

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: "Assignment operators - assign an expression to a variable"
description: "C# Assignment sets the value of the expression. Alternatively, `ref` assignment sets the reference of a reference variable."
ms.date: 04/04/2025
ms.date: 06/11/2025
f1_keywords:
- "=_CSharpKeyword"
helpviewer_keywords:
@@ -77,11 +77,11 @@ You can use the null-coalescing assignment operator `??=` to assign the value of

A user-defined type can't [overload](operator-overloading.md) the assignment operator. However, a user-defined type can define an implicit conversion to another type. That way, the value of a user-defined type can be assigned to a variable, a property, or an indexer element of another type. For more information, see [User-defined conversion operators](user-defined-conversion-operators.md).

A user-defined type can't explicitly overload a compound assignment operator. However, if a user-defined type overloads a binary operator `op`, the `op=` operator, if it exists, is also implicitly overloaded.
If a user-defined type overloads a binary operator `op`, the `op=` operator, if it exists, is also implicitly overloaded. Beginning with C# 14, a user-defined type can explicitly overload the compound assignment operators (`op=`) to provide a more efficient implementation. Typically, a type overloads these operators because the value can be updated in place, rather than allocating a new instance to hold the result of the binary operation. If a type doesn't provide an explicit overload, the compiler generates the implicit overload.

## C# language specification

For more information, see the [Assignment operators](~/_csharpstandard/standard/expressions.md#1221-assignment-operators) section of the [C# language specification](~/_csharpstandard/standard/README.md).
For more information, see the [Assignment operators](~/_csharpstandard/standard/expressions.md#1221-assignment-operators) section of the [C# language specification](~/_csharpstandard/standard/README.md) and the [User defined compound assignment](~/_csharplang/proposals/user-defined-compound-assignment.md) feature specification.

## See also

Loading
Oops, something went wrong.