Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
A C#14 felhasználó által definiált összetett hozzárendelési operátorokat ad hozzá, amelyek lehetővé teszik az adatstruktúra mutációját új példány létrehozása helyett. A C#korábbi verzióiban a kifejezés:
a += b;
A következő kódra kibővítve lett:
// compiler-generated code prior to C# 13:
var tmp = a + b;
a = tmp;
A bővítés a a típustól függően túlzott foglalásokhoz vezet új példányok létrehozásához, vagy több tulajdonság értékeinek másolásához, hogy értékeket állítson be a másolaton. Ha felhasználó által definiált operátort += ad hozzá, az azt jelzi, hogy egy típus jobb munkát végezhet a célobjektum helyben történő frissítésével.
A C# támogatja a meglévő bővítést, de csak akkor használja, ha egy összetett, felhasználó által definiált operátor nem érhető el.
Ebben az útmutatóban Ön:
- Futtassa a kezdő mintát.
- A kód szűk keresztmetszeteinek azonosítása.
- Új összetett hozzárendelési operátorok implementálása.
- Elemezze a kész mintát.
Előfeltételek
- A .NET 10 SDK. Töltse le a .NET letöltési webhelyről.
- Visual Studio 2026. Töltse le a Visual Studio oldaláról.
A kiindulási minta elemzése
Futtassa a kezdőalkalmazást. A GitHub-adattárból dotnet/docs szerezheti be. A mintaalkalmazás egy színházi helyszínen szimulálja a koncertek részvételének nyomon követését. A szimuláció a valósághű érkezési mintákat modellezi egész este, a korai résztvevőktől a fő rohanásig a showtime előtt. Ez a szimuláció bemutatja az objektumlefoglalásokat, amikor hagyományos operátorokat használ, szemben a felhasználó által definiált összetett hozzárendelési operátorokkal lehetséges hatékonyságnövekedéssel.
Az alkalmazás több színházi kapun (főszinten és erkélyszakaszon) keresztül követi nyomon a részvételt a koncertlátogatók érkezésekor. Minden kapu egy rekord használatával GateAttendance tartja nyilván a résztvevők számát. A szimuláció során a kód gyakran frissíti ezeket a számokat növekményes (++) és összeadási (+=) műveletekkel. A következő kód a szimuláció egy részét mutatja be:
// Gate 1 - busiest entrance (target: ~100-130 people)
gates.MainFloorGates[0] += random.Next(8, 15); // Corporate group
++gates.MainFloorGates[0]; // Single patron
gates.MainFloorGates[0] += random.Next(20, 30); // Tour/large group arrival
gates.MainFloorGates[0] += random.Next(5, 12); // Family groups
++gates.MainFloorGates[0]; // Solo attendee
// Gate 2 - second busiest (target: ~85-115 people)
gates.MainFloorGates[1] = gates.MainFloorGates[1] + random.Next(6, 12); // Group booking
++gates.MainFloorGates[1]; // Single patron
gates.MainFloorGates[1] += random.Next(18, 28); // Large family/reunion
gates.MainFloorGates[1] += random.Next(8, 15); // Corporate/business group
gates.MainFloorGates[1] += random.Next(4, 8); // Couples/small groups
++gates.MainFloorGates[1]; // Individual patron
A kód szűk keresztmetszeteinek azonosítása
A hagyományos operátorok esetében minden művelet új GateAttendance példányt hoz létre, ami jelentős memórialefoglalásokhoz vezet. Az indító GateAttendancenem módosítható. A kód nem tudja módosítani az objektum állapotát az inicializálás után. A tervezési döntéshez objektumok másolása szükséges, ha módosítania kell az állapotot.
A szimuláció futtatásakor a részletes kimenet a következőt mutatja:
- Kapunkénti jelenléti számok különböző érkezési időszakokban.
- Teljes jelenléti követés az összes kapun.
- Egy végleges átfogó jelentés a részvételi statisztikákkal.
Az alábbi szöveg néhány példakimenetet jelenít meg:
Peak arrival time - all gates busy...
Peak rush period completed - all gates processed heavy traffic.
--- Gate Status After Main Rush (7:15 PM) ---
Main Floor Gates:
Main-Floor-Gate-1: 145 attendees
Main-Floor-Gate-2: 168 attendees
Main-Floor-Gate-3: 149 attendees
Main-Floor-Gate-4: 71 attendees
Main Floor Subtotal: 533 attendees
Balcony Gates:
Balcony-Gate-Left: 164 attendees
Balcony-Gate-Right: 134 attendees
Balcony Subtotal: 298 attendees
Total Current Attendance: 831 / 1000
--- Late Arrivals (7:15 PM - 7:30 PM) ---
Final patrons arriving before curtain...
Final arrivals processed - concert about to begin!
Vizsgálja meg az indító GateAttendance rekord osztályt:
public record class GateAttendance(string GateId)
{
public int Count { get; init; }
public static GateAttendance operator ++(GateAttendance gate)
{
GateAttendance updateGate = gate with { Count = gate.Count + 1 };
return updateGate;
}
public static GateAttendance operator +(GateAttendance gate, int partySize)
{
GateAttendance updateGate = gate with { Count = gate.Count + partySize };
return updateGate;
}
}
A InitialImplementation.GateAttendance rekord a C#-ban történő operátor-túlterhelés hagyományos megközelítését mutatja be. Figyelje meg, hogy a növekmény operátor (++) és az összeadási operátor (+) is teljesen új GateAttendance példányokat hoz létre a with kifejezéssel. Minden alkalommal, amikor gate++ vagy gate += partySize kiírásra kerül, az operátorok egy új rekordpéldányt hoznak létre a frissített Count értékkel, majd visszaadják az új példányt. Bár ez a megközelítés fenntartja a nem módosíthatóságot és a szálbiztonságot, ez a gyakori memóriafoglalások költségével jár. A sok művelettel rendelkező forgatókönyvekben – például a több száz nézői frissítéssel rendelkező koncertszimulációhoz hasonlóan – ezek a foglalások gyorsan halmozódnak fel, ami hatással lehet a teljesítményre és növeli a szemétgyűjtési nyomást.
Ennek a foglalási viselkedésnek a méréséhez próbálja meg futtatni a .NET objektumfoglalás-követő eszközt a Visual Studióban. Amikor a koncertszimuláció során profilozza az aktuális megvalósítást, felfedezheti, hogy 134 GateAttendance objektumot foglal le a viszonylag kis méretű szimuláció elvégzéséhez. Minden operátorhívás létrehoz egy új példányt, amely bemutatja, hogy a foglalások milyen gyorsan halmozódhatnak fel valós forgatókönyvekben. Ez a mérés konkrét alapkonfigurációt biztosít az összetett hozzárendelési operátorokkal elért teljesítménybeli fejlesztések összehasonlításához.
Összetett hozzárendelési operátorok implementálása
A C# 14 olyan felhasználó által definiált összetett hozzárendelési operátorokat vezet be, amelyek új példányok létrehozása helyett helyszíni mutációkat tesznek lehetővé. Ezek az operátorok hatékonyabb alternatívát nyújtanak a hagyományos mintával, miközben fenntartják a jól ismert összetett hozzárendelési szintaxist.
Az összetett hozzárendelési operátorok olyan új szintaxist használnak, amely a void kulcsszó alkalmazásával deklarál visszatérési operator metódusokat. Adja hozzá a következő operátorokat az GateAttendance osztályhoz:
public void operator +=(int value) => this.property += value;
public void operator ++() => this.property++;
A hagyományos operátorok fő különbségei a következők:
-
Mutáció: Az aktuális példányt közvetlenül
thishasználatával módosítják. - Nincsenek új példányok: Az új objektumokat visszaadó hagyományos operátorokkal ellentétben az összetett operátorok módosítják a meglévőket.
-
Visszatérési típus: Az összetett hozzárendelési operátorok nem a típust magát, hanem
voidadják vissza.
Amikor a fordító összetett hozzárendelési kifejezésekkel (például a += b vagy ++a) találkozik, az a következő feloldási sorrendet követi:
-
Összetett hozzárendelési operátor keresése: Ha a típus felhasználó által definiált összetett hozzárendelési operátort határoz meg (például),
+=++használja közvetlenül. -
Visszalépés a hagyományos expanzióra: Ha nincs összetett operátor, bontsa ki a hagyományos formát (
a = a + b).
Ez azt jelenti, hogy mindkét megközelítés egyszerre implementálható. Az összetett operátorok elsőbbséget élveznek, ha elérhetők, de a hagyományos operátorok tartalékként szolgálnak olyan helyzetekben, ahol az összetett hozzárendelés nem megfelelő.
Az összetett hozzárendelési operátorok számos előnnyel járnak:
- Csökkentett foglalások: Módosítsa az objektumokat helyben, ahelyett, hogy új példányokat hozna létre.
- Jobb teljesítmény: Az ideiglenes objektumok létrehozásának megszüntetése és a szemétgyűjtési nyomás csökkentése.
-
Ismerős szintaxis: Használja ugyanazt
+=a szintaxist,++amelyet a fejlesztők már ismernek. - Visszamenőleges kompatibilitás: A hagyományos operátorok továbbra is tartalékként működnek.
Az új összetett hozzárendelési operátorok a következő kódban jelennek meg:
public void operator ++() => Count++;
public void operator +=(int partySize) => Count += partySize;
Megjegyzés:
A C++-t ismerő fejlesztőkben felmerülhet a kérdés, hogy miért van szükség csak egy ++ vagy -- operátorra. A fordító létrehozza a kódot a módosítás előtti vagy utáni kifejezés visszatérési értékként való használatára. A fordító által létrehozott kód az eredeti vagy a módosított érték alapján végzi el a hozzárendelést, attól függően, hogy az előnövekmény (++x) vagy a növekmény utáni (x++) meghívása megtörtént-e.
Kész minta elemzése
Most, hogy implementálta az összetett hozzárendelési operátorokat, ideje felmérni a teljesítmény javulását. A memóriafoglalások drámai különbségének méréséhez futtassa újra a .NET objektumfoglalás-követő eszközt a frissített kódon.
Ha az alkalmazást az összetett hozzárendelési operátorokkal profilozza, figyelemre méltó csökkenést tapasztal: a teljes koncertszimuláció során csak 10 GateAttendance objektum van lefoglalva az előző 134 foglaláshoz képest. Ez a frissítés 92% csökkenti az objektumlefoglalásokat!
A fennmaradó 10 kiosztás az egyes színházi kapuk GateAttendance kezdeti példányainak létrehozásából származik (négy fő emeleti kapu + két erkélykapu = hat kezdeti példány), valamint néhány további kiosztás a szimuláció más részeiből, amelyek nem használják az összetett operátorokat.
Ez az allokációcsökkentés valós teljesítménybeli előnyöket eredményez.
- Csökkent memóriaterhelés: Ritkábban előforduló szemétgyűjtési ciklusok.
- Jobb gyorsítótár-hely: Kevesebb objektumlétrehozás kevesebb memóriatöredezettséget jelent.
- Továbbfejlesztett átviteli teljesítmény: a kiosztásból és a gyűjtési többletterhelésből mentett processzorciklusok.
- Méretezhetőség: Az előnyök megsokszorozódnak a nagyobb műveleti kötettel rendelkező forgatókönyvekben.
A teljesítmény javítása még jelentősebbé válik az éles alkalmazásokban, ahol hasonló minták sokkal nagyobb méretekben fordulnak elő – képzelje el, hogy több millió tranzakciót követ nyomon, több ezer számlálót frissít, vagy nagy gyakoriságú adatfolyamokat dolgoz fel.
Próbáljon meg más lehetőségeket azonosítani az összetett hozzárendelési operátorok számára a kódbázisban. Keresd meg azokat a mintákat, amelyekben hagyományos hozzárendelési műveleteket használsz, és fontold meg, hogy hasznos lehet-e az összetett hozzárendelés szintaxisa. Miközben ezen műveletek némelyike már használja a += szimulációs kódban, az alapelv minden olyan forgatókönyvre vonatkozik, ahol inkább az objektumok ismételt módosítása történik, mint új példányok létrehozása.
Utolsó kísérletként módosítsa a GateAttendance típust a record class-ről record struct-re. Ez egy másik optimalizálás, és ebben a szimulációban működik, mert a szerkezet kis memóriaigényű. A szerkezet másolása GateAttendance nem költséges művelet. Ennek ellenére kisebb javításokat érhetsz el.