Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Nota
Artikel ini adalah spesifikasi fitur. Spesifikasi berfungsi sebagai dokumen desain untuk fitur tersebut. Ini termasuk perubahan spesifikasi yang diusulkan, bersama dengan informasi yang diperlukan selama desain dan pengembangan fitur. Artikel ini diterbitkan sampai perubahan spesifikasi yang diusulkan diselesaikan dan dimasukkan dalam spesifikasi ECMA saat ini.
Mungkin ada beberapa perbedaan antara spesifikasi fitur dan implementasi yang selesai. Perbedaan tersebut dijelaskan dalam catatan rapat terkait desain bahasa (LDM) .
Anda dapat mempelajari lebih lanjut tentang proses untuk mengadopsi speklet fitur ke dalam standar bahasa C# dalam artikel tentang spesifikasi .
Masalah juara: https://github.com/dotnet/csharplang/issues/4665
Ringkasan
C# harus mendukung penentuan varian checked dari operator yang didefinisikan pengguna berikut sehingga pengguna dapat mengaktifkan atau menonaktifkan perilaku luapan yang sesuai.
- Operator unary
++dan--§12,8,16 dan §12,9,6. - Operator unary
-§12.9.3. - Operator biner
+,-,*, dan/§12,10. - Operator konversi eksplisit.
Motivasi
Tidak ada cara bagi pengguna untuk mendeklarasikan tipe dan mendukung versi operator yang sudah dicek dan belum dicek. Ini akan menyulitkan penerapan berbagai algoritma untuk menggunakan antarmuka generic math yang diusulkan dan diekspos oleh tim pustaka. Demikian juga, ini membuatnya tidak mungkin untuk mengekspos jenis seperti Int128 atau UInt128 tanpa bahasa secara bersamaan menyertakan dukungannya sendiri untuk menghindari perubahan yang merusak.
Desain terperinci
Sintaksis
Tata bahasa pada operator (§15,10) akan disesuaikan untuk mengizinkan kata kunci checked setelah kata kunci operator tepat sebelum token operator:
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 ')'
;
Misalnya:
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) {...}
Untuk kejelasan di bawah ini, operator dengan kata kunci checked disebut sebagai checked operator dan operator tanpa kata kunci checked disebut sebagai . Ketentuan ini tidak berlaku untuk operator yang tidak memiliki formulir checked.
Semantik
checked operator yang ditentukan pengguna diharapkan melemparkan pengecualian ketika hasil operasi terlalu besar untuk diwakili dalam jenis tujuan. Apa artinya terlalu besar sebenarnya tergantung pada sifat jenis tujuan dan tidak ditentukan oleh bahasa. Biasanya pengecualian yang dilemparkan adalah System.OverflowException, tetapi bahasa tidak memiliki persyaratan khusus mengenai hal ini.
regular operator yang ditentukan pengguna diharapkan tidak melemparkan pengecualian ketika hasil operasi terlalu besar untuk diwakili dalam jenis tujuan. Sebaliknya, diharapkan untuk mengembalikan instance yang mewakili hasil yang terpotong. Apa artinya terlalu besar dan dipotong sebenarnya tergantung pada sifat jenis tujuan dan tidak ditentukan oleh bahasa.
Semua operator yang ditentukan pengguna yang ada di luar sana yang akan memiliki formulir checked yang didukung termasuk dalam kategori regular operators. Dipahami bahwa banyak dari mereka mungkin tidak mengikuti semantik yang ditentukan di atas, tetapi untuk tujuan analisis semantik, kompilator akan mengasumsikan bahwa mereka melakukannya.
Konteks dicentang vs. tidak dicentang dalam checked operator
Konteks yang dicentang/tidak dicentang dalam isi checked operator tidak terpengaruh oleh keberadaan kata kunci checked. Dengan kata lain, konteksnya sama dengan tepat di awal deklarasi operator. Pengembang harus secara eksplisit mengalihkan konteks jika bagian dari algoritma mereka tidak dapat mengandalkan konteks default.
Nama dalam metadata
Bagian "I.10.3.1 Operator unary" dari ECMA-335 akan disesuaikan untuk menyertakan op_CheckedIncrement, op_CheckedDecrement, op_CheckedUnaryNegation sebagai nama metode yang mengimplementasikan operator unary yang diperiksa ++, --, dan -.
Bagian "Operator Biner I.10.3.2" ECMA-335 akan disesuaikan untuk menyertakan op_CheckedAddition, op_CheckedSubtraction, op_CheckedMultiply, op_CheckedDivision sebagai nama untuk metode yang menerapkan operator biner +, -, *, dan / yang diperiksa.
Bagian "Operator konversi I.10.3.3" ECMA-335 akan disesuaikan untuk menyertakan op_CheckedExplicit sebagai nama untuk metode yang menerapkan operator konversi eksplisit yang diperiksa.
Operator Unary
Unary checked operators mengikuti aturan dari §15.10.2.
Selain itu, deklarasi checked operator memerlukan deklarasi berpasangan dari regular operator (tipe pengembalian juga harus sesuai). Jika tidak, akan terjadi kesalahan waktu kompilasi.
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);
}
Operator biner
Biner checked operators mengikuti aturan dari §15.10.3.
Selain itu, deklarasi checked operator memerlukan deklarasi berpasangan dari regular operator (tipe pengembalian juga harus sesuai). Jika tidak, akan terjadi kesalahan waktu kompilasi.
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);
}
Operator kandidat yang ditentukan pengguna
Bagian Operator pengguna Kandidat (§12.4.6) akan disesuaikan sebagai berikut (penambahan/perubahan dalam huruf tebal).
Mengingat jenis T dan operasi operator op(A), di mana op adalah operator yang dapat kelebihan beban dan A adalah daftar argumen, kumpulan operator yang ditentukan pengguna kandidat yang disediakan oleh T untuk operator op(A) ditentukan sebagai berikut:
- Tentukan jenis
T0. JikaTadalah jenis nullable,T0adalah jenis dasarnya, jika bukan,T0sama denganT. - Temukan kumpulan operator yang ditentukan pengguna,
U. Set ini terdiri dari:-
Dalam konteks evaluasi
unchecked, semua deklarasioperator opreguler dalamT0. -
Dalam konteks evaluasi
checked, semua deklarasioperator opdiperiksa dan teratur dalamT0kecuali deklarasi reguler yang memiliki deklarasichecked operatorpencocokan pasangan.
-
Dalam konteks evaluasi
- Untuk semua deklarasi
operator opdalamUdan semua bentuk terangkat dari operator tersebut, jika setidaknya satu operator dapat diterapkan (§12.4.6 - Anggota fungsi yang dapat diterapkan) terhadap daftar argumenA, maka kumpulan operator kandidat mencakup seluruh operator yang dapat diterapkan diT0. - Jika tidak, jika
T0adalahobject, maka himpunan operator kandidat kosong. - Jika tidak, kumpulan operator kandidat yang disediakan oleh
T0adalah kumpulan operator kandidat yang disediakan oleh kelas dasar langsungT0, atau kelas dasar efektifT0jikaT0adalah parameter tipe.
Aturan serupa akan diterapkan saat menentukan set operator kandidat dalam antarmuka https://github.com/dotnet/csharplang/blob/main/meetings/2017/LDM-2017-06-27.md#shadowing-within-interfaces.
Bagian §12.8.20 akan disesuaikan untuk mencerminkan efek yang dimiliki konteks yang dicentang/tidak dicentang pada resolusi kelebihan beban operator unary dan biner.
Contoh #1:
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);
}
Contoh #2:
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
{
}
Contoh #3:
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
{
}
Operator konversi
Konversi checked operators mengikuti aturan dari §15.10.4.
Namun, deklarasi checked operator memerlukan deklarasi secara berpasangan dari regular operator. Jika tidak, akan terjadi kesalahan waktu kompilasi.
Paragraf berikut
Tanda tangan operator konversi terdiri dari jenis sumber dan jenis target. (Ini adalah satu-satunya bentuk anggota yang jenis pengembaliannya menjadi bagian dari tanda tangan.) Klasifikasi implisit atau eksplisit operator konversi bukan bagian dari tanda tangan operator. Dengan demikian, kelas atau struktur tidak dapat mendeklarasikan operator konversi implisit dan eksplisit dengan jenis sumber dan target yang sama.
akan disesuaikan untuk memungkinkan tipe mendeklarasikan bentuk konversi eksplisit yang dicek dan biasa dengan tipe sumber dan target yang sama. Jenis tidak akan diizinkan untuk mendeklarasikan operator konversi implisit dan operator konversi eksplisit yang dicek dengan jenis sumber dan target yang sama.
Pemrosesan konversi eksplisit yang ditentukan pengguna
Poin ketiga dalam §10.5.5:
- Temukan kumpulan operator konversi yang ditentukan pengguna dan diangkat yang berlaku,
U. Set ini terdiri dari operator konversi implisit atau eksplisit yang ditentukan pengguna dan diangkat, yang dideklarasikan oleh kelas atau struktur dalamD, yang mengonversi dari jenis yang mencakup atau dicakup olehSke jenis yang mencakup atau dicakup olehT. JikaUkosong, konversi tidak terdefinisi dan terjadi kesalahan waktu kompilasi.
akan diganti dengan poin-poin utama berikut:
- Temukan set operator konversi,
U0. Set ini terdiri dari:-
Dalam konteks evaluasi
unchecked, operator konversi implisit atau eksplisit reguler yang didefinisikan oleh pengguna yang dideklarasikan oleh kelas atau struktur dalamD. -
Dalam konteks evaluasi
checked, operator konversi eksplisit implisit atau reguler yang ditentukan pengguna yang dideklarasikan oleh kelas atau struktur dalamDkecuali operator konversi eksplisit reguler yang memiliki pencocokan pasanganchecked operatordeklarasi dalam jenis deklarasi yang sama.
-
Dalam konteks evaluasi
- Temukan kumpulan operator konversi yang ditentukan pengguna dan diangkat yang berlaku,
U. Set ini terdiri dari operator konversi implisit atau eksplisit yang ditentukan pengguna dan diangkat dalamU0yang mengonversi dari jenis yang mencakup atau dicakup olehSke jenis yang mencakup atau dicakup olehT. JikaUkosong, konversi tidak terdefinisi dan terjadi kesalahan waktu kompilasi.
Operator checked dan unchecked di bagian §11.8.20 akan disesuaikan untuk mencerminkan efek yang dimiliki konteks checked/unchecked pada pemrosesan konversi eksplisit yang didefinisikan oleh pengguna.
Mengimplementasikan operator
checked operator tidak menerapkan regular operator dan sebaliknya.
Pohon Ekspresi Linq
Checked operators akan didukung dalam Expression Trees Linq. Simpul UnaryExpression/BinaryExpression akan dibuat dengan padanan MethodInfoyang sesuai.
Metode pabrik berikut akan digunakan:
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);
Perhatikan, bahwa C# tidak mendukung penugasan di pohon ekspresi, oleh karena itu kenaikan/penurunan yang diperiksa tidak akan didukung juga.
Tidak ada metode pabrik untuk pembagian yang diperiksa. Ada pertanyaan terbuka mengenai analisis pembagian pada Struktur Ekspresi Linq ini - .
Dinamis
Kami akan menyelidiki biaya penambahan dukungan untuk operator yang diperiksa dalam pemanggilan dinamis di CoreCLR dan mengejar implementasi jika biayanya tidak terlalu tinggi. Ini adalah kutipan dari https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-09.md.
Kekurangan
Ini menambahkan kompleksitas ke bahasa dan memungkinkan pengguna untuk memperkenalkan lebih banyak jenis perubahan signifikan pada tipe data mereka.
Alternatif
Antarmuka matematika generik yang direncanakan pustaka untuk diekspos dapat mengekspos metode bernama (seperti AddChecked). Kelemahan utamanya adalah bahwa ini kurang dapat dibaca/dipertahankan dan tidak mendapatkan manfaat dari aturan prioritas bahasa di sekitar operator.
Bagian ini mencantumkan alternatif yang dibahas, tetapi tidak diimplementasikan
Penempatan kata kunci checked
Atau kata kunci checked dapat dipindahkan ke tempat tepat sebelum kata kunci operator:
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) {...}
Atau dapat dipindahkan ke kumpulan pengubah operator:
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) {...}
kata kunci unchecked
Ada saran untuk mendukung kata kunci unchecked pada posisi yang sama dengan kata kunci checked dengan kemungkinan arti berikut:
- Hanya untuk mencerminkan secara eksplisit sifat keteraturan operator tersebut, atau
- Mungkin untuk menunjuk varian operator yang berbeda yang seharusnya digunakan dalam konteks
unchecked. Bahasa ini dapat mendukungop_Addition,op_CheckedAddition, danop_UncheckedAdditionuntuk membantu membatasi jumlah perubahan yang mengganggu. Ini menambahkan lapisan kompleksitas lain yang kemungkinan tidak diperlukan di sebagian besar kode.
Nama operator di ECMA-335
Atau nama operator dapat op_UnaryNegationChecked, op_AdditionChecked, op_SubtractionChecked, op_MultiplyChecked, op_DivisionChecked, dengan Checked di akhir. Namun, sepertinya sudah ada pola yang terbentuk untuk mengakhiri nama dengan kata operator. Misalnya, terdapat operator op_UnsignedRightShift daripada operator op_RightShiftUnsigned.
Checked operators tidak dapat diaplikasikan dalam konteks unchecked
Kompilator, ketika melakukan pencarian anggota untuk menemukan operator yang didefinisikan pengguna dalam konteks unchecked, dapat mengabaikan checked operators. Jika metadata ditemukan yang hanya menentukan checked operator, maka kesalahan kompilasi akan terjadi.
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);
}
Aturan pencarian operator yang lebih rumit dan resolusi kelebihan beban dalam konteks checked
Pengkompilasi, saat melakukan pencarian anggota untuk menemukan operator spesifik pengguna kandidat dalam konteks checked, juga akan mempertimbangkan operator yang berlaku yang diakhiri dengan Checked. Artinya, jika pengkompilasi mencoba menemukan anggota fungsi yang berlaku untuk operator penambahan biner, ia akan mencari op_Addition dan op_AdditionChecked. Jika satu-satunya anggota fungsi yang sesuai adalah checked operator, maka itu akan digunakan. Jika regular operator dan checked operator ada dan sama-sama berlaku, checked operator akan lebih disukai. Jika regular operator dan checked operator ada tetapi regular operator sama persis sementara checked operator tidak, kompilator akan lebih memilih regular operator.
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);
}
Cara lain lagi untuk membangun kumpulan operator yang mungkin ditentukan pengguna.
Resolusi kelebihan beban operator unary
Dengan asumsi bahwa regular operator sesuai dengan konteks evaluasi unchecked, checked operator cocok dengan konteks evaluasi checked, dan operator yang tidak memiliki bentuk checked (misalnya, +) cocok dengan keduanya, maka butir pertama pada §12.4.4 - Resolusi kelebihan beban operator unary:
- Sekumpulan operator yang didefinisikan pengguna kandidat yang disediakan oleh
Xuntuk operasioperator op(x)ditentukan menggunakan aturan §12.4.6 - Kandidat operator yang didefinisikan pengguna.
akan diganti dengan dua poin berikut ini:
- Kumpulan operator kandidat yang ditentukan pengguna yang disediakan oleh
Xuntuk operasioperator op(x)yang cocok dengan konteks aktif/non-aktif saat ini ditentukan menggunakan aturan kandidat operator yang ditentukan pengguna . - Jika koleksi operator yang ditentukan pengguna tidak kosong, maka ini menjadi kumpulan operator kandidat untuk operasi tersebut. Jika tidak, kumpulan operator kandidat yang ditentukan pengguna yang disediakan oleh
Xuntuk operasioperator op(x)yang mencocokkan konteks yang diperiksa/tidak dicentang yang berlawanan ditentukan dengan menggunakan aturan §12.4.6 - Operator kandidat yang ditentukan pengguna.
Resolusi kelebihan beban operator biner
Dengan asumsi bahwa regular operator cocok dengan konteks evaluasi unchecked, checked operator cocok dengan konteks evaluasi checked, dan operator yang tidak memiliki bentuk checked (misalnya, %) cocok dengan salah satu dari konteks tersebut, butir pertama dalam §12.4.5 - Resolusi kelebihan beban operator biner:
- Kumpulan operator yang ditentukan pengguna kandidat yang disediakan oleh
XdanYuntuk operasioperator op(x,y)ditentukan. Set ini terdiri dari penyatuan operator kandidat yang disediakan olehXdan operator kandidat yang disediakan olehY, masing-masing ditentukan menggunakan aturan §12.4.6 - Operator kandidat yang ditentukan pengguna. JikaXdanYadalah jenis yang sama, atau jikaXdanYberasal dari jenis dasar umum, operator kandidat bersama hanya terjadi dalam kumpulan gabungan sekali.
akan diganti dengan dua poin berikut ini:
- Kumpulan operator kandidat yang didefinisikan pengguna yang disediakan oleh
XdanYuntuk operasioperator op(x,y)yang cocok dengan konteks dicentang/tidak dicentang saat ini ditentukan. Set ini terdiri dari penyatuan operator kandidat yang disediakan olehXdan operator kandidat yang disediakan olehY, masing-masing ditentukan menggunakan aturan §12.4.6 - Operator kandidat yang ditentukan pengguna. JikaXdanYadalah jenis yang sama, atau jikaXdanYberasal dari jenis dasar umum, operator kandidat bersama hanya terjadi dalam kumpulan gabungan sekali. - Jika koleksi operator yang ditentukan pengguna tidak kosong, maka ini menjadi kumpulan operator kandidat untuk operasi tersebut. Jika tidak, kumpulan operator kandidat yang ditentukan pengguna dan disediakan oleh
XdanYuntuk operasioperator op(x,y)yang cocok dengan konteks diperiksa/tidak dicentang yang berlawanan ditentukan. Set ini terdiri dari penyatuan operator kandidat yang disediakan olehXdan operator kandidat yang disediakan olehY, masing-masing ditentukan menggunakan aturan §12.4.6 - Operator kandidat yang ditentukan pengguna. JikaXdanYadalah jenis yang sama, atau jikaXdanYberasal dari jenis dasar umum, operator kandidat bersama hanya terjadi dalam kumpulan gabungan sekali.
Contoh #1:
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);
}
Contoh #2:
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
{
}
Contoh #3:
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
{
}
Contoh #4:
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();
}
Contoh #5:
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();
}
Pemrosesan konversi eksplisit yang ditentukan pengguna
Dengan asumsi bahwa regular operator cocok dengan konteks evaluasi unchecked dan checked operator cocok dengan konteks evaluasi checked, poin ketiga dalam §10.5.3 Evaluasi konversi yang ditentukan pengguna:
- Temukan kumpulan operator konversi yang ditentukan pengguna dan diangkat yang berlaku,
U. Set ini terdiri dari operator konversi implisit atau eksplisit yang ditentukan pengguna dan diangkat, yang dideklarasikan oleh kelas atau struktur dalamD, yang mengonversi dari jenis yang mencakup atau dicakup olehSke jenis yang mencakup atau dicakup olehT. JikaUkosong, konversi tidak terdefinisi dan terjadi kesalahan waktu kompilasi.
akan diganti dengan poin-poin utama berikut:
- Temukan kumpulan operator konversi eksplisit yang ditentukan pengguna dan diangkat yang berlaku cocok dengan konteks yang dicentang/tidak dicentang saat ini,
U0. Set ini terdiri dari operator konversi eksplisit yang ditentukan pengguna dan diangkat yang dideklarasikan oleh kelas atau struktur diDyang cocok dengan konteks yang diperiksa/tidak dicentang saat ini dan dikonversi dari jenis yang mencakup atau dicakup olehSke jenis yang mencakup atau dicakup olehT. - Temukan kumpulan operator konversi eksplisit yang ditentukan pengguna dan diangkat yang berlaku cocok dengan konteks yang diperiksa/tidak dicentang yang berlawanan,
U1. JikaU0tidak kosong,U1kosong. Jika tidak, set ini terdiri dari operator konversi eksplisit yang ditentukan pengguna dan diangkat yang dideklarasikan oleh kelas atau struktur diDyang cocok dengan konteks yang diperiksa/tidak dicentang dan dikonversi dari jenis yang mencakup atau dicakup olehSke jenis yang mencakup atau dicakup olehT. - Temukan kumpulan operator konversi yang ditentukan pengguna dan diangkat yang berlaku,
U. Set ini terdiri dari operator dariU0,U1, serta operator konversi implisit yang didefinisikan oleh pengguna dan dinaikkan yang dideklarasikan oleh kelas atau struktur dalamDyang melakukan konversi dari jenis yang mencakup atau dicakup olehSke jenis yang mencakup atau dicakup olehT. JikaUkosong, konversi tidak terdefinisi dan terjadi kesalahan waktu kompilasi.
Namun, lagi-lagi ada cara lain untuk membangun serangkaian operator yang ditentukan untuk kandidat pengguna.
Resolusi kelebihan beban operator unary
Poin pertama di bagian §12.4.4 akan disesuaikan sebagai berikut (penambahan dalam huruf tebal).
- Kumpulan operator yang ditentukan pengguna kandidat yang disediakan oleh
Xuntuk operasioperator op(x)ditentukan menggunakan aturan bagian "Operator yang ditentukan pengguna kandidat" di bawah ini. Jika set berisi setidaknya satu operator dalam formulir yang dicentang, semua operator dalam bentuk reguler akan dihapus dari set.
Bagian §12.8.20 akan disesuaikan untuk mencerminkan efek yang dimiliki konteks yang diperiksa/tidak dicentang pada resolusi kelebihan beban operator unary.
Resolusi kelebihan beban operator biner
Poin pertama di bagian §12.4.5 akan disesuaikan sebagai berikut (penambahan dalam "huruf tebal").
- Kumpulan operator yang ditentukan pengguna kandidat yang disediakan oleh
XdanYuntuk operasioperator op(x,y)ditentukan. Set ini terdiri dari gabungan operator kandidat yang diberikan olehXdan operator kandidat yang diberikan olehY, masing-masing ditentukan berdasarkan aturan dalam bagian "Kandidat operator yang ditentukan pengguna" di bawah ini. JikaXdanYadalah jenis yang sama, atau jikaXdanYberasal dari jenis dasar umum, operator kandidat bersama hanya terjadi dalam kumpulan gabungan sekali. Jika set berisi setidaknya satu operator dalam formulir yang dicentang, semua operator dalam bentuk reguler akan dihapus dari set.
Operator yang diperiksa dan tidak dicentang §12.8.20 akan disesuaikan untuk mencerminkan efek yang dimiliki konteks yang dicentang/tidak dicentang pada resolusi kelebihan beban operator biner.
Operator kandidat yang ditentukan pengguna
§12.4.6 - Operator yang didefinisikan pengguna sebagai kandidat bagian akan disesuaikan sebagai berikut ini (penambahan dalam huruf tebal).
Mengingat jenis T dan operasi operator op(A), di mana op adalah operator yang dapat kelebihan beban dan A adalah daftar argumen, kumpulan operator yang ditentukan pengguna kandidat yang disediakan oleh T untuk operator op(A) ditentukan sebagai berikut:
- Tentukan jenis
T0. JikaTadalah jenis nullable,T0adalah jenis dasarnya, jika bukan,T0sama denganT. - Untuk semua deklarasi
operator opdalam bentuk yang telah diperiksa dan teratur dalam konteks evaluasicheckeddan hanya dalam bentuk reguler dalam konteks evaluasiuncheckeddalamT0dan semua bentuk pengangkatan dari operator tersebut, jika setidaknya satu operator berlaku (§12.6.4.2) sehubungan dengan daftar argumenA, maka kumpulan operator kandidat yang terdiri dari semua operator yang berlaku dalamT0. - Jika tidak, jika
T0adalahobject, maka himpunan operator kandidat kosong. - Jika tidak, kumpulan operator kandidat yang disediakan oleh
T0adalah kumpulan operator kandidat yang disediakan oleh kelas dasar langsungT0, atau kelas dasar efektifT0jikaT0adalah parameter tipe.
Pemfilteran serupa akan diterapkan saat menentukan set operator kandidat dalam antarmuka https://github.com/dotnet/csharplang/blob/main/meetings/2017/LDM-2017-06-27.md#shadowing-within-interfaces.
Bagian §12.8.20 akan disesuaikan untuk mencerminkan efek yang dimiliki konteks yang diperiksa/tidak dicentang pada resolusi kelebihan beban operator unary dan biner.
Contoh #1:
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);
}
Contoh #2:
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
{
}
Contoh #3:
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
{
}
Contoh #4:
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();
}
Contoh #5:
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();
}
Pemrosesan konversi eksplisit yang ditentukan pengguna
Poin ketiga dalam §10.5.5:
- Temukan kumpulan operator konversi yang ditentukan pengguna dan diangkat yang berlaku,
U. Set ini terdiri dari operator konversi implisit atau eksplisit yang ditentukan pengguna dan diangkat, yang dideklarasikan oleh kelas atau struktur dalamD, yang mengonversi dari jenis yang mencakup atau dicakup olehSke jenis yang mencakup atau dicakup olehT. JikaUkosong, konversi tidak terdefinisi dan terjadi kesalahan waktu kompilasi.
akan diganti dengan poin-poin utama berikut:
- Temukan kumpulan operator konversi eksplisit yang ditentukan pengguna dan diarahkan yang relevan,
U0. Set ini terdiri dari operator konversi eksplisit yang ditentukan pengguna dan diangkat yang dideklarasikan oleh kelas atau struktur dalamDdalam bentuk yang diperiksa dan teratur dalam konteks evaluasicheckeddan hanya dalam bentuk teratur dalam konteks evaluasiunchecked, serta konversi dari tipe yang mencakup atau dicakup olehSke tipe yang mencakup atau dicakup olehT. - Jika
U0berisi setidaknya satu operator dalam formulir yang dicentang, semua operator dalam bentuk reguler akan dihapus dari set. - Temukan kumpulan operator konversi yang ditentukan pengguna dan diangkat yang berlaku,
U. Set ini terdiri dari operator-operator dariU0, dan operator konversi implisit yang ditentukan oleh pengguna dan dinaikkan yang dideklarasikan dalam kelas atau struktur diDyang mengkonversi dari jenis yang mencakup atau dicakup olehSke jenis yang mencakup atau dicakup olehT. JikaUkosong, konversi tidak terdefinisi dan terjadi kesalahan waktu kompilasi.
Operator checked dan unchecked pada bagian §12.8.20 akan disesuaikan untuk mencerminkan efek konteks checked/unchecked pada pemrosesan konversi eksplisit yang didefinisikan oleh pengguna.
Konteks dicentang vs. tidak dicentang dalam checked operator
Pengkompilasi dapat memperlakukan konteks default checked operator seperti yang diperiksa. Pengembang harus secara eksplisit menggunakan unchecked jika bagian dari algoritma mereka tidak boleh berpartisipasi dalam checked context. Namun, ini mungkin tidak berfungsi dengan baik di masa depan jika kita mulai mengizinkan token checked/unchecked sebagai pengubah pada operator untuk mengatur konteks dalam isi. Pengubah dan kata kunci dapat saling bertentangan. Selain itu, kami tidak akan dapat melakukan hal yang sama (memperlakukan konteks default sebagai tidak dicentang) untuk regular operator karena itu akan menjadi perubahan yang mengganggu kompatibilitas.
Pertanyaan yang belum terselesaikan
Haruskah bahasa mengizinkan pengubah checked dan unchecked pada metode (misalnya static checked void M())?
Ini akan memungkinkan penghapusan tingkat penganakan untuk metode yang membutuhkannya.
Memeriksa pembagian dalam Pohon Ekspresi LINQ
Tidak ada metode factory untuk membuat simpul pembagian yang diperiksa dan tidak ada anggota ExpressionType.DivideChecked.
Kita masih dapat menggunakan metode pabrik berikut untuk membuat simpul pembagi reguler dengan MethodInfo menunjuk ke metode op_CheckedDivision.
Konsumen harus memeriksa nama untuk menyimpulkan konteks.
public static BinaryExpression Divide (Expression left, Expression right, MethodInfo? method);
Perhatikan, meskipun bagian §12.8.20 mencantumkan operator / sebagai salah satu operator yang terpengaruh oleh konteks evaluasi yang dicentang/tidak dicentang, IL tidak memiliki kode op khusus untuk melakukan pembagian yang diperiksa.
Kompilator selalu menggunakan metode pabrik tanpa memperdulikan konteks saat ini.
Proposal: Pembagian yang ditentukan pengguna dan diperiksa tidak akan didukung dalam Pohon Ekspresi Linq.
(Diselesaikan) Haruskah kita mendukung operator konversi implisit yang diperiksa?
Secara umum, operator konversi implisit tidak diharapkan untuk melemparkan.
Proposal : Tidak.
Resolusi : Disetujui - https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-07.md#checked-implicit-conversions
Rapat desain
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