Skip to content

Commit f249f0d

Browse files
committed
proofread and fix warnings.
1 parent 72d1172 commit f249f0d

File tree

2 files changed

+31
-33
lines changed

2 files changed

+31
-33
lines changed

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

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
11
---
22
title: Explore user defined instance compound assignment operators
3-
description: "C# 14 enables user defined instance compound assignment operators. These can provide better performance by minimizing allocations or copy operations. Learn how to create these 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
88
ms.date: 09/15/2025
9-
9+
ai-usage:ai-assisted
1010
#customer intent: As a C# developer, I want implement user defined instance compound assignment operators so that my algorithms are more efficient.
11-
1211
---
13-
1412
# Tutorial: Create compound assignment operators
1513

1614
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:
@@ -19,16 +17,16 @@ C#14.0 adds *user defined compound assignment operators* that enable mutating a
1917
a += b;
2018
```
2119

22-
was expanded to the following code:
20+
Was expanded to the following code:
2321

2422
```csharp
2523
var tmp = a + b;
2624
a = tmp;
2725
```
2826

29-
Depending on the type of `a`, this 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.
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.
3028

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

3331
In this tutorial, you:
3432

@@ -45,15 +43,15 @@ In this tutorial, you:
4543

4644
## Analyze the starting sample
4745

48-
Run the app to understand what it does. The sample application simulates concert attendance tracking at a theater venue. The simulation models realistic arrival patterns throughout the evening, from early patrons to the main rush before showtime. This simulation demonstrates the performance impact of object allocations when using traditional operators versus the efficiency gains possible with user-defined compound assignment operators.
46+
Run the starter application. You can get it from [the `dotnet/docs` GitHub repository](https://github.com/dotnet/docs/blob/main/docs/csharp/whats-new/tutorials/snippets/CompoundAssignment). The sample application simulates concert attendance tracking at a theater venue. The simulation models realistic arrival patterns throughout the evening, from early attendees to the main rush before showtime. This simulation demonstrates the object allocations when using traditional operators versus the efficiency gains possible with user-defined compound assignment operators.
4947

5048
The app tracks attendance through multiple theater gates (main floor and balcony sections) as concert-goers arrive. Each gate maintains a count of attendees using a `GateAttendance` record. Throughout the simulation, the code frequently updates these counts using increment (`++`) and addition (`+=`) operations. The following code shows a portion of that simulation:
5149

5250
:::code language="csharp" source="./snippets/CompoundAssignment/GateAttendanceTests.cs" id="Simulation":::
5351

5452
With traditional operators, each operation creates a new `GateAttendance` instance due to the immutable nature of records, leading to significant memory allocations.
5553

56-
When you run the simulation, you'll see detailed output showing:
54+
When you run the simulation, you see detailed output showing:
5755

5856
- Gate-by-gate attendance numbers during different arrival periods.
5957
- Total attendance tracking across all gates.
@@ -95,13 +93,13 @@ Examine the starter `GateAttendance` record class:
9593

9694
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.
9795

98-
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'll 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'll achieve with compound assignment operators.
96+
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.
9997

10098
## Implement compound assignment operators
10199

102100
C# 14 introduces user-defined compound assignment operators that enable in-place mutations instead of creating new instances. These operators provide a more efficient alternative to the traditional pattern while maintaining the familiar compound assignment syntax.
103101

104-
Compound assignment operators use a new syntax that declares `void` return methods with the `operator` keyword:
102+
Compound assignment operators use a new syntax that declares `void` return methods with the `operator` keyword. Add the following operators to the `GateAttendance` class:
105103

106104
```csharp
107105
public void operator +=(int value) => this.property += value;
@@ -110,9 +108,9 @@ public void operator ++() => this.property++;
110108

111109
The key differences from traditional operators are:
112110

113-
- **Return type**: Compound assignment operators return `void`, not the type itself
114111
- **Mutation**: They modify the current instance directly using `this`
115112
- **No new instances**: Unlike traditional operators that return new objects, compound operators modify existing ones
113+
- **Return type**: Compound assignment operators return `void`, not the type itself
116114

117115
When the compiler encounters compound assignment expressions like `a += b` or `++a`, it follows this resolution order:
118116

@@ -134,11 +132,11 @@ The new compound assignment operators are shown in the following code:
134132

135133
## Analyze finished sample
136134

137-
Now that you've implemented the compound assignment operators, it's time to measure the performance improvement. Run the [.NET Object Allocation tracking tool](~/visualstudio/profiling/dotnet-alloc-tool) again on the updated code to see the dramatic difference in memory allocations.
135+
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.
138136

139-
When you profile the application with the compound assignment operators enabled, you'll observe a remarkable reduction: only **10 `GateAttendance` objects** are allocated during the entire concert simulation, compared to the previous 134 allocations. This represents a 92% reduction in object allocations!
137+
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!
140138

141-
The remaining 10 allocations come from the initial creation of the `GateAttendance` instances for each theater gate (4 main floor gates + 2 balcony gates = 6 initial instances), plus a few additional allocations from other parts of the simulation that don't use the compound operators.
139+
The remaining 10 allocations come from the initial creation of the `GateAttendance` instances for each theater gate (four main floor gates + two balcony gates = six initial instances), plus a few more allocations from other parts of the simulation that don't use the compound operators.
142140

143141
This allocation reduction translates to real performance benefits:
144142

@@ -149,12 +147,12 @@ This allocation reduction translates to real performance benefits:
149147

150148
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.
151149

152-
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 are already using `+=` in the simulation code, the principle applies to any scenario where you're repeatedly modifying objects rather than creating new instances.
150+
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.
153151

154-
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'll see small improvements.
152+
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.
155153

156154
## Related content
157155

158156
- [What's new in C# 14](../csharp-14.md)
159-
- [Operator overloading - define unary, arithmetic, equality and comparison operators](../../language-reference/operators/operator-overloading.md)
160-
- [Analyze memory usage by using the .NET Object Allocation tool - Visual Studio](~/visualstudio/profiling/dotnet-alloc-tool)
157+
- [Operator overloading - define unary, arithmetic, equality, and comparison operators](../../language-reference/operators/operator-overloading.md)
158+
- [Analyze memory usage by using the .NET Object Allocation tool - Visual Studio](/visualstudio/profiling/dotnet-alloc-tool)
Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
public record class GateAttendance(string GateId)
1+
// <GateAttendanceStarter>
2+
public record class GateAttendance(string GateId)
23
{
3-
public int Count { get; private set; }
4+
public int Count { get; init; }
45

56
public static GateAttendance operator ++(GateAttendance gate)
67
{
@@ -13,20 +14,14 @@
1314
GateAttendance updateGate = gate with { Count = gate.Count + partySize };
1415
return updateGate;
1516
}
17+
}
18+
// </GateAttendanceStarter>
1619

17-
// <CompoundAssignmentOperators>
18-
public void operator ++() => Count++;
19-
20-
public void operator +=(int partySize) => Count += partySize;
21-
// </CompoundAssignmentOperators>
22-
}
23-
24-
namespace InitialImplementation
20+
namespace FinalImplementation
2521
{
26-
// <GateAttendanceStarter>
2722
public record class GateAttendance(string GateId)
2823
{
29-
public int Count { get; init; }
24+
public int Count { get; private set; }
3025

3126
public static GateAttendance operator ++(GateAttendance gate)
3227
{
@@ -39,6 +34,11 @@ public record class GateAttendance(string GateId)
3934
GateAttendance updateGate = gate with { Count = gate.Count + partySize };
4035
return updateGate;
4136
}
42-
}
43-
// </GateAttendanceStarter>
37+
38+
// <CompoundAssignmentOperators>
39+
public void operator ++() => Count++;
40+
41+
public void operator +=(int partySize) => Count += partySize;
42+
// </CompoundAssignmentOperators>
43+
}
4444
}

0 commit comments

Comments
 (0)