Skip to content

Commit 6c94fe4

Browse files
BillWagnerCopilotgewarren
authored
Add reference and fundamentals for user defined compound assignment operators (#46674)
* Add speclet Add the speclet to the docset. Add text in What's new in .NET 10 and What's new in C# 14. * Update language reference on operators This commit updates the files for operators where compound assignment can be overloaded. * lint * update operator overloading reference. * formatting issue * build issue * remove outdated restrictions. * Update docs/csharp/language-reference/operators/operator-overloading.md * Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Genevieve Warren <24882762+gewarren@users.noreply.github.com> * Respond to feedback. --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Genevieve Warren <24882762+gewarren@users.noreply.github.com>
1 parent 88150f0 commit 6c94fe4

File tree

14 files changed

+188
-90
lines changed

14 files changed

+188
-90
lines changed

docfx.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@
6060
"simple-lambda-parameters-with-modifiers.md",
6161
"partial-events-and-constructors.md",
6262
"null-conditional-assignment.md",
63-
"extensions.md"
63+
"extensions.md",
64+
"user-defined-compound-assignment.md"
6465
],
6566
"src": "_csharplang/proposals",
6667
"dest": "csharp/language-reference/proposals",
@@ -691,6 +692,7 @@
691692
"_csharplang/proposals/partial-events-and-constructors.md": "Partial events and constructors",
692693
"_csharplang/proposals/null-conditional-assignment.md": "Null conditional assignment",
693694
"_csharplang/proposals/extensions.md": "Extension members",
695+
"_csharplang/proposals/user-defined-compound-assignment.md": "User-defined compound assignment",
694696
"_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md": "C# compiler breaking changes since C# 10",
695697
"_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 8.md": "C# compiler breaking changes since C# 11",
696698
"_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 9.md": "C# compiler breaking changes since C# 12",
@@ -815,6 +817,7 @@
815817
"_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.",
816818
"_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.",
817819
"_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.",
820+
"_csharplang/proposals/user-defined-compound-assignment.md": "This proposal introduces user-defined compound assignment operators. Developers can override compound assignment, increment, and decrement operators.",
818821
"_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",
819822
"_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",
820823
"_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",

docs/core/whats-new/dotnet-10/overview.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ C# 14 introduces several new features and enhancements to improve developer prod
5454
- Support for partial instance constructors and partial events, complementing partial methods and properties introduced in C# 13.
5555
- New `extension` blocks add support for static extension methods, and static and instance extension properties.
5656
- Null-conditional assignment using the `?.` operator.
57+
- User-defined compound assignment operators like `+=` and `-=`.
58+
- User-defined increment (`++`) and decrement (`--`) operators.
5759

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

docs/csharp/language-reference/operators/addition-operator.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: "Addition operators - + and +="
33
description: "The C# addition operators (`+`, and `+=`) work with operands of numeric, string, or delegate types."
4-
ms.date: 11/22/2024
4+
ms.date: 06/11/2025
55
f1_keywords:
66
- "+_CSharpKeyword"
77
- "+=_CSharpKeyword"
@@ -16,19 +16,19 @@ helpviewer_keywords:
1616
---
1717
# Addition operators - `+` and `+=`
1818

19-
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.
19+
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.
2020

2121
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.
2222

2323
## String concatenation
2424

2525
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):
2626

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

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

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

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

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

3939
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:
4040

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

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

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

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

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

6767
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).
6868

6969
## Operator overloadability
7070

71-
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.
71+
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.
7272

7373
## C# language specification
7474

75-
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).
75+
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.
7676

7777
## See also
7878

docs/csharp/language-reference/operators/arithmetic-operators.md

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

41-
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.
41+
All [integral](../builtin-types/integral-numeric-types.md) and [floating-point](../builtin-types/floating-point-numeric-types.md) numeric types support these operators.
4242

43-
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.
43+
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.
4444

4545
## Increment operator ++
4646

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

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

117-
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).
117+
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).
118118

119119
## Remainder operator %
120120

@@ -136,7 +136,7 @@ For the `float` and `double` operands, the result of `x % y` for the finite `x`
136136
- 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.
137137

138138
> [!NOTE]
139-
> 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.
139+
> 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.
140140
141141
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).
142142

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

173-
is equivalent to
173+
Is equivalent to
174174

175175
```csharp
176176
x = x op y
177177
```
178178

179-
except that `x` is only evaluated once.
179+
Except that `x` is only evaluated once.
180180

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

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

248248
## Operator overloadability
249249

250-
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.
250+
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.
251251

252252
### User-defined checked operators
253253

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

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

273274
> [!NOTE]
274-
> 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.
275+
> 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.
275276

276277
## C# language specification
277278

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

293295
## See also
294296

docs/csharp/language-reference/operators/assignment-operator.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: "Assignment operators - assign an expression to a variable"
33
description: "C# Assignment sets the value of the expression. Alternatively, `ref` assignment sets the reference of a reference variable."
4-
ms.date: 04/04/2025
4+
ms.date: 06/11/2025
55
f1_keywords:
66
- "=_CSharpKeyword"
77
helpviewer_keywords:
@@ -77,11 +77,11 @@ You can use the null-coalescing assignment operator `??=` to assign the value of
7777

7878
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).
7979

80-
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.
80+
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.
8181

8282
## C# language specification
8383

84-
For more information, see the [Assignment operators](~/_csharpstandard/standard/expressions.md#1221-assignment-operators) section of the [C# language specification](~/_csharpstandard/standard/README.md).
84+
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.
8585

8686
## See also
8787

0 commit comments

Comments
 (0)