Kompatibilitási szabályok módosítása
A .NET a teljes előzményei során megkísérelt magas szintű kompatibilitást fenntartani verzióról verzióra és a .NET implementációira. Bár a .NET 5 (és a .NET Core) és a későbbi verziók a .NET-keretrendszer képest új technológiának tekinthetők, a .NET implementációjának két fő tényezője korlátozza, hogy eltérjen a .NET-keretrendszer:
Sok fejlesztő vagy eredetileg fejlesztett vagy fejleszt tovább .NET-keretrendszer alkalmazásokat. Konzisztens viselkedésre számítanak a .NET-implementációkban.
A .NET Standard kódtárprojektek lehetővé teszik a fejlesztők számára, hogy olyan kódtárakat hozzanak létre, amelyek .NET-keretrendszer és .NET 5 (és .NET Core) és újabb verziók által megosztott közös API-kat céloznak meg. A fejlesztők elvárják, hogy a .NET 5-alkalmazásokban használt kódtárak ugyanúgy viselkedjenek, mint a .NET-keretrendszer-alkalmazásokban használt kódtárak.
A .NET-implementációk kompatibilitása mellett a fejlesztők magas szintű kompatibilitást várnak a .NET adott implementációjának verziói között. A .NET Core egy korábbi verziójához írt kódnak zökkenőmentesen kell futnia a .NET 5-ös vagy újabb verzióján. Valójában sok fejlesztő arra számít, hogy a .NET újonnan kiadott verzióiban talált új API-knak kompatibilisnek kell lenniük azokkal a kiadás előtti verziókkal is, amelyekben ezeket az API-kat bevezették.
Ez a cikk ismerteti a kompatibilitást befolyásoló módosításokat, valamint azt, hogy a .NET-csapat hogyan értékeli ki az egyes módosítástípusokat. A .NET-csapat által a lehetséges kompatibilitástörő változások megközelítésének megértése különösen hasznos azon fejlesztők számára, akik olyan lekéréses kérelmeket nyitnak meg, amelyek módosítják a meglévő .NET API-k viselkedését.
A következő szakaszok a .NET API-k módosításainak kategóriáit és azok alkalmazáskompatibilitásra gyakorolt hatását ismertetik. A módosítások vagy engedélyezettek (✔️), nem engedélyezettek (❌), vagy ítélkeznek, és kiértékelik, hogy az előző viselkedés mennyire kiszámítható, nyilvánvaló és konzisztens volt (❓).
Feljegyzés
- A .NET-kódtárak változásainak kiértékelése mellett a kódtár-fejlesztők ezen feltételek segítségével is kiértékelhetik a több .NET-implementációt és verziót célzó kódtáraik módosításait.
- A kompatibilitási kategóriákról, például a visszamenőleges és a korábbi kompatibilitásról a kódmódosítások kompatibilitását ismertető cikkben talál további információt.
A közbeszerzési szerződés módosítása
A kategória változásai módosítják egy típus nyilvános felületét. A kategória legtöbb változtatása nem engedélyezett, mivel sértik a visszamenőleges kompatibilitást (az API egy korábbi verziójával fejlesztett alkalmazás egy későbbi verzióban történő újrafordítás nélkül történő végrehajtásának képességét).
Típusok
✔️ ENGEDÉLYEZVE: Az illesztő implementáció eltávolítása egy típusból, ha az illesztő már alaptípussal implementálva van
❓ ÍTÉLETRE VAN SZÜKSÉG: Új felületi implementáció hozzáadása egy típushoz
Ez elfogadható változás, mert nem érinti hátrányosan a meglévő ügyfeleket. A típus bármilyen módosításának az itt meghatározott elfogadható változások határain belül kell működnie ahhoz, hogy az új implementáció elfogadható maradjon. Rendkívül óvatosságra van szükség, ha olyan interfészeket ad hozzá, amelyek közvetlenül befolyásolják a tervező vagy szerializáló azon képességét, hogy olyan kódot vagy adatokat generáljanak, amelyek nem használhatók fel lefelé. Ilyen például az ISerializable interfész.
❓ ÍTÉLETRE VAN SZÜKSÉG: Új alaposztály bevezetése
Egy típus két meglévő típus közötti hierarchiába vezethető be, ha nem vezet be új absztrakt tagokat, vagy nem módosítja a meglévő típusok szemantikáját vagy viselkedését. Például a .NET-keretrendszer 2.0-ban az DbConnection osztály egy új alaposztály SqlConnectionlett, amely korábban közvetlenül a forrásból Componentszármazott.
✔️ ENGEDÉLYEZETT: Típus áthelyezése egyik szerelvényről a másikra
A régi szerelvényt úgy kell megjelölni, hogy az TypeForwardedToAttribute az új szerelvényre mutat.
✔️ ENGEDÉLYEZETT: Szerkezettípus módosítása típusra
readonly struct
readonly struct
A típus típusrastruct
történő módosítása nem engedélyezett.✔️ ENGEDÉLYEZETT: A lezárt vagy absztrakt kulcsszó hozzáadása egy típushoz, ha nincsenek akadálymentes (nyilvános vagy védett) konstruktorok
✔️ ENGEDÉLYEZETT: Egy típus láthatóságának bővítése
❌LETILTVA: Egy típus névterének vagy nevének módosítása
❌NEM ENGEDÉLYEZETT: Nyilvános típus átnevezése vagy eltávolítása
Ez megszakítja az átnevezett vagy eltávolított típust használó összes kódot.
Feljegyzés
Ritkán előfordulhat, hogy a .NET eltávolít egy nyilvános API-t. További információ: API-eltávolítás a .NET-ben. További információ: . A NET támogatási szabályzatát lásd: .NET támogatási szabályzat.
❌NEM ENGEDÉLYEZETT: Az enumerálás alapjául szolgáló típus módosítása
Ez a fordítási idő és a viselkedéstörő változás, valamint egy bináris törésmódosítás, amely az attribútumargumentumokat elválaszthatatlanné teheti.
❌NEM ENGEDÉLYEZETT: Korábban feloldott típus zárolása
❌NEM ENGEDÉLYEZETT: Illesztő hozzáadása a felület alaptípusainak készletéhez
Ha egy felület olyan felületet implementál, amelyet korábban nem implementált, a felület eredeti verzióját implementáló összes típus megszakad.
❓ ÍTÉLETRE VAN SZÜKSÉG: Egy osztály eltávolítása az alaposztályok készletéből vagy egy interfész a implementált interfészek készletéből
A felület eltávolítására vonatkozó szabály alól egyetlen kivétel van: hozzáadhatja az eltávolított felületből származó illesztő implementációját. Eltávolíthatja IDisposable például, ha a típus vagy felület implementálva IComponentvan , amely implementálja IDisposablea elemet.
❌NEM ENGEDÉLYEZETT: Típus
readonly struct
módosítása szerkezettípusraA típus típusra
readonly struct
történő módosításastruct
azonban engedélyezett.❌NEM ENGEDÉLYEZETT: Szerkezettípus módosítása típusra
ref struct
, és fordítva❌NEM ENGEDÉLYEZETT: Egy típus láthatóságának csökkentése
Egy típus láthatóságának növelése azonban engedélyezett.
Tagok
✔️ ENGEDÉLYEZETT: A nem virtuális tag láthatóságának bővítése
✔️ ENGEDÉLYEZETT: Absztrakt tag hozzáadása olyan nyilvános típushoz, amely nem rendelkezik akadálymentes (nyilvános vagy védett) konstruktorokkal, vagy a típus zárt
Az absztrakt tag hozzáadása azonban olyan típushoz, amely akadálymentes (nyilvános vagy védett) konstruktorokkal rendelkezik, és nem
sealed
engedélyezett.✔️ ENGEDÉLYEZETT: Védett tag láthatóságának korlátozása, ha a típus nem rendelkezik akadálymentes (nyilvános vagy védett) konstruktorokkal, vagy a típus zárt
✔️ ENGEDÉLYEZETT: Tag áthelyezése a hierarchiában magasabb osztályba, mint az a típus, amelyből eltávolították
✔️ ENGEDÉLYEZETT: Felülbírálás hozzáadása vagy eltávolítása
A felülbírálás bevezetése miatt a korábbi felhasználók átugorhatják a felülbírálást a bázis hívásakor.
✔️ ENGEDÉLYEZETT: Konstruktor hozzáadása egy osztályhoz, valamint egy paraméter nélküli konstruktor, ha az osztály korábban nem rendelkezett konstruktorokkal
Nem lehet azonban olyan konstruktort hozzáadni egy olyan osztályhoz, amely korábban nem rendelkezett konstruktorokkal a paraméter nélküli konstruktor hozzáadása nélkül .
✔️ ENGEDÉLYEZETT: Váltás visszatérési
ref readonly
értékreref
(kivéve a virtuális módszereket vagy interfészeket)✔️ ENGEDÉLYEZETT: A mező írásvédett eltávolítása, kivéve, ha a mező statikus típusa nem módosítható értéktípus
✔️ ENGEDÉLYEZETT: Korábban nem definiált új esemény meghívása
❓ ÍTÉLETRE VAN SZÜKSÉG: Új példánymező hozzáadása típushoz
Ez a változás hatással van a szerializálásra.
❌NEM ENGEDÉLYEZETT: Nyilvános tag vagy paraméter átnevezése vagy eltávolítása
Ez megszakítja az átnevezett vagy eltávolított tagot vagy paramétert használó összes kódot.
Ez magában foglalja a getter vagy a setter tulajdonságból való eltávolítását vagy átnevezését, valamint az enumerálási tagok átnevezését vagy eltávolítását.
❌NEM ENGEDÉLYEZETT: Tag hozzáadása egy felülethez
Ha implementációt ad meg, egy új tag hozzáadása egy meglévő felülethez nem feltétlenül fog fordítási hibákat eredményezni az alsóbb rétegbeli szerelvényekben. Azonban nem minden nyelv támogatja az alapértelmezett felülettagokat (DIM-eket). Bizonyos esetekben a futtatókörnyezet nem tudja eldönteni, hogy melyik alapértelmezett felülettagot hívja meg. Ezért a tag meglévő felülethez való hozzáadása kompatibilitástörő változásnak minősül.
❌NEM ENGEDÉLYEZETT: Nyilvános állandó vagy enumerálási tag értékének módosítása
❌NEM ENGEDÉLYEZETT: Tulajdonság, mező, paraméter vagy visszatérési érték típusának módosítása
❌NEM ENGEDÉLYEZETT: Paraméterek hozzáadása, eltávolítása vagy sorrendjének módosítása
❌NEM ENGEDÉLYEZETT: A be- vagy ki- vagy újraf kulcsszó hozzáadása vagy eltávolítása egy paraméterből
❌NEM ENGEDÉLYEZETT: Paraméter átnevezése (beleértve az eset módosítását is)
Ennek két oka van:
Megszakítja a késedelmesen kötött forgatókönyveket, például a Visual Basic késői kötési funkcióját és a C# dinamikus használatát.
Megszakítja a forráskompatibilitást, ha a fejlesztők nevesített argumentumokat használnak.
❌NEM ENGEDÉLYEZETT: Visszatérési
ref
értékről visszatérésiref readonly
értékre váltás❌️ NEM ENGEDÉLYEZETT: Váltás egy
ref readonly
ref
virtuális metódus vagy felület visszatérési értékére❌NEM ENGEDÉLYEZETT: Kivonat hozzáadása vagy eltávolítása egy tagból
❌LETILTVA: A virtuális kulcsszó eltávolítása egy tagból
❌LETILTVA: A virtuális kulcsszó hozzáadása egy taghoz
Bár ez gyakran nem jelent kompatibilitástörő változást, mert a C#-fordító általában kibocsátja a nem virtuális metódusok hívására vonatkozó callvirt Intermediate Language (IL) utasításokat (
callvirt
null értékű ellenőrzést végez, míg egy normál hívás nem), ez a viselkedés több okból sem marad el:Nem a C# az egyetlen nyelv, amelyet a .NET céloz meg.
A C#-fordító egyre inkább megpróbál normál hívásra optimalizálni
callvirt
, amikor a célmetódus nem virtuális, és valószínűleg nem null értékű (például a ?. null propagálási operátoron keresztül elért metódus).
A metódus virtuálissá tétele azt jelenti, hogy a fogyasztói kód gyakran nem virtuálisan hívja meg.
❌LETILTVA: Virtuális tag absztrakciója
A virtuális tag olyan metódus-implementációt biztosít, amelyet egy származtatott osztály felülírhat . Az absztrakt tag nem biztosít implementációt, ezért felül kell bírálni .
❌NEM ENGEDÉLYEZETT: A lezárt kulcsszó hozzáadása egy felülettaghoz
Ha
sealed
hozzáad egy alapértelmezett illesztőtagot, az nem virtuálisvá válik, megakadályozva, hogy egy származtatott típus implementációja meghívja az adott tagot.❌NEM ENGEDÉLYEZETT: Absztrakt tag hozzáadása olyan nyilvános típushoz, amely akadálymentes (nyilvános vagy védett) konstruktorokkal rendelkezik, és nincs lezárva
❌LETILTVA: Statikus kulcsszó hozzáadása vagy eltávolítása egy tagból
❌NEM ENGEDÉLYEZETT: Olyan túlterhelés hozzáadása, amely kizárja a meglévő túlterhelést, és más viselkedést határoz meg
Ez megszakítja az előző túlterheléshez kötött meglévő ügyfeleket. Ha például egy osztálynak egyetlen verziója van egy metódusnak, amely elfogadja a metódust UInt32, egy meglévő fogyasztó sikeresen kapcsolódik ehhez a túlterheléshez egy Int32 érték átadásakor. Ha azonban olyan túlterhelést ad hozzá, amely elfogadja Int32az újrafordítást vagy a késői kötést, a fordító most már az új túlterheléshez kapcsolódik. Ha eltérő viselkedési eredmények jelentkeznek, ez egy kompatibilitástörő változás.
❌NEM ENGEDÉLYEZETT: Konstruktor hozzáadása olyan osztályhoz, amely korábban nem rendelkezett konstruktorral a paraméter nélküli konstruktor hozzáadása nélkül
❌️ NEM ENGEDÉLYEZETT: Írásvédett hozzáadása egy mezőhöz
❌NEM ENGEDÉLYEZETT: Tag láthatóságának csökkentése
Ez magában foglalja a védett tagok láthatóságának csökkentését, ha vannak akadálymentes (
public
vagyprotected
) konstruktorok, és a típus nincs lezárva. Ha ez nem így van, a védett tagok láthatóságának csökkentése engedélyezett.A tagok láthatóságának növelése engedélyezett.
❌NEM ENGEDÉLYEZETT: Tag típusának módosítása
Egy metódus visszatérési értéke, illetve egy tulajdonság vagy mező típusa nem módosítható. Például egy olyan metódus aláírása, amely visszaad egy metódust Object , nem módosítható Stringegy , vagy fordítva.
❌LETILTVA: Példánymező hozzáadása olyan szerkezethez, amely nem rendelkezik nem közzétételi mezőkkel
Ha egy struktúra csak nyilvános mezőkkel rendelkezik, vagy egyáltalán nem tartalmaz mezőket, a hívók az adott típusú helyieket deklarálhatják anélkül, hogy meghívják az struktúra konstruktorát, vagy először inicializálják a helyit
default(T)
, amíg az összes nyilvános mező be van állítva a szerkezeten az első használat előtt. Ha új mezőket ad hozzá – nyilvános vagy nem nyilvános – egy ilyen szerkezethez, az a hívók forrásmegszakítási módosítása, mivel a fordítónak most további mezőket kell inicializálnia.Emellett az új mezők – nyilvános vagy nem nyilvános – hozzáadása egy olyan szerkezethez, amely nem tartalmaz mezőket vagy csak nyilvános mezőket, bináris törést jelent a kódjukra alkalmazott
[SkipLocalsInit]
hívók számára. Mivel a fordító nem tudott ezekről a mezőkről a fordításkor, olyan IL-t bocsáthat ki, amely nem inicializálja teljesen a szerkezetet, ami a nem inicializált veremadatokból való létrehozáshoz vezet.Ha egy szerkezet nem nyilvános mezőkkel rendelkezik, a fordító már kikényszeríti az inicializálást a konstruktoron keresztül, és
default(T)
az új példánymezők hozzáadása nem jelent kompatibilitástörő változást.❌NEM ENGEDÉLYEZETT: Meglévő esemény kirúgása, amikor még soha nem aktiválódott
Működésbeli változások
Szerelvények
✔️ ENGEDÉLYEZETT: A szerelvény hordozhatóvá tétele, ha ugyanazok a platformok továbbra is támogatottak
❌LETILTVA: Egy szerelvény nevének módosítása
❌LETILTVA: A szerelvény nyilvános kulcsának módosítása
Tulajdonságok, mezők, paraméterek és visszatérési értékek
✔️ ENGEDÉLYEZETT: Tulajdonság, mező, visszatérési érték vagy kimenő paraméter értékének módosítása származtatottabb típusra
Például egy metódus, amely egy típust Object ad vissza, visszaadhat egy példányt String . (A metódus aláírása azonban nem módosítható.)
✔️ ENGEDÉLYEZETT: Egy tulajdonság vagy paraméter elfogadott értékeinek tartományának növelése, ha a tag nem virtuális
Bár a metódusnak átadható vagy a tag által visszaadott értékek tartománya kibővülhet, a paraméter vagy a tag típusa nem. Ha például a metódusnak átadott értékek 0-124-ről 0-255-re bővülhetnek, a paraméter típusa nem válthat Byte Int32át a következőre.
❌NEM ENGEDÉLYEZETT: Egy tulajdonság vagy paraméter elfogadott értékeinek tartományának növelése, ha a tag virtuális
Ez a módosítás megszakítja a meglévő felülbírált tagokat, amelyek nem fognak megfelelően működni a kiterjesztett értéktartomány esetében.
❌NEM ENGEDÉLYEZETT: Egy tulajdonság vagy paraméter elfogadott értékeinek tartományának csökkentése
❌NEM ENGEDÉLYEZETT: Tulajdonság, mező, visszatérési érték vagy kimenő paraméter visszaadott értékeinek tartományának növelése
❌NEM ENGEDÉLYEZETT: Tulajdonság, mező, metódus visszatérési értékének vagy kimenő paraméterének visszaadott értékeinek módosítása
❌NEM ENGEDÉLYEZETT: Tulajdonság, mező vagy paraméter alapértelmezett értékének módosítása
A paraméter alapértelmezett értékének módosítása vagy eltávolítása nem bináris törés. A paraméter alapértelmezett értékének eltávolítása forrástörés, és az alapértelmezett paraméterérték módosítása viselkedési törést eredményezhet az újrafordítás után.
Ezért a paraméter alapértelmezett értékeinek eltávolítása elfogadható abban az esetben, ha ezeket az alapértelmezett értékeket egy új metódus túlterhelésére "helyezi át" a kétértelműség kiküszöbölése érdekében. Vegyük például egy meglévő metódust
MyMethod(int a = 1)
. Ha két választható paraméterrel túlterheléstMyMethod
vezet be, ésb
az alapértelmezett értéketa
az új túlterhelésre helyezi át, megőrizheti a kompatibilitást.a
Most a két túlterhelés ésMyMethod(int a)
MyMethod(int a = 1, int b = 2)
. Ez a minta lehetővé tesziMyMethod()
a fordítást.❌NEM ENGEDÉLYEZETT: Numerikus visszatérési érték pontosságának módosítása
❓ ÍTÉLETRE VAN SZÜKSÉG: A bemenet elemzésének módosítása és új kivételek kiváltása (még akkor is, ha az elemzési viselkedés nincs megadva a dokumentációban).
Kivételek
✔️ ENGEDÉLYEZETT: A meglévő kivételnél származtatottabb kivételt eredményez
Mivel az új kivétel egy meglévő kivétel alosztálya, a korábbi kivételkezelő kód továbbra is kezeli a kivételt. A 4. .NET-keretrendszer például a kultúralétrehozási és -lekérési módszerek ahelyettArgumentException, hogy CultureNotFoundException a kultúra nem található volna. Mivel CultureNotFoundException a ArgumentExceptionszármazik, ez elfogadható változás.
✔️ ENGEDÉLYEZETT: Pontosabb kivételt eredményez, mint NotSupportedExceptiona , , NotImplementedExceptionNullReferenceException
✔️ ENGEDÉLYEZETT: Visszavonhatatlannak minősülő kivétel eldobálása
A helyreállíthatatlan kivételeket nem szabad elkapni, hanem egy magas szintű catch-all kezelőnek kell kezelnie. Ezért a felhasználóknak nem kell olyan kóddal rendelkezniük, amely elkapja ezeket a explicit kivételeket. A helyreállíthatatlan kivételek a következők:
✔️ ENGEDÉLYEZETT: Új kivétel dobása egy új kódútvonalon
A kivételnek csak olyan új kódútvonalra kell vonatkoznia, amely új paraméterértékekkel vagy állapottal van végrehajtva, és amelyet nem lehet végrehajtani az előző verziót megcélozó meglévő kóddal.
✔️ ENGEDÉLYEZETT: Kivétel eltávolítása robusztusabb viselkedés vagy új forgatókönyvek engedélyezéséhez
Például egy
Divide
olyan módszer, amely korábban csak a pozitív értékeket kezelte és más módon dobta, ArgumentOutOfRangeException úgy módosítható, hogy a negatív és a pozitív értékeket is támogassa kivétel nélkül.✔️ ENGEDÉLYEZVE: Hibaüzenet szövegének módosítása
A fejlesztők nem támaszkodhatnak a hibaüzenetek szövegére, amelyek a felhasználói kultúra alapján is változnak.
❌NEM ENGEDÉLYEZETT: Kivétel kivetése a fent nem felsorolt egyéb esetekben
❌LETILTVA: Kivétel eltávolítása a fent nem felsorolt egyéb esetekben
Attribútumok
✔️ ENGEDÉLYEZETT: Nem megfigyelhető attribútum értékének módosítása
❌NEM ENGEDÉLYEZETT: Megfigyelhető attribútum értékének módosítása
❓ ÍTÉLETRE VAN SZÜKSÉG: Attribútum eltávolítása
Az attribútumok (például NonSerializedAttribute) eltávolítása a legtöbb esetben kompatibilitástörő változás.
Platformtámogatás
✔️ ENGEDÉLYEZETT: Korábban nem támogatott platformon végzett művelet támogatása
❌LETILTVA: Nem támogat vagy igényel adott szervizcsomagot egy korábban platformon támogatott művelethez
Belső implementáció változásai
❓ ÍTÉLETRE VAN SZÜKSÉG: Belső típus felületének módosítása
Ezek a módosítások általában engedélyezettek, bár a magánreflexiót megszakítják. Bizonyos esetekben, amikor a népszerű külső kódtárak vagy a fejlesztők nagy száma a belső API-któl függ, előfordulhat, hogy ezek a módosítások nem engedélyezettek.
❓ ÍTÉLETRE VAN SZÜKSÉG: A tag belső végrehajtásának módosítása
Ezek a módosítások általánosan engedélyezettek, bár a magánreflexiót megszakítják. Bizonyos esetekben, amikor az ügyfélkód gyakran a magánreflexiótól függ, vagy ha a változás nem kívánt mellékhatásokat okoz, előfordulhat, hogy ezek a változások nem engedélyezettek.
✔️ ENGEDÉLYEZETT: Művelet teljesítményének javítása
A művelet teljesítményének módosítása alapvető fontosságú, de az ilyen módosítások megszakíthatják a művelet aktuális sebességére támaszkodó kódot. Ez különösen igaz az aszinkron műveletek időzítésétől függő kódra. A teljesítményváltozásnak nincs hatása a szóban forgó API egyéb viselkedésére; ellenkező esetben a változás megtörik.
✔️ ENGEDÉLYEZETT: Egy művelet teljesítményének közvetett (és gyakran kedvezőtlen) módosítása
Ha a szóban forgó módosítás más okból nem minősül kompatibilitástörőnek, ez elfogadható. Gyakran olyan műveleteket kell végrehajtani, amelyek további műveleteket is tartalmazhatnak, vagy amelyek új funkciókat adnak hozzá. Ez szinte mindig hatással lesz a teljesítményre, de elengedhetetlen lehet ahhoz, hogy a szóban forgó API a várt módon működjön.
❌NEM ENGEDÉLYEZETT: Szinkron API módosítása aszinkronra (és fordítva)
Kódmódosítások
✔️ ENGEDÉLYEZETT: Paramok hozzáadása paraméterhez
❌NEM ENGEDÉLYEZETT: A szerkezet átalakítása osztályra, és fordítva
❌NEM ENGEDÉLYEZETT: Az ellenőrzött kulcsszó hozzáadása kódblokkhoz
Ez a módosítás azt okozhatja, hogy a korábban végrehajtott kód egy olyan kódot eredményez OverflowException , amely elfogadhatatlan.
❌NEM ENGEDÉLYEZETT: Params eltávolítása egy paraméterből
❌NEM ENGEDÉLYEZETT: Az események aktiválási sorrendjének módosítása
A fejlesztők észszerűen elvárhatják, hogy az események ugyanabban a sorrendben aktiválódnak, és a fejlesztői kód gyakran attól függ, hogy az események milyen sorrendben legyenek aktiválva.
❌NEM ENGEDÉLYEZETT: Egy esemény egy adott műveleten történő növelésének eltávolítása
❌LETILTVA: A megadott események számának módosítása
❌NEM ENGEDÉLYEZETT: A számbavételi típus hozzáadása FlagsAttribute