You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/csharp/whats-new/tutorials/compound-assignment-operators.md
+15-17Lines changed: 15 additions & 17 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -86,13 +86,11 @@ Final patrons arriving before curtain...
86
86
Final arrivals processed - concert about to begin!
87
87
```
88
88
89
-
This realistic scenario provides an excellent test case for measuring the performance benefits of compound assignment operators, as the frequent count updates mirror common patterns in real applications where objects are repeatedly modified.
90
-
91
89
Examine the starter `GateAttendance` record class:
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 our concert simulation with hundreds of attendance updates—these allocations accumulate quickly, potentially impacting performance and increasing garbage collection pressure.
93
+
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.
96
94
97
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
96
@@ -109,23 +107,23 @@ public void operator ++() => this.property++;
109
107
110
108
The key differences from traditional operators are:
111
109
112
-
-**Mutation**: They modify the current instance directly using `this`
113
-
-**No new instances**: Unlike traditional operators that return new objects, compound operators modify existing ones
114
-
-**Return type**: Compound assignment operators return `void`, not the type itself
110
+
-**Mutation**: They modify the current instance directly using `this`.
111
+
-**No new instances**: Unlike traditional operators that return new objects, compound operators modify existing ones.
112
+
-**Return type**: Compound assignment operators return `void`, not the type itself.
115
113
116
114
When the compiler encounters compound assignment expressions like `a += b` or `++a`, it follows this resolution order:
117
115
118
-
1.**Check for compound assignment operator**: If the type defines a user-defined compound assignment operator (`+=`, `++`, etc.), use it directly
119
-
2.**Fallback to traditional expansion**: If no compound operator exists, expand to the traditional form (`a = a + b`)
116
+
1.**Check for compound assignment operator**: If the type defines a user-defined compound assignment operator (for example, `+=` or `++`), use it directly.
117
+
2.**Fallback to traditional expansion**: If no compound operator exists, expand to the traditional form (`a = a + b`).
120
118
121
119
This means you can implement both approaches simultaneously. The compound operators take precedence when available, but the traditional operators serve as fallbacks for scenarios where compound assignment isn't suitable.
122
120
123
121
Compound assignment operators provide several advantages:
124
122
125
-
-**Reduced allocations**: Modify objects in-place instead of creating new instances
-**Familiar syntax**: Use the same `+=`, `++` syntax developers already know.
126
+
-**Backward compatibility**: Traditional operators continue to work as fallbacks.
129
127
130
128
The new compound assignment operators are shown in the following code:
131
129
@@ -141,14 +139,14 @@ The remaining 10 allocations come from the initial creation of the `GateAttendan
141
139
142
140
This allocation reduction translates to real performance benefits:
143
141
144
-
-**Reduced memory pressure**: Less frequent garbage collection cycles
145
-
-**Better cache locality**: Fewer object creations mean less memory fragmentation
146
-
-**Improved throughput**: CPU cycles saved from allocation and collection overhead
147
-
-**Scalability**: Benefits multiply in scenarios with higher operation volumes
142
+
-**Reduced memory pressure**: Less frequent garbage collection cycles.
143
+
-**Better cache locality**: Fewer object creations mean less memory fragmentation.
144
+
-**Improved throughput**: CPU cycles saved from allocation and collection overhead.
145
+
-**Scalability**: Benefits multiply in scenarios with higher operation volumes.
148
146
149
147
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.
150
148
151
-
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're repeatedly modifying objects rather than creating new instances.
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.
152
150
153
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.
0 commit comments