Skip to content

Commit 0ba1268

Browse files
committed
Outline and sample
1 parent fc48880 commit 0ba1268

File tree

7 files changed

+347
-0
lines changed

7 files changed

+347
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ ehthumbs_vista.db
4949
[Bb]in/
5050
[Oo]bj/
5151
*.sln
52+
*.slnx
5253
*.user
5354

5455
# Ionide folder, used in F# for VSCode

docs/csharp/toc.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,8 @@ items:
174174
href: whats-new/version-update-considerations.md
175175
- name: Tutorials
176176
items:
177+
- name: Explore compound assignment
178+
href: whats-new/tutorials/compound-assignment-operators.md
177179
- name: Explore primary constructors
178180
href: whats-new/tutorials/primary-constructors.md
179181
- name: Explore static interface members
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
---
2+
title: Explore instance compound assignment operators
3+
description: "C# 14 enables instance compound assignment operators. These can provide better performance by minimizing allocations or copy operations. Learn how to create these operators."
4+
author: billwagner
5+
ms.author: wiwagn
6+
ms.service: dotnet-csharp
7+
ms.topic: tutorial
8+
ms.date: 09/15/2025
9+
10+
#customer intent: As a C# developer, I want implement compound assignment operators so that my algorithms are more efficient.
11+
12+
---
13+
14+
# Tutorial: Create compound assignment operators
15+
16+
17+
[Introduce and explain the purpose of the article.]
18+
19+
<!-- Required: Introductory paragraphs (no heading)
20+
21+
Write a brief introduction that can help the user
22+
decide whether the article is relevant for them and
23+
to describe how reading the article might benefit
24+
them.
25+
26+
-->
27+
28+
In this tutorial, you:
29+
30+
> [!div class="checklist"]
31+
> * Install prerequisites
32+
> * Analyze the starting sample
33+
> * Implement compound assignment operators
34+
> * Analyze completed sample
35+
36+
## Prerequisites
37+
38+
- The .NET 10 preview SDK. Download it from the [.NET download site](https://dotnet.microsoft.com/download/dotnet/10.0).
39+
- Visual Studio 2026 (preview). Download it from the [Visual Studio insiders page](https://visualstudio.microsoft.com/insiders/).
40+
41+
## Analyze the starting sample
42+
43+
- Run the app: understand what it does.
44+
- Read the `GateAttendance` class closely. Note that the operators allocate new instances of objects.
45+
- (optional) Run the Visual Studio performance profiler to count allocations (134 `GateAttendance` allocations)
46+
47+
## Implement compound assignment operators
48+
49+
## Analyze finished sample
50+
51+
- (Optional) Run the profiler again. Now, only 10 instance of GateAttendance objects are allocated.
52+
- Try and spot any additional allocations by replacing `+` operations with `+=` where possible.
53+
- Discuss other options, like `struct` types. Point out that compound assignment helps here by avoiding copy operations
54+
55+
## Related content
56+
57+
- What's new.
58+
- Operators in language reference
59+
- [Analyze memory usage by using the .NET Object Allocation tool - Visual Studio](~/visualstudio/profiling/dotnet-alloc-tool.md)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net10.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
<LangVersion>preview</LangVersion>
9+
</PropertyGroup>
10+
11+
</Project>
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
public record class GateAttendance(string GateId)
2+
{
3+
private int count = 0;
4+
5+
public int Count => count;
6+
7+
public static GateAttendance operator ++(GateAttendance gate)
8+
{
9+
GateAttendance updateGate = gate with { count = gate.count + 1 };
10+
return updateGate;
11+
}
12+
13+
public static GateAttendance operator +(GateAttendance gate, int partySize)
14+
{
15+
GateAttendance updateGate = gate with { count = gate.count + partySize };
16+
return updateGate;
17+
}
18+
19+
// New style:
20+
public void operator ++() => this.count++;
21+
22+
public void operator +=(int partySize) => this.count += partySize;
23+
}
24+
Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
public static class TheaterConcertSimulationCompound
2+
{
3+
private const int MAX_ATTENDANCE = 1000;
4+
private const int EXPECTED_SALES = 850;
5+
6+
public static void SimulateConcertAttendance()
7+
{
8+
Console.WriteLine("=== Royal Theater Concert Attendance Simulation ===");
9+
Console.WriteLine($"Venue Capacity: {MAX_ATTENDANCE} | Expected Sales: {EXPECTED_SALES}");
10+
Console.WriteLine("Concert: 'Symphony Under the Stars' - 7:30 PM\n");
11+
12+
// Initialize theater gates
13+
var theaterGates = new TheaterGates();
14+
15+
Console.WriteLine("--- Gate Status Before Concert ---");
16+
PrintTheaterStatus(theaterGates);
17+
18+
// Simulate pre-concert arrival patterns
19+
SimulatePreConcertArrivals(theaterGates);
20+
21+
Console.WriteLine("\n--- Gate Status After Pre-Concert Arrivals (6:30 PM) ---");
22+
PrintTheaterStatus(theaterGates);
23+
24+
// Simulate main arrival rush
25+
SimulateMainArrivalRush(theaterGates);
26+
27+
Console.WriteLine("\n--- Gate Status After Main Rush (7:15 PM) ---");
28+
PrintTheaterStatus(theaterGates);
29+
30+
// Simulate late arrivals
31+
SimulateLateArrivals(theaterGates);
32+
33+
Console.WriteLine("\n--- Final Attendance Report (7:30 PM - Concert Start) ---");
34+
GenerateFinalReport(theaterGates);
35+
}
36+
37+
private static void SimulatePreConcertArrivals(TheaterGates gates)
38+
{
39+
Console.WriteLine("--- Pre-Concert Arrivals (6:00 PM - 6:30 PM) ---");
40+
Console.WriteLine("Early patrons and season ticket holders arriving...\n");
41+
42+
// Early arrivals - mainly main floor, some balcony
43+
// Main floor gates - moderate traffic
44+
++gates.MainFloorGates[0]; // Single patron
45+
gates.MainFloorGates[0] += 2; // Couple
46+
gates.MainFloorGates[0] += 6; // Corporate early group
47+
gates.MainFloorGates[1] = gates.MainFloorGates[1] + 4; // Family
48+
gates.MainFloorGates[1] += 8; // Season ticket holders
49+
++gates.MainFloorGates[2]; // Single patron
50+
gates.MainFloorGates[2] += 5; // Early dinner group
51+
gates.MainFloorGates[3] += 3; // Small group
52+
gates.MainFloorGates[3] += 7; // VIP early access
53+
++gates.MainFloorGates[3]; // Individual VIP
54+
55+
// Balcony gates - lighter but increased traffic
56+
++gates.BalconyGates[0]; // Single patron
57+
gates.BalconyGates[0] += 4; // Early bird group
58+
gates.BalconyGates[1] += 2; // Couple
59+
gates.BalconyGates[1] += 6; // Student group with early tickets
60+
++gates.BalconyGates[1]; // Individual student
61+
62+
Console.WriteLine("Early arrivals processed through all gates.");
63+
}
64+
65+
private static void SimulateMainArrivalRush(TheaterGates gates)
66+
{
67+
Console.WriteLine("\n--- Main Arrival Rush (6:30 PM - 7:15 PM) ---");
68+
Console.WriteLine("Peak arrival time - all gates busy...\n");
69+
70+
var random = new Random();
71+
72+
// Heavy traffic through main floor gates
73+
for (int i = 0; i < 3; i++)
74+
{
75+
// Gate 1 - busiest entrance (target: ~100-130 people)
76+
gates.MainFloorGates[0] += random.Next(8, 15); // Corporate group
77+
++gates.MainFloorGates[0]; // Single patron
78+
gates.MainFloorGates[0] += random.Next(20, 30); // Tour/large group arrival
79+
gates.MainFloorGates[0] += random.Next(5, 12); // Family groups
80+
++gates.MainFloorGates[0]; // Solo attendee
81+
82+
// Gate 2 - second busiest (target: ~85-115 people)
83+
gates.MainFloorGates[1] = gates.MainFloorGates[1] + random.Next(6, 12); // Group booking
84+
++gates.MainFloorGates[1]; // Single patron
85+
gates.MainFloorGates[1] += random.Next(18, 28); // Large family/reunion
86+
gates.MainFloorGates[1] += random.Next(8, 15); // Corporate/business group
87+
gates.MainFloorGates[1] += random.Next(4, 8); // Couples/small groups
88+
++gates.MainFloorGates[1]; // Individual patron
89+
90+
// Gate 3 - moderate traffic (target: ~70-95 people)
91+
++gates.MainFloorGates[2]; // Individual
92+
gates.MainFloorGates[2] += random.Next(4, 8); // Small group
93+
gates.MainFloorGates[2] += random.Next(15, 22); // Community/organization group
94+
gates.MainFloorGates[2] += random.Next(10, 16); // Club/society members
95+
++gates.MainFloorGates[2]; // Solo attendee
96+
gates.MainFloorGates[2] += random.Next(6, 12); // Friends/social group
97+
98+
// Gate 4 - lighter but steady (target: ~60-85 people)
99+
gates.MainFloorGates[3] += random.Next(3, 6); // Family group
100+
gates.MainFloorGates[3] += random.Next(8, 15); // Celebration/event group
101+
++gates.MainFloorGates[3]; // Individual attendee
102+
gates.MainFloorGates[3] += random.Next(5, 10); // Couples/pairs
103+
104+
// Balcony gates - steady increased flow
105+
// Left balcony gate (target: ~80-100 people)
106+
++gates.BalconyGates[0]; // Single patron
107+
gates.BalconyGates[0] += random.Next(5, 10); // Small group
108+
gates.BalconyGates[0] += random.Next(15, 25); // Student/educational group
109+
gates.BalconyGates[0] += random.Next(10, 18); // Budget-conscious attendees
110+
++gates.BalconyGates[0]; // Individual
111+
gates.BalconyGates[0] += random.Next(6, 12); // Senior/community group
112+
113+
// Right balcony gate (target: ~70-95 people)
114+
gates.BalconyGates[1] += random.Next(4, 8); // Small group
115+
++gates.BalconyGates[1]; // Individual
116+
gates.BalconyGates[1] += random.Next(16, 24); // Academic/institutional group
117+
gates.BalconyGates[1] += random.Next(10, 16); // Community organization
118+
gates.BalconyGates[1] += random.Next(4, 8); // Young professionals/friends
119+
++gates.BalconyGates[1]; // Solo patron
120+
}
121+
122+
Console.WriteLine("Peak rush period completed - all gates processed heavy traffic.");
123+
}
124+
125+
private static void SimulateLateArrivals(TheaterGates gates)
126+
{
127+
Console.WriteLine("\n--- Late Arrivals (7:15 PM - 7:30 PM) ---");
128+
Console.WriteLine("Final patrons arriving before curtain...\n");
129+
130+
var random = new Random();
131+
132+
// Light but varied traffic as concert approaches
133+
// Main floor gates - scattered late arrivals (1-8 people per gate)
134+
++gates.MainFloorGates[0]; // Last-minute arrival
135+
gates.MainFloorGates[0] += random.Next(2, 6); // Delayed group
136+
137+
gates.MainFloorGates[1] += random.Next(1, 4); // Rushing small group
138+
gates.MainFloorGates[1] += random.Next(2, 7); // Traffic/parking delayed group
139+
140+
++gates.MainFloorGates[2]; // Single late arrival
141+
gates.MainFloorGates[2] += random.Next(1, 5); // Delayed couple/small group
142+
143+
gates.MainFloorGates[3] += random.Next(1, 4); // Late couple
144+
gates.MainFloorGates[3] += random.Next(2, 6); // Last-minute purchasers
145+
++gates.MainFloorGates[3]; // Solo rush arrival
146+
147+
// Balcony gates - lighter late traffic (1-5 people per gate)
148+
++gates.BalconyGates[0]; // Late balcony patron
149+
gates.BalconyGates[0] += random.Next(1, 4); // Delayed small group
150+
151+
gates.BalconyGates[1] += random.Next(1, 3); // Final arrivals
152+
gates.BalconyGates[1] += random.Next(2, 5); // Work-delayed group
153+
++gates.BalconyGates[1]; // Individual latecomer
154+
155+
Console.WriteLine("Final arrivals processed - concert about to begin!");
156+
}
157+
158+
private static void PrintTheaterStatus(TheaterGates gates)
159+
{
160+
Console.WriteLine("Main Floor Gates:");
161+
for (int i = 0; i < gates.MainFloorGates.Length; i++)
162+
{
163+
var gate = gates.MainFloorGates[i];
164+
Console.WriteLine($" {gate.GateId}: {gate.Count,3} attendees");
165+
}
166+
167+
var mainFloorTotal = gates.MainFloorGates.Sum(g => g.Count);
168+
Console.WriteLine($" Main Floor Subtotal: {mainFloorTotal,3} attendees");
169+
170+
Console.WriteLine("\nBalcony Gates:");
171+
for (int i = 0; i < gates.BalconyGates.Length; i++)
172+
{
173+
var gate = gates.BalconyGates[i];
174+
Console.WriteLine($" {gate.GateId}: {gate.Count,3} attendees");
175+
}
176+
177+
var balconyTotal = gates.BalconyGates.Sum(g => g.Count);
178+
Console.WriteLine($" Balcony Subtotal: {balconyTotal,3} attendees");
179+
180+
var totalAttendance = mainFloorTotal + balconyTotal;
181+
Console.WriteLine($"\nTotal Current Attendance: {totalAttendance,3} / {MAX_ATTENDANCE}");
182+
}
183+
184+
private static void GenerateFinalReport(TheaterGates gates)
185+
{
186+
var mainFloorTotal = gates.MainFloorGates.Sum(g => g.Count);
187+
var balconyTotal = gates.BalconyGates.Sum(g => g.Count);
188+
var totalAttendance = mainFloorTotal + balconyTotal;
189+
190+
PrintTheaterStatus(gates);
191+
192+
Console.WriteLine("\n" + new string('=', 50));
193+
Console.WriteLine("FINAL CONCERT ATTENDANCE REPORT");
194+
Console.WriteLine(new string('=', 50));
195+
196+
Console.WriteLine($"Expected Sales: {EXPECTED_SALES,3}");
197+
Console.WriteLine($"Actual Attendance: {totalAttendance,3}");
198+
Console.WriteLine($"Venue Capacity: {MAX_ATTENDANCE,3}");
199+
200+
var attendanceRate = (double)totalAttendance / EXPECTED_SALES * 100;
201+
var capacityUtilization = (double)totalAttendance / MAX_ATTENDANCE * 100;
202+
203+
Console.WriteLine($"Attendance Rate: {attendanceRate,5:F1}% of expected");
204+
Console.WriteLine($"Capacity Utilization: {capacityUtilization,5:F1}% of maximum");
205+
206+
// Gate distribution analysis
207+
Console.WriteLine($"\nGate Distribution:");
208+
Console.WriteLine($"Main Floor: {mainFloorTotal,3} ({(double)mainFloorTotal/totalAttendance*100:F1}%)");
209+
Console.WriteLine($"Balcony: {balconyTotal,3} ({(double)balconyTotal/totalAttendance*100:F1}%)");
210+
211+
// Performance indicators using switch expression
212+
var performanceMessage = totalAttendance switch
213+
{
214+
var t when t >= EXPECTED_SALES * 0.95 => "\n✅ Excellent attendance! Concert exceeded expectations.",
215+
var t when t >= EXPECTED_SALES * 0.85 => "\n✅ Good attendance! Concert met expectations.",
216+
var t when t >= EXPECTED_SALES * 0.70 => "\n⚠️ Moderate attendance. Consider marketing review.",
217+
_ => "\n❌ Low attendance. Significant marketing review needed."
218+
};
219+
220+
Console.WriteLine(performanceMessage);
221+
222+
Console.WriteLine("\nConcert begins! 🎼");
223+
}
224+
}
225+
226+
public struct TheaterGates
227+
{
228+
// Main floor gates (4 gates) - initialized with default gate instances
229+
public GateAttendance[] MainFloorGates { get; set; } =
230+
[
231+
new GateAttendance("Main-Floor-Gate-1"),
232+
new GateAttendance("Main-Floor-Gate-2"),
233+
new GateAttendance("Main-Floor-Gate-3"),
234+
new GateAttendance("Main-Floor-Gate-4")
235+
];
236+
237+
// Balcony gates (2 gates) - initialized with default gate instances
238+
public GateAttendance[] BalconyGates { get; set; } =
239+
[
240+
new GateAttendance("Balcony-Gate-Left"),
241+
new GateAttendance("Balcony-Gate-Right")
242+
];
243+
244+
// Explicit constructor required when using field initializers in structs
245+
public TheaterGates()
246+
{
247+
}
248+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
TheaterConcertSimulationCompound.SimulateConcertAttendance();
2+

0 commit comments

Comments
 (0)