Skip to content

Commit 97b6254

Browse files
authored
edit pass based on feedback (#49911)
* edit pass based on feedback Fixes #49604 Also, searched for other instances of Visual Studio preview (which is now generally released) and update those as well. * Copilot review updates * Apply suggestions from code review
1 parent f2a5af2 commit 97b6254

File tree

2 files changed

+26
-20
lines changed

2 files changed

+26
-20
lines changed

docs/csharp/whats-new/tutorials/compound-assignment-operators.md

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
---
2-
title: Explore user defined instance compound assignment operators
3-
description: "C# 14 enables user defined instance compound assignment operators. These operators can provide better performance by minimizing allocations or copy operations. Learn how to create these operators."
2+
title: Explore user-defined instance compound assignment operators
3+
description: "C# 14 enables user-defined instance compound assignment operators. These operators can provide better performance by minimizing allocations or copy operations. Learn how to create these operators."
44
author: billwagner
55
ms.author: wiwagn
66
ms.service: dotnet-csharp
77
ms.topic: tutorial
8-
ms.date: 09/15/2025
8+
ms.date: 11/14/2025
99
ai-usage: ai-assisted
10-
#customer intent: As a C# developer, I want implement user defined instance compound assignment operators so that my algorithms are more efficient.
10+
#customer intent: As a C# developer, I want to implement user-defined instance compound assignment operators so that my algorithms are more efficient.
1111
---
1212
# Tutorial: Create compound assignment operators
1313

14-
C#14.0 adds *user defined compound assignment operators* that enable mutating a data structure in place, rather than creating a new instance. In previous versions of C#, the expression:
14+
C#14 adds [*user-defined compound assignment operators*](~/_csharplang/proposals/csharp-14.0/user-defined-compound-assignment.md) that enable mutating a data structure in place, rather than creating a new instance. In previous versions of C#, the expression:
1515

1616
```csharp
1717
a += b;
@@ -20,27 +20,28 @@ a += b;
2020
Was expanded to the following code:
2121

2222
```csharp
23+
// compiler-generated code prior to C# 13:
2324
var tmp = a + b;
2425
a = tmp;
2526
```
2627

27-
Depending on the type of `a`, this expansion leads to excessive allocations to create new instances, or copying the values of several properties to set values on the copy. Adding a user defined operator for `+=` indicates a type can do a better job by updating the destination object in place.
28+
Depending on the type of `a`, this expansion leads to excessive allocations to create new instances, or copying the values of several properties to set values on the copy. Adding a user-defined operator for `+=` indicates a type can do a better job by updating the destination object in place.
2829

29-
C# supports the existing expansion, but it uses it only when a compound user defined operator isn't available.
30+
C# supports the existing expansion, but it uses it only when a compound user-defined operator isn't available.
3031

3132
In this tutorial, you:
3233

3334
> [!div class="checklist"]
3435
>
35-
> * Install prerequisites
36-
> * Analyze the starting sample
37-
> * Implement compound assignment operators
38-
> * Analyze completed sample
36+
> * Run the starting sample.
37+
> * Identify bottlenecks in the code.
38+
> * Implement new compound assignment operators.
39+
> * Analyze the completed sample.
3940
4041
## Prerequisites
4142

4243
- The .NET 10 SDK. Download it from the [.NET download site](https://dotnet.microsoft.com/download/dotnet/10.0).
43-
- Visual Studio 2026 (preview). Download it from the [Visual Studio insiders page](https://visualstudio.microsoft.com/insiders/).
44+
- Visual Studio 2026. Download it from the [Visual Studio page](https://visualstudio.microsoft.com).
4445

4546
## Analyze the starting sample
4647

@@ -50,15 +51,17 @@ The app tracks attendance through multiple theater gates (main floor and balcony
5051

5152
:::code language="csharp" source="./snippets/CompoundAssignment/GateAttendanceTests.cs" id="Simulation":::
5253

53-
With traditional operators, each operation creates a new `GateAttendance` instance due to the immutable nature of records, leading to significant memory allocations.
54+
## Identify bottlenecks in the code
5455

55-
When you run the simulation, you see detailed output showing:
56+
With traditional operators, each operation creates a new `GateAttendance` instance, leading to significant memory allocations. The starter `GateAttendance` is *immutable*. Your code can't modify the state of the object after it's been initialized. That design decision requires copying objects if you need to modify state.
57+
58+
When you run the simulation, the detailed output shows:
5659

5760
- Gate-by-gate attendance numbers during different arrival periods.
5861
- Total attendance tracking across all gates.
5962
- A final comprehensive report with attendance statistics.
6063

61-
You can see a portion of the output:
64+
The following text displays some of the example output:
6265

6366
```txt
6467
Peak arrival time - all gates busy...
@@ -92,7 +95,7 @@ Examine the starter `GateAttendance` record class:
9295

9396
The `InitialImplementation.GateAttendance` record demonstrates the traditional approach to operator overloading in C#. Notice how both the increment operator (`++`) and addition operator (`+`) create entirely new instances of `GateAttendance` using the `with` expression. Each time you write `gate++` or `gate += partySize`, the operators allocate a new record instance with the updated `Count` value, then return that new instance. While this approach maintains immutability and thread safety, it comes at the cost of frequent memory allocations. In scenarios with many operations—like the concert simulation with hundreds of attendance updates—these allocations accumulate quickly, potentially impacting performance and increasing garbage collection pressure.
9497

95-
To see this allocation behavior in action, try running the [.NET Object Allocation tracking tool](/visualstudio/profiling/dotnet-alloc-tool) in Visual Studio. When you profile the current implementation during the concert simulation, you discover that it allocates 134 `GateAttendance` objects to complete the relatively small simulation. Each operator call creates a new instance, demonstrating how quickly allocations can accumulate in real-world scenarios. This measurement provides a concrete baseline for comparing the performance improvements you achieve with compound assignment operators.
98+
To measure this allocation behavior, try running the [.NET Object Allocation tracking tool](/visualstudio/profiling/dotnet-alloc-tool) in Visual Studio. When you profile the current implementation during the concert simulation, you discover that it allocates 134 `GateAttendance` objects to complete the relatively small simulation. Each operator call creates a new instance, demonstrating how quickly allocations can accumulate in real-world scenarios. This measurement provides a concrete baseline for comparing the performance improvements you achieve with compound assignment operators.
9699

97100
## Implement compound assignment operators
98101

@@ -129,9 +132,12 @@ The new compound assignment operators are shown in the following code:
129132

130133
:::code language="csharp" source="./snippets/CompoundAssignment/GateAttendance.cs" id="CompoundAssignmentOperators":::
131134

135+
> [!NOTE]
136+
> Developers familiar with C++ might wonder why only one `++` or `--` operator is required. The compiler generates the code to use either the expression before or after modification as the return value. The compiler-generated code performs the assignment using either the original value or the modified value based on whether pre-increment (`++x`) or post-increment (`x++`) was called.
137+
132138
## Analyze finished sample
133139

134-
Now that you implemented the compound assignment operators, it's time to measure the performance improvement. To see the dramatic difference in memory allocations, run the [.NET Object Allocation tracking tool](/visualstudio/profiling/dotnet-alloc-tool) again on the updated code.
140+
Now that you implemented the compound assignment operators, it's time to measure the performance improvement. To measure the dramatic difference in memory allocations, run the [.NET Object Allocation tracking tool](/visualstudio/profiling/dotnet-alloc-tool) again on the updated code.
135141

136142
When you profile the application with the compound assignment operators enabled, you observe a remarkable reduction: only **10 `GateAttendance` objects** are allocated during the entire concert simulation, compared to the previous 134 allocations. This update represents a 92% reduction in object allocations!
137143

@@ -146,9 +152,9 @@ This allocation reduction translates to real performance benefits:
146152

147153
The performance improvement becomes even more significant in production applications where similar patterns occur at much larger scales—imagine tracking millions of transactions, updating thousands of counters, or processing high-frequency data streams.
148154

149-
Try identifying other opportunities for compound assignment operators in the codebase. Look for patterns where you see traditional assignment operations like `gates.MainFloorGates[1] = gates.MainFloorGates[1] + 4` and consider whether they could benefit from compound assignment syntax. While some of these operations are already using `+=` in the simulation code, the principle applies to any scenario where you repeatedly modify objects rather than creating new instances.
155+
Try identifying other opportunities for compound assignment operators in the codebase. Look for patterns where you use traditional assignment operations like `gates.MainFloorGates[1] = gates.MainFloorGates[1] + 4` and consider whether they could benefit from compound assignment syntax. While some of these operations are already using `+=` in the simulation code, the principle applies to any scenario where you repeatedly modify objects rather than creating new instances.
150156

151-
As a final experiment, change the `GateAttendance` type from a `record class` to a `record struct`. It's a different optimization, and it works in this simulation because the struct has a small memory footprint. Copying a `GateAttendance` struct isn't an expensive operation. Even so, you see small improvements.
157+
As a final experiment, change the `GateAttendance` type from a `record class` to a `record struct`. It's a different optimization, and it works in this simulation because the struct has a small memory footprint. Copying a `GateAttendance` struct isn't an expensive operation. Even so, you achieve small improvements.
152158

153159
## Related content
154160

docs/csharp/whats-new/tutorials/extension-members.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ In this tutorial, you:
2727
## Prerequisites
2828

2929
- The .NET 10 SDK. Download it from the [.NET download site](https://dotnet.microsoft.com/download/dotnet/10.0).
30-
- Visual Studio 2026 (preview). Download it from the [Visual Studio insiders page](https://visualstudio.microsoft.com/insiders/).
30+
- Visual Studio 2026. Download it from the [Visual Studio page](https://visualstudio.microsoft.com).
3131

3232
## Create the sample application
3333

0 commit comments

Comments
 (0)