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.
Jegyzet
Ez a cikk egy funkcióspecifikáció. A specifikáció a funkció tervezési dokumentumaként szolgál. Tartalmazza a specifikáció javasolt módosításait, valamint a funkció tervezése és fejlesztése során szükséges információkat. Ezeket a cikkeket mindaddig közzéteszik, amíg a javasolt specifikációmódosításokat nem véglegesítik, és be nem építik a jelenlegi ECMA-specifikációba.
A szolgáltatás specifikációja és a befejezett implementáció között eltérések lehetnek. Ezeket a különbségeket a vonatkozó nyelvi tervezési értekezlet (LDM) megjegyzései rögzítik.
A funkcióspektusok C# nyelvi szabványba való bevezetésének folyamatáról a specifikációkcímű cikkben olvashat bővebben.
Bajnoki probléma: https://github.com/dotnet/csharplang/issues/4665
Összefoglalás
A C#-nak támogatnia kell a következő felhasználó által definiált operátorok checked variánsainak meghatározását, hogy a felhasználók a megfelelő módon engedélyezhesse vagy kizárhassák a túlcsordulási viselkedést:
- A
++és--egyoperandusú operátorok §12.8.16 és §12.9.6. - A
-unáris operátor §12.9.3. - A
+,-,*és/bináris operátorok §12.10. - Explicit konverziós operátorok.
Motiváció
A felhasználó nem deklarálhat típust, és nem támogathatja az operátorok ellenőrzött és nem ellenőrzött verzióit. Ez megnehezíti a különböző algoritmusok portját a kódtárak csapata által közzétett javasolt generic math felületek használatához. Hasonlóképpen, ez lehetetlenné teszi egy olyan típus, mint a Int128 vagy a UInt128 kitettségét anélkül, hogy a nyelv egyidejűleg biztosítaná a saját támogatását a kompatibilitást veszélyeztető változások elkerülése érekében.
Részletes kialakítás
Szintaxis
Az operátorok nyelvtana (§15.10) úgy lesz módosítva, hogy a checked kulcsszó a operator kulcsszó után közvetlenül az operátor token előtt legyen.
overloadable_unary_operator
: '+' | 'checked'? '-' | '!' | '~' | 'checked'? '++' | 'checked'? '--' | 'true' | 'false'
;
overloadable_binary_operator
: 'checked'? '+' | 'checked'? '-' | 'checked'? '*' | 'checked'? '/' | '%' | '&' | '|' | '^' | '<<'
| right_shift | '==' | '!=' | '>' | '<' | '>=' | '<='
;
conversion_operator_declarator
: 'implicit' 'operator' type '(' type identifier ')'
| 'explicit' 'operator' 'checked'? type '(' type identifier ')'
;
Például:
public static T operator checked ++(T x) {...}
public static T operator checked --(T x) {...}
public static T operator checked -(T x) {...}
public static T operator checked +(T lhs, T rhs) {...}
public static T operator checked -(T lhs, T rhs) {...}
public static T operator checked *(T lhs, T rhs) {...}
public static T operator checked /(T lhs, T rhs) {...}
public static explicit operator checked U(T x) {...}
public static T I1.operator checked ++(T x) {...}
public static T I1.operator checked --(T x) {...}
public static T I1.operator checked -(T x) {...}
public static T I1.operator checked +(T lhs, T rhs) {...}
public static T I1.operator checked -(T lhs, T rhs) {...}
public static T I1.operator checked *(T lhs, T rhs) {...}
public static T I1.operator checked /(T lhs, T rhs) {...}
public static explicit I1.operator checked U(T x) {...}
Az alábbi rövidség kedvéért az checked kulcsszóval rendelkező operátort checked operator, a nélküle lévő operátort pedig regular operator-nak nevezzük. Ezek a kifejezések nem alkalmazhatók olyan operátorokra, amelyek nem rendelkeznek checked űrlappal.
Szemantika
A felhasználó által definiált checked operator kivételt okozhat, ha egy művelet eredménye túl nagy ahhoz, hogy a céltípusban szerepeljen. Az, hogy mit jelent túl nagynak lenni, valójában a céltípus jellegétől függ, és nem írja elő a nyelv. A kivétel általában egy System.OverflowException, de a nyelv nem rendelkezik ezzel kapcsolatos konkrét követelményekkel.
A felhasználó által definiált regular operator várhatóan nem okoz kivételt, ha egy művelet eredménye túl nagy ahhoz, hogy a céltípusban szerepeljen. Ehelyett várható, hogy egy csonkolt eredményt képviselő példányt adjon vissza. Az, hogy mit jelent túl nagynak lenni, és hogy csonkoljanak, valójában a céltípus jellegétől függ, és a nyelv nem írja elő.
Minden meglévő, felhasználó által definiált operátor, amely checked űrlapot támogat, a regular operatorskategóriájába tartozik. Érthető, hogy sokan valószínűleg nem követik a fent megadott szemantikát, de szemantikai elemzés céljából a fordító feltételezi, hogy igen.
Bejelölt és be nem jelölt környezet egy checked operator
A checked operator törzsében lévő ellenőrzött/nem ellenőrzött környezetet nem befolyásolja a checked kulcsszó jelenléte. Más szóval a környezet ugyanaz, mint közvetlenül az operátor deklaráció elején. A fejlesztőnek explicit módon át kell váltania a környezetet, ha az algoritmus egy része nem támaszkodhat az alapértelmezett környezetre.
Nevek a metaadatokban
Az ECMA-335 "I.10.3.1 Unary operátorok" szakaszát úgy kell módosítani, hogy az op_CheckedIncrement, op_CheckedDecrement, op_CheckedUnaryNegation szerepeljen az ellenőrzött egyváltozós operátorokat megvalósító módszerek neveként, ++, -- és -.
Az ECMA-335 "I.10.3.2 Bináris operátorok" szakaszát úgy kell módosítani, hogy az op_CheckedAddition, op_CheckedSubtraction, op_CheckedMultiply, op_CheckedDivision szerepeljen az ellenőrzött +, -, *és / bináris operátorokat implementáló módszerek neveként.
Az ECMA-335 "I.10.3.3 Konverziós operátorok" szakaszát úgy kell módosítani, hogy az op_CheckedExplicit szerepeljen az ellenőrzött explicit konverziós operátort implementáló metódus neveként.
Unary operátorok
Az egyes műveletek checked operators a §15.10.2szabályait követik.
A checked operator deklarációhoz szükség van egy regular operator párhoz tartozó deklarációra is, és a visszatérési típusnak is meg kell egyeznie. Máskülönben fordítási időhiba lép fel.
public struct Int128
{
// This is fine, both a checked and regular operator are defined
public static Int128 operator checked -(Int128 lhs);
public static Int128 operator -(Int128 lhs);
// This is fine, only a regular operator is defined
public static Int128 operator --(Int128 lhs);
// This should error, a regular operator must also be defined
public static Int128 operator checked ++(Int128 lhs);
}
Bináris operátorok
A bináris checked operators kövesse a szabályokat a §15.10.3szerint.
A checked operator deklarációhoz szükség van egy regular operator párhoz tartozó deklarációra is, és a visszatérési típusnak is meg kell egyeznie. Máskülönben fordítási időhiba lép fel.
public struct Int128
{
// This is fine, both a checked and regular operator are defined
public static Int128 operator checked +(Int128 lhs, Int128 rhs);
public static Int128 operator +(Int128 lhs, Int128 rhs);
// This is fine, only a regular operator is defined
public static Int128 operator -(Int128 lhs, Int128 rhs);
// This should error, a regular operator must also be defined
public static Int128 operator checked *(Int128 lhs, Int128 rhs);
}
Jelölt felhasználó által definiált operátorok
A jelölt felhasználói operátorok (§12.4.6) a következőképpen lesznek módosítva (a hozzáadások/módosítások félkövérek).
Egy T típus és egy operator op(A)művelet esetén – ahol op egy túlterhelhető operátor, A pedig egy argumentumlista –, a T esetében a operator op(A) által biztosított felhasználó által definiált operátorok halmaza az alábbiak szerint lesz meghatározva:
- Határozza meg a
T0típust. HaTnull értékű típus,T0a mögöttes típus, ellenkező esetbenT0egyenlőT. - Keresse meg a felhasználó által definiált operátorok készletét,
U. Ez a készlet a következőkből áll:-
A
uncheckedértékelési környezetben azoperator opösszes rendszeresT0deklaráció. -
checkedkiértékelési környezetben az összes ellenőrzött és rendszeresoperator opdeklarációT0, kivéve azokat a reguláris deklarációkat, amelyek párosan egyezőchecked operatordeklarációval rendelkeznek.
-
A
- Ha az
operator opösszesUdeklarációja és az ilyen operátorok összes feloldott formája esetében legalább egy operátor alkalmazható (12.4.6 . § - Az alkalmazható függvénytag) az argumentumlistaAtekintetében , akkor a jelölt operátorok halmazaT0minden ilyen alkalmazható operátorból áll . - Ellenkező esetben, ha
T0object, a jelölt operátorok készlete üres. - Ellenkező esetben a
T0által biztosított jelölt operátorok halmaza aT0közvetlen alaposztálya által biztosított jelölt operátorok készlete, vagy aT0tényleges alaposztálya, haT0típusparaméter.
Hasonló szabályokat lesznek alkalmazva a jelölt operátorok meghatározásánál az interfészekben https://github.com/dotnet/csharplang/blob/main/meetings/2017/LDM-2017-06-27.md#shadowing-within-interfaces.
A §12.8.20 szakaszt úgy kell módosítani, hogy az tükrözze az ellenőrzött/nem ellenőrzött környezetnek az unáris és bináris operátorok túlterhelési feloldására gyakorolt hatását.
1. példa:
public class MyClass
{
public static void Add(Int128 lhs, Int128 rhs)
{
// Resolves to `op_CheckedAddition`
Int128 r1 = checked(lhs + rhs);
// Resolves to `op_Addition`
Int128 r2 = unchecked(lhs + rhs);
// Resolve to `op_Subtraction`
Int128 r3 = checked(lhs - rhs);
// Resolve to `op_Subtraction`
Int128 r4 = unchecked(lhs - rhs);
// Resolves to `op_CheckedMultiply`
Int128 r5 = checked(lhs * rhs);
// Error: Operator '*' cannot be applied to operands of type 'Int128' and 'Int128'
Int128 r6 = unchecked(lhs * rhs);
}
public static void Divide(Int128 lhs, byte rhs)
{
// Resolves to `op_Division` - it is a better match than `op_CheckedDivision`
Int128 r4 = checked(lhs / rhs);
}
}
public struct Int128
{
public static Int128 operator checked +(Int128 lhs, Int128 rhs);
public static Int128 operator +(Int128 lhs, Int128 rhs);
public static Int128 operator -(Int128 lhs, Int128 rhs);
// Cannot be declared in C# - missing unchecked operator, but could be declared by some other language
public static Int128 operator checked *(Int128 lhs, Int128 rhs);
public static Int128 operator checked /(Int128 lhs, int rhs);
public static Int128 operator /(Int128 lhs, byte rhs);
}
2. példa:
class C
{
static void Add(C2 x, C3 y)
{
object o;
// error CS0034: Operator '+' is ambiguous on operands of type 'C2' and 'C3'
o = checked(x + y);
// C2.op_Addition
o = unchecked(x + y);
}
}
class C1
{
// Cannot be declared in C# - missing unchecked operator, but could be declared by some other language
public static C1 operator checked + (C1 x, C3 y) => new C3();
}
class C2 : C1
{
public static C2 operator + (C2 x, C1 y) => new C2();
}
class C3 : C1
{
}
3. példa:
class C
{
static void Add(C2 x, C3 y)
{
object o;
// error CS0034: Operator '+' is ambiguous on operands of type 'C2' and 'C3'
o = checked(x + y);
// C1.op_Addition
o = unchecked(x + y);
}
}
class C1
{
public static C1 operator + (C1 x, C3 y) => new C3();
}
class C2 : C1
{
// Cannot be declared in C# - missing unchecked operator, but could be declared by some other language
public static C2 operator checked + (C2 x, C1 y) => new C2();
}
class C3 : C1
{
}
Konverziós operátorok
A checked operators konverzió kövesse a §15.10.4szabályait.
A checked operator deklarációhoz azonban szükség van egy regular operatorpáronkénti nyilatkozatra. Máskülönben fordítási időhiba lép fel.
A következő bekezdés
A konverziós operátor aláírása a forrástípusból és a céltípusból áll. (Ez az egyetlen olyan tagi forma, amelynek a visszatérési típusa részt vesz az aláírásban.) A konverziós operátor implicit vagy explicit besorolása nem része az operátor aláírásának. Így egy osztály vagy struktúra nem deklarálhat implicit és explicit konverziós operátort is ugyanazzal a forrás- és céltípussal.
úgy lesz módosítva, hogy egy típus deklarálhassa az azonos forrás- és céltípusú explicit konverziók ellenőrzött és rendszeres formáit. Egy típus nem deklarálhat implicit és ellenőrzött explicit konverziós operátort ugyanazzal a forrás- és céltípussal.
Felhasználó által definiált explicit konverziók feldolgozása
A §10.5.5harmadik pontja:
- Keresse meg a felhasználó által definiált és átemelt konverziós operátorok halmazát,
U. Ez a készlet az osztályok vagy struktúrák által aD-ban deklarált, felhasználó által definiált és emelt implicit vagy explicit konverziós operátorokból áll, amelyek olyan típusról alakulnak át egy másik típusra, amelyet azSkörülfog, vagy amely azS-et körülfogja, a által körülfogott vagy a -t körülfogó típusra. HaUüres, a konvertálás nincs meghatározva, és fordítási időhiba lép fel.
helyére a következő felsorolásjelek kerülnek:
- Keresse meg a konverziós operátorok készletét,
U0. Ez a készlet a következőkből áll:-
A
uncheckedkiértékelési környezetben a felhasználó által meghatározott implicit vagy explicit konverziós operátorok, amelyeket az osztályok vagy a structok deklaráltakD. -
checkedkiértékelési környezetben a felhasználó által definiált implicit vagy szokványos/ellenőrzött explicit konverziós operátorok, amelyeket az osztályok vagy struktúrák deklaráltakD, kivéve azokat a szokványos explicit konverziós operátorokat, amelyek páronként összepárosítottchecked operatordeklarációval rendelkeznek ugyanabban a deklarálási típusban.
-
A
- Keresse meg a felhasználó által definiált és átemelt konverziós operátorok halmazát,
U. Ez a készlet a felhasználó által definiált és felemelt implicit vagy explicit konverziós operátorokból áll,U0, amelyek egySáltal körülölelt vagy körülölelő típusból egyTáltal körülölelt vagy körülölelő típussá alakulnak át. HaUüres, a konvertálás nincs meghatározva, és fordítási időhiba lép fel.
A 11.8.20 szakasz, az ellenőrzött és nem ellenőrzött operátorok, úgy lesz módosítva, hogy tükrözze a felhasználó által definiált explicit konverziók feldolgozására gyakorolt hatást.
Operátorok implementálása
A checked operator nem implementálja regular operator-t, és fordítva is.
Linq-kifejezésfák
A Checked operators támogatva lesz a Linq Expression Trees-ben. Létre fog jönni egy csomópont UnaryExpression/BinaryExpression megfelelő MethodInfo-mal.
A következő gyári módszereket fogják használni:
public static UnaryExpression NegateChecked (Expression expression, MethodInfo? method);
public static BinaryExpression AddChecked (Expression left, Expression right, MethodInfo? method);
public static BinaryExpression SubtractChecked (Expression left, Expression right, MethodInfo? method);
public static BinaryExpression MultiplyChecked (Expression left, Expression right, MethodInfo? method);
public static UnaryExpression ConvertChecked (Expression expression, Type type, MethodInfo? method);
Vegye figyelembe, hogy a C# nem támogatja a kifejezésfák hozzárendeléseit, ezért az ellenőrzött növekmény/csökkenés sem támogatott.
Nincs gyári módszer az ellenőrzött osztáshoz. Ezzel kapcsolatban van egy nyitott kérdés: ellenőrzött osztás a Linq kifejezésfákban.
Dinamikus
Megvizsgáljuk, hogy a CoreCLR-ben a dinamikus meghívásban lévő ellenőrzött operátorok támogatásának hozzáadása mennyibe kerül, és végrehajtjuk a megvalósítást, ha a költségek nem túl magasak. Ez egy idézet https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-09.md.
Hátránya
Ez további összetettséggel bővíti a nyelvet, és lehetővé teszi a felhasználók számára, hogy a típusukon több kompatibilitástörő módosítást vezessenek be.
Alternatívák
A kódtárak által elérhetővé tenni tervezett általános matematikai felületek elnevezett metódusokat (például AddChecked) tehetnek közzé. Az elsődleges hátránya az, hogy ez kevésbé olvasható/karbantartható, és nem élvezi a nyelvi elsőbbségi szabályok előnyeit az operátorok körül.
Ez a szakasz a tárgyalt, de nem implementált alternatívákat sorolja fel
A checked kulcsszó elhelyezése
Másik lehetőségként a checked kulcsszó közvetlenül a operator kulcsszó előtti helyre helyezhető át:
public static T checked operator ++(T x) {...}
public static T checked operator --(T x) {...}
public static T checked operator -(T x) {...}
public static T checked operator +(T lhs, T rhs) {...}
public static T checked operator -(T lhs, T rhs) {...}
public static T checked operator *(T lhs, T rhs) {...}
public static T checked operator /(T lhs, T rhs) {...}
public static explicit checked operator U(T x) {...}
public static T checked I1.operator ++(T x) {...}
public static T checked I1.operator --(T x) {...}
public static T checked I1.operator -(T x) {...}
public static T checked I1.operator +(T lhs, T rhs) {...}
public static T checked I1.operator -(T lhs, T rhs) {...}
public static T checked I1.operator *(T lhs, T rhs) {...}
public static T checked I1.operator /(T lhs, T rhs) {...}
public static explicit checked I1.operator U(T x) {...}
Vagy áthelyezhető az operátormódosítók készletébe:
operator_modifier
: 'public'
| 'static'
| 'extern'
| 'checked'
| operator_modifier_unsafe
;
public static checked T operator ++(T x) {...}
public static checked T operator --(T x) {...}
public static checked T operator -(T x) {...}
public static checked T operator +(T lhs, T rhs) {...}
public static checked T operator -(T lhs, T rhs) {...}
public static checked T operator *(T lhs, T rhs) {...}
public static checked T operator /(T lhs, T rhs) {...}
public static checked explicit operator U(T x) {...}
public static checked T I1.operator ++(T x) {...}
public static checked T I1.operator --(T x) {...}
public static checked T I1.operator -(T x) {...}
public static checked T I1.operator +(T lhs, T rhs) {...}
public static checked T I1.operator -(T lhs, T rhs) {...}
public static checked T I1.operator *(T lhs, T rhs) {...}
public static checked T I1.operator /(T lhs, T rhs) {...}
public static checked explicit I1.operator U(T x) {...}
unchecked kulcsszó
A unchecked kulcsszót a checked kulcsszóval azonos pozícióban támogatandó javaslatok a következő lehetséges jelentéssel:
- Egyszerűen az operátor szokásos jellegének explicit megjelenítése, vagy
- Talán egy olyan operátor eltérő ízének kijelölése, amelyet egy
uncheckedkontextusban kellene használni. A nyelv támogathatjaop_Addition,op_CheckedAdditionésop_UncheckedAdditiona kompatibilitástörő módosítások számának korlátozásához. Ez egy újabb összetettségi réteget ad hozzá, amely valószínűleg nem szükséges a legtöbb kódban.
Operátornevek az ECMA-335-ben
Másik lehetőségként az operátornevek lehetnek op_UnaryNegationChecked, op_AdditionChecked, op_SubtractionChecked, op_MultiplyChecked, op_DivisionChecked, a végén pedig Checked. Úgy tűnik azonban, hogy már létezik egy minta, amely a nevek operátorszavaval való befejezésére van kialakítva. A op_RightShiftUnsigned operátor helyett például egy op_UnsignedRightShift operátor van.
Checked operators nem alkalmazhatók unchecked környezetben
A fordító, amikor tagkeresést hajt végre a felhasználó által definiált operátorok unchecked környezetben való kereséséhez, figyelmen kívül hagyhatja checked operators. Ha olyan metaadatok jelennek meg, amelyek csak egy checked operatorhatároznak meg, akkor fordítási hiba történik.
public class MyClass
{
public static void Add(Int128 lhs, Int128 rhs)
{
// Resolves to `op_CheckedMultiply`
Int128 r5 = checked(lhs * rhs);
// Error: Operator '*' cannot be applied to operands of type 'Int128' and 'Int128'
Int128 r5 = unchecked(lhs * rhs);
}
}
public struct Int128
{
public static Int128 operator checked *(Int128 lhs, Int128 rhs);
}
Bonyolultabb operátorkeresési és túlterhelésfeloldási szabályok checked környezetben
A fordító, amikor tagkeresést hajt végre a felhasználó által definiált operátorok checked környezetben való kereséséhez, figyelembe veszi a Checkedvégződő alkalmazható operátorokat is. Vagyis, ha a fordító megpróbálná megtalálni a bináris összeadás operátorhoz megfelelő függvénytagokat, akkor mind a op_Addition, mind a op_AdditionCheckedértékeket keresné. Ha az egyetlen alkalmazható függvénytag egy checked operator, akkor azt fogja használni. Ha létezik regular operator és checked operator is, és egyformán alkalmazhatók, a checked operator lesz előnyben részesítve. Ha regular operator és checked operator is létezik, és a regular operator pontosan egyezik, de a checked operator nem, akkor a fordító a regular operator-et fogja előnyben részesíteni.
public class MyClass
{
public static void Add(Int128 lhs, Int128 rhs)
{
// Resolves to `op_CheckedAddition`
Int128 r1 = checked(lhs + rhs);
// Resolves to `op_Addition`
Int128 r2 = unchecked(lhs + rhs);
// Resolve to `op_Subtraction`
Int128 r3 = checked(lhs - rhs);
// Resolve to `op_Subtraction`
Int128 r4 = unchecked(lhs - rhs);
}
public static void Multiply(Int128 lhs, byte rhs)
{
// Resolves to `op_Multiply` even though `op_CheckedMultiply` is also applicable
Int128 r4 = checked(lhs * rhs);
}
}
public struct Int128
{
public static Int128 operator checked +(Int128 lhs, Int128 rhs);
public static Int128 operator +(Int128 lhs, Int128 rhs);
public static Int128 operator -(Int128 lhs, Int128 rhs);
public static Int128 operator checked *(Int128 lhs, int rhs);
public static Int128 operator *(Int128 lhs, byte rhs);
}
Egy másik módszer a felhasználó által definiált operátorok halmazának létrehozására
Unary operátor túlterhelésének feloldása
Feltételezve, hogy regular operator megegyezik a unchecked kiértékelési környezettel, checked operator megegyezik a checked kiértékelési környezettel, és egy olyan operátor, amely nem rendelkezik checked formával (például +), bármelyik környezettel egyezik, az első pont a §12.4.4 - Unary operátor túlterhelési feloldás:
- A
Xáltal a művelethezoperator op(x)által biztosított jelölt felhasználó által megadott operátorok készletét a 12.4.6.
A következő két felsorolásjelre lesz cserélve:
- A
Xáltal a művelethez megadott,operator op(x)a jelenlegi ellenőrzött/nem ellenőrzött környezetnek megfelelő, jelölt felhasználó által megadott operátorok halmaza felhasználó által definiáltszabályaival van meghatározva. - Ha a felhasználó által definiált jelölt operátorok készlete nem üres, akkor ez lesz a művelet jelölt operátorainak halmaza. Ellenkező esetben a
Xáltal a művelethez megadott,operator op(x)az ellenkezőleg ellenőrzött/nem ellenőrzött környezetnek megfelelő, jelölt felhasználó által megadott operátorok készletét a 12.4.6.
Bináris operátor túlterhelésének feloldása
Feltételezve, hogy a regular operator egyezik a unchecked kiértékelési környezettel, a checked operator egyezik a checked kiértékelési környezettel, és egy olyan operátor, amelynek nincs checked formája (például %), bármely környezettel egyezik, a 12.4.5 szakaszának első pontja - bináris operátorok túlterhelésének feloldása -:
- A
Xés aYáltal aoperator op(x,y)művelethez megadott, felhasználó által megadott jelölt operátorok készlete lesz meghatározva. A halmaz aXés aYáltal biztosított jelölt operátorok egyesüléséből áll, amelyek mindegyike a §12.4.6 - Jelölt felhasználó által definiált operátorokszabályai alapján van meghatározva. HaXésYazonos típusúak, vagy ha aXés aYegy közös alaptípusból származik, akkor a megosztott jelölt operátorok csak egyszer fordulnak elő az egyesített csoportban.
A következő két felsorolásjelre lesz cserélve:
- A
XésYáltal a művelethez megadott, a felhasználó által jelölt operátorok készleteoperator op(x,y)megfelel az aktuális ellenőrzött/nem ellenőrzött környezetnek, van meghatározva. A halmaz aXés aYáltal biztosított jelölt operátorok egyesüléséből áll, amelyek mindegyike a §12.4.6 - Jelölt felhasználó által definiált operátorokszabályai alapján van meghatározva. HaXésYazonos típusúak, vagy ha aXés aYegy közös alaptípusból származik, akkor a megosztott jelölt operátorok csak egyszer fordulnak elő az egyesített csoportban. - Ha a felhasználó által definiált jelölt operátorok készlete nem üres, akkor ez lesz a művelet jelölt operátorainak halmaza. Ellenkező esetben meghatározásra kerül a
XésYáltal biztosított, felhasználó által definiált operátorok készlete aoperator op(x,y)művelethez, amely az ellenkező ellenőrzött/nem ellenőrzött környezet kontextusával van összhangban. A halmaz aXés aYáltal biztosított jelölt operátorok egyesüléséből áll, amelyek mindegyike a §12.4.6 - Jelölt felhasználó által definiált operátorokszabályai alapján van meghatározva. HaXésYazonos típusúak, vagy ha aXés aYegy közös alaptípusból származik, akkor a megosztott jelölt operátorok csak egyszer fordulnak elő az egyesített csoportban.
1. példa:
public class MyClass
{
public static void Add(Int128 lhs, Int128 rhs)
{
// Resolves to `op_CheckedAddition`
Int128 r1 = checked(lhs + rhs);
// Resolves to `op_Addition`
Int128 r2 = unchecked(lhs + rhs);
// Resolve to `op_Subtraction`
Int128 r3 = checked(lhs - rhs);
// Resolve to `op_Subtraction`
Int128 r4 = unchecked(lhs - rhs);
// Resolves to `op_CheckedMultiply`
Int128 r5 = checked(lhs * rhs);
// Resolves to `op_CheckedMultiply`
Int128 r5 = unchecked(lhs * rhs);
}
public static void Divide(Int128 lhs, byte rhs)
{
// Resolves to `op_CheckedDivision`
Int128 r4 = checked(lhs / rhs);
}
}
public struct Int128
{
public static Int128 operator checked +(Int128 lhs, Int128 rhs);
public static Int128 operator +(Int128 lhs, Int128 rhs);
public static Int128 operator -(Int128 lhs, Int128 rhs);
public static Int128 operator checked *(Int128 lhs, Int128 rhs);
public static Int128 operator checked /(Int128 lhs, int rhs);
public static Int128 operator /(Int128 lhs, byte rhs);
}
2. példa:
class C
{
static void Add(C2 x, C3 y)
{
object o;
// C1.op_CheckedAddition
o = checked(x + y);
// C2.op_Addition
o = unchecked(x + y);
}
}
class C1
{
public static C1 operator checked + (C1 x, C3 y) => new C3();
}
class C2 : C1
{
public static C2 operator + (C2 x, C1 y) => new C2();
}
class C3 : C1
{
}
3. példa:
class C
{
static void Add(C2 x, C3 y)
{
object o;
// C2.op_CheckedAddition
o = checked(x + y);
// C1.op_Addition
o = unchecked(x + y);
}
}
class C1
{
public static C1 operator + (C1 x, C3 y) => new C3();
}
class C2 : C1
{
public static C2 operator checked + (C2 x, C1 y) => new C2();
}
class C3 : C1
{
}
4. példa:
class C
{
static void Add(C2 x, byte y)
{
object o;
// C1.op_CheckedAddition
o = checked(x + y);
// C2.op_Addition
o = unchecked(x + y);
}
static void Add2(C2 x, int y)
{
object o;
// C2.op_Addition
o = checked(x + y);
// C2.op_Addition
o = unchecked(x + y);
}
}
class C1
{
public static C1 operator checked + (C1 x, byte y) => new C1();
}
class C2 : C1
{
public static C2 operator + (C2 x, int y) => new C2();
}
5. példa:
class C
{
static void Add(C2 x, byte y)
{
object o;
// C2.op_CheckedAddition
o = checked(x + y);
// C1.op_Addition
o = unchecked(x + y);
}
static void Add2(C2 x, int y)
{
object o;
// C1.op_Addition
o = checked(x + y);
// C1.op_Addition
o = unchecked(x + y);
}
}
class C1
{
public static C1 operator + (C1 x, int y) => new C1();
}
class C2 : C1
{
public static C2 operator checked + (C2 x, byte y) => new C2();
}
Felhasználó által definiált explicit konverziók feldolgozása
Feltételezve, hogy regular operator megfelel unchecked kiértékelési környezetnek, és checked operator megfelel checked kiértékelési környezetnek, a §10.5.3, felhasználó által definiált átalakítások értékelésének harmadik pontja a következő:
- Keresse meg a felhasználó által definiált és átemelt konverziós operátorok halmazát,
U. Ez a készlet az osztályok vagy struktúrák által aD-ban deklarált, felhasználó által definiált és emelt implicit vagy explicit konverziós operátorokból áll, amelyek olyan típusról alakulnak át egy másik típusra, amelyet azSkörülfog, vagy amely azS-et körülfogja, a által körülfogott vagy a -t körülfogó típusra. HaUüres, a konvertálás nincs meghatározva, és fordítási időhiba lép fel.
helyére a következő felsorolásjelek kerülnek:
- Keresse meg az alkalmazható, felhasználó által definiált és feloldott explicit konverziós operátorok készletét, amelyek megfelelnek az aktuális ellenőrzött/nem ellenőrzött környezetnek ,,
U0. Ez a készlet az osztályok vagyDáltal deklarált, felhasználó által definiált és felemelt explicit konverziós operátorokból áll, amelyek megfelelnek az aktuális ellenőrzött/nem ellenőrzött környezetnek, és azSáltal magában foglalt vagy magában foglalt típusbólTáltal magában foglalt vagy magában foglalt típussá alakulnak át. - Keresse meg a felhasználó által definiált és felemelt explicit konverziós operátorok készletét, egyeznek az ellenkezőleg ellenőrzött/nem ellenőrzött környezettel,
U1. HaU0nem üres,U1üres. Ellenkező esetben ez a csoport a felhasználó által definiált és felemeltté vált explicit konverziós operátorokból áll, amelyeket az osztályok vagy struktúrák deklarálnak a(z)D-ban, és amelyek a(z) környezeti kontextusnak megfelelően ellentétes felügyelt/felügyeletlen helyzetet kezelnek, és átalakítanak egy olyan típust, amelyet a(z)Skörülírt vagy körülírt, egy olyan típussá, amelyet a(z)Tkörülírt vagy körülírt. - Keresse meg a felhasználó által definiált és átemelt konverziós operátorok halmazát,
U. Ez a készlet aU0és aU1operátorokból, valamint azD-ben deklarált, felhasználó által definiált és emelt implicit konverziós operátorokból áll, amelyek olyan típusok közötti átalakításokat végeznek, amelyek azS-at vagy magukban foglalják, vagy azok részei, hogy aT-et vagy magukban foglalják, vagy azok részeivé váljanak. HaUüres, a konvertálás nincs meghatározva, és fordítási időhiba lép fel.
Egy másik módszer a felhasználó által definiált operátorok halmazának létrehozására
Unary operátor túlterhelésének feloldása
A §12.4.4 szakasz első felsoroláspontja az alábbiak szerint lesz módosítva (a kiegészítések félkövérek).
- A
Xáltal aoperator op(x)művelethez megadott, felhasználó által definiált jelölt operátorok halmazát az alábbi "Felhasználó által definiált jelölt operátorok" szakasz szabályai határozzák meg. Ha a készlet legalább egy operátort tartalmaz bejelölt formában, a normál formában lévő összes operátor el lesz távolítva a készletből.
A 12.8.20 szakaszt úgy kell módosítani, hogy az tükrözze az ellenőrzött/nem ellenőrzött környezetnek a nem túlterhelt operátorok túlterhelésének feloldására gyakorolt hatását.
Bináris operátor túlterhelésének feloldása
A 12.4.5 szakasz első felsorolása az alábbiak szerint lesz módosítva (a kiegészítések félkövérek).
- A
Xés aYáltal aoperator op(x,y)művelethez megadott, felhasználó által megadott jelölt operátorok készlete lesz meghatározva. A csoport aXáltal biztosított jelölt operátorok és aYáltal biztosított jelölt operátorok egyesítő egyesítéséből áll, amelyek mindegyike a "Jelölt felhasználó által definiált operátorok" szakasz szabályai alapján van meghatározva. HaXésYazonos típusúak, vagy ha aXés aYegy közös alaptípusból származik, akkor a megosztott jelölt operátorok csak egyszer fordulnak elő az egyesített csoportban. Ha a készlet legalább egy operátort tartalmaz bejelölt formában, a normál formában lévő összes operátor el lesz távolítva a készletből.
A §12.8.20 szakasz ellenőrzött és nem ellenőrzött operátorai úgy lesznek módosítva, hogy tükrözzék, hogyan hat a bináris operátorok túlterhelésének feloldására a checked/unchecked kontextus.
Jelölt felhasználó által definiált operátorok
A §12.4.6 – A felhasználó által definiált jelölt operátorok szakasz az alábbiak szerint módosul (a kiegészítések félkövérek).
Egy T típus és egy operator op(A)művelet esetén – ahol op egy túlterhelhető operátor, A pedig egy argumentumlista –, a T esetében a operator op(A) által biztosított felhasználó által definiált operátorok halmaza az alábbiak szerint lesz meghatározva:
- Határozza meg a
T0típust. HaTnull értékű típus,T0a mögöttes típus, ellenkező esetbenT0egyenlőT. - Minden
operator opdeklaráció esetében az ellenőrzött és rendszeres űrlapjaikbancheckedértékelési kontextusban, és csak auncheckedértékelési környezetbenT0és az ilyen operátorok összes felemelt formájában, ha legalább egy operátor alkalmazható (12.6.4.2) az argumentumlistaAtekintetében , akkor a jelölt operátorok készleteT0összes ilyen alkalmazható operátorából áll . - Ellenkező esetben, ha
T0object, a jelölt operátorok készlete üres. - Ellenkező esetben a
T0által biztosított jelölt operátorok halmaza aT0közvetlen alaposztálya által biztosított jelölt operátorok készlete, vagy aT0tényleges alaposztálya, haT0típusparaméter.
Hasonló szűrést alkalmazunk a https://github.com/dotnet/csharplang/blob/main/meetings/2017/LDM-2017-06-27.md#shadowing-within-interfacesinterfészek jelölt operátorainak meghatározásakor.
A §12.8.20 szakaszt úgy kell módosítani, hogy tükrözze azt a hatást, amelyet az ellenőrzött/nem ellenőrzött környezet az unáris és bináris operátorok túlterhelésének feloldására gyakorol.
1. példa:
public class MyClass
{
public static void Add(Int128 lhs, Int128 rhs)
{
// Resolves to `op_CheckedAddition`
Int128 r1 = checked(lhs + rhs);
// Resolves to `op_Addition`
Int128 r2 = unchecked(lhs + rhs);
// Resolve to `op_Subtraction`
Int128 r3 = checked(lhs - rhs);
// Resolve to `op_Subtraction`
Int128 r4 = unchecked(lhs - rhs);
// Resolves to `op_CheckedMultiply`
Int128 r5 = checked(lhs * rhs);
// Error: Operator '*' cannot be applied to operands of type 'Int128' and 'Int128'
Int128 r5 = unchecked(lhs * rhs);
}
public static void Divide(Int128 lhs, byte rhs)
{
// Resolves to `op_CheckedDivision`
Int128 r4 = checked(lhs / rhs);
}
}
public struct Int128
{
public static Int128 operator checked +(Int128 lhs, Int128 rhs);
public static Int128 operator +(Int128 lhs, Int128 rhs);
public static Int128 operator -(Int128 lhs, Int128 rhs);
public static Int128 operator checked *(Int128 lhs, Int128 rhs);
public static Int128 operator checked /(Int128 lhs, int rhs);
public static Int128 operator /(Int128 lhs, byte rhs);
}
2. példa:
class C
{
static void Add(C2 x, C3 y)
{
object o;
// C1.op_CheckedAddition
o = checked(x + y);
// C2.op_Addition
o = unchecked(x + y);
}
}
class C1
{
public static C1 operator checked + (C1 x, C3 y) => new C3();
}
class C2 : C1
{
public static C2 operator + (C2 x, C1 y) => new C2();
}
class C3 : C1
{
}
3. példa:
class C
{
static void Add(C2 x, C3 y)
{
object o;
// C2.op_CheckedAddition
o = checked(x + y);
// C1.op_Addition
o = unchecked(x + y);
}
}
class C1
{
public static C1 operator + (C1 x, C3 y) => new C3();
}
class C2 : C1
{
public static C2 operator checked + (C2 x, C1 y) => new C2();
}
class C3 : C1
{
}
4. példa:
class C
{
static void Add(C2 x, byte y)
{
object o;
// C2.op_Addition
o = checked(x + y);
// C2.op_Addition
o = unchecked(x + y);
}
static void Add2(C2 x, int y)
{
object o;
// C2.op_Addition
o = checked(x + y);
// C2.op_Addition
o = unchecked(x + y);
}
}
class C1
{
public static C1 operator checked + (C1 x, byte y) => new C1();
}
class C2 : C1
{
public static C2 operator + (C2 x, int y) => new C2();
}
5. példa:
class C
{
static void Add(C2 x, byte y)
{
object o;
// C2.op_CheckedAddition
o = checked(x + y);
// C1.op_Addition
o = unchecked(x + y);
}
static void Add2(C2 x, int y)
{
object o;
// C1.op_Addition
o = checked(x + y);
// C1.op_Addition
o = unchecked(x + y);
}
}
class C1
{
public static C1 operator + (C1 x, int y) => new C1();
}
class C2 : C1
{
public static C2 operator checked + (C2 x, byte y) => new C2();
}
Felhasználó által definiált explicit konverziók feldolgozása
A §10.5.5harmadik pontja:
- Keresse meg a felhasználó által definiált és átemelt konverziós operátorok halmazát,
U. Ez a készlet az osztályok vagy struktúrák által aD-ban deklarált, felhasználó által definiált és emelt implicit vagy explicit konverziós operátorokból áll, amelyek olyan típusról alakulnak át egy másik típusra, amelyet azSkörülfog, vagy amely azS-et körülfogja, a által körülfogott vagy a -t körülfogó típusra. HaUüres, a konvertálás nincs meghatározva, és fordítási időhiba lép fel.
helyére a következő felsorolásjelek kerülnek:
- Keresse meg a felhasználó által definiált és kiemelt explicit konverziós operátorok készletét,
U0. Ez a készlet aDosztályok vagy struktúrák által deklarált, felhasználó által meghatározott és felemelt explicit konverziós operátorokból áll, amelyek acheckedkiértékelési kontextusban ellenőrzött és szokásos formájukban jelennek meg, és auncheckedkiértékelési kontextusban csak szokásos formájukban érhetők el, és amelyek egy olyan típusból alakítanak át, amely magában foglalja vagy tartalmazva van aSáltal, egy olyan típusba, amely magában foglalja vagy tartalmazva van aTáltal. - Ha
U0legalább egy operátort tartalmaz ellenőrzött formában, a normál formában lévő összes operátor el lesz távolítva a készletből. - Keresse meg a felhasználó által definiált és átemelt konverziós operátorok halmazát,
U. Ez a készlet aU0operátorai mellett aDosztályai vagy szerkezetei által deklarált, felhasználó által definiált és emelt implicit átalakító operátorokból áll, amelyek egySáltal magában foglalt vagy általa magában foglalt típusból egyTáltal magában foglalt vagy általa magában foglalt típusba alakítanak át. HaUüres, a konvertálás nincs meghatározva, és fordítási időhiba lép fel.
A jelű szakasz 12.8.20 módosítva lesz, hogy tükrözze az ellenőrzött/nem ellenőrzött környezetnek a felhasználó által definiált explicit konverziók feldolgozására gyakorolt hatását.
Bejelölt és be nem jelölt környezet egy checked operator
A fordító a checked operator alapértelmezett környezetét az ellenőrzésnek megfelelően kezelheti. A fejlesztőnek kifejezetten használnia kell a unchecked-t, ha az algoritmus egy részének nem kéne részt vennie a checked context-ben. A jövőben azonban ez nem fog jól működni, ha a checked/unchecked tokeneket módosítókét engedélyezzük operátorokon a környezet megadására a törzsön belül. A módosító és a kulcsszó ellentmondhat egymásnak. Emellett nem tudnánk ugyanezt megtenni: az alapértelmezett környezetet nem ellenőrzöttként kezelni egy regular operator esetén, mert az egy kompatibilitástörő változás lenne.
Megoldatlan kérdések
Engedélyezi-e a nyelv checked és unchecked módosítókat a metódusokon (például static checked void M())?
Ez lehetővé tenné a beágyazási szintek eltávolítását az azt igénylő metódusok esetében.
Ellenőrzött osztás a Linq-kifejezésfákban
Nincs gyári módszer egy ellenőrzött osztáscsomópont létrehozásához, és nincs ExpressionType.DivideChecked tag.
A következő gyári metódussal továbbra is normál osztáscsomópontot hozhatunk létre, ahol MethodInfo a op_CheckedDivision metódusra mutat.
A fogyasztóknak ellenőrizniük kell a nevet, hogy következtethessenek a kontextusra.
public static BinaryExpression Divide (Expression left, Expression right, MethodInfo? method);
Vegye figyelembe, hogy annak ellenére, hogy 12.8.20 szakasz a / operátort az ellenőrzött/nem ellenőrzött kiértékelési környezet által érintett operátorok egyikeként sorolja fel, az IL nem rendelkezik speciális műveleti kóddal az ellenőrzött osztás végrehajtásához.
A fordító mindig a gyári módszert használja a környezettől függetlenül ma.
Javaslat: A felhasználó által megadott osztás nem lesz támogatott a Linq Kifejezésfákban.
(Megoldott) Támogatnunk kell az implicit ellenőrzött konverziós operátorokat?
Az implicit konverziós operátoroknak általában nem szabad dobnia.
Javaslat: Nem.
állásfoglalás: jóváhagyva – https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-07.md#checked-implicit-conversions
Tervezési értekezletek
https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-07.md https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-09.md https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-14.md https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-23.md
C# feature specifications