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.
8.1 Umum
Jenis bahasa C# dibagi menjadi dua kategori utama: jenis referensi dan jenis nilai. Jenis nilai atau jenis referensi mungkin merupakan jenis generik, yang mengambil satu atau beberapa jenis parameters. Parameter jenis dapat menunjuk jenis nilai dan jenis referensi.
type
: reference_type
| value_type
| type_parameter
| pointer_type // unsafe code support
;
pointer_type (§24.3) hanya tersedia dalam kode tidak aman (§24).
Jenis nilai berbeda dari jenis referensi di mana variabel jenis nilai secara langsung berisi datanya, sedangkan variabel jenis referensi menyimpan referensi ke datanya, yang terakhir dikenal sebagai objek. Dengan jenis referensi, dimungkinkan bagi dua variabel untuk mereferensikan objek yang sama, dan dengan demikian mungkin untuk operasi pada satu variabel untuk memengaruhi objek yang dirujuk oleh variabel lain. Dengan jenis nilai, variabel masing-masing memiliki salinan data mereka sendiri, dan tidak mungkin bagi operasi pada satu untuk memengaruhi yang lain.
Catatan: Ketika variabel adalah parameter referensi atau output, variabel tersebut tidak memiliki penyimpanannya sendiri tetapi mereferensikan penyimpanan variabel lain. Dalam hal ini, variabel ref atau out secara efektif merupakan alias untuk variabel lain dan bukan variabel yang berbeda. catatan akhir
Sistem jenis C#disatukan sehingga nilai dari jenis apa pun dapat diperlakukan sebagai objek. Setiap jenis dalam C# secara langsung atau tidak langsung berasal dari jenis kelas object, dan object merupakan kelas dasar utama dari semua jenis. Nilai jenis referensi diperlakukan sebagai objek hanya dengan melihat nilai sebagai jenis object. Nilai dari jenis nilai diperlakukan sebagai objek dengan melakukan operasi pembungkusan dan pembongkaran (§8.3.13).
Untuk kenyamanan, sepanjang spesifikasi ini, beberapa nama jenis pustaka ditulis tanpa menggunakan kualifikasi nama lengkapnya. Lihat §C.5 untuk informasi selengkapnya.
8.2 Jenis referensi
8.2.1 Umum
Jenis referensi adalah jenis kelas, jenis antarmuka, jenis array, jenis delegasi, dynamic jenis, atau parameter jenis apa pun yang dibatasi menjadi jenis referensi (yaitu, parameter jenis apa pun dengan batasan jenis referensi atau batasan jenis kelas (§15.2.5)). Untuk setiap jenis referensi yang tidak dapat diubah ke null, ada jenis referensi null yang sesuai yang dicatat dengan menambahkan ke ? nama jenis.
reference_type
: non_nullable_reference_type
| nullable_reference_type
;
non_nullable_reference_type
: class_type
| interface_type
| array_type
| delegate_type
| 'dynamic'
;
class_type
: type_name
| 'object'
| 'string'
;
interface_type
: type_name
;
array_type
: non_array_type rank_specifier+
;
non_array_type
: value_type
| class_type
| interface_type
| delegate_type
| 'dynamic'
| type_parameter
| pointer_type // unsafe code support
;
rank_specifier
: '[' ','* ']'
;
delegate_type
: type_name
;
nullable_reference_type
: non_nullable_reference_type nullable_type_annotation
;
nullable_type_annotation
: '?'
;
pointer_type hanya tersedia dalam kode tidak aman (§24.3). nullable_reference_type dibahas lebih lanjut dalam §8.9.
Nilai jenis referensi adalah referensi ke instans jenis , yang terakhir dikenal sebagai objek. Nilai null khusus kompatibel dengan semua jenis referensi dan menunjukkan tidak adanya instans.
8.2.2 Jenis kelas
Jenis kelas menentukan struktur data yang berisi anggota data(konstanta dan bidang), anggota fungsis (metode, properti, peristiwa, pengindeks, operator, konstruktor instans, finalizer, dan konstruktor statis), dan jenis berlapis. Jenis kelas mendukung pewarisan, mekanisme di mana kelas turunan dapat memperluas dan mengkhususkan kelas dasar. Instans jenis kelas dibuat menggunakan object_creation_expression s (§12.8.17.2).
Jenis kelas dijelaskan dalam §15.
Jenis kelas tertentu yang telah ditentukan sebelumnya memiliki arti khusus dalam bahasa C#, seperti yang dijelaskan dalam tabel di bawah ini.
| Jenis kelas | Keterangan |
|---|---|
System.Object |
Kelas dasar utama dari semua tipe lainnya. Lihat §8.2.3. |
System.String |
Jenis string bahasa C#. Lihat §8.2.5. |
System.ValueType |
Kelas dasar dari semua jenis nilai. Lihat §8.3.2. |
System.Enum |
Kelas dasar dari semua enum tipe. Lihat §20,5. |
System.Array |
Kelas dasar dari semua jenis array. Lihat §17.2.2. |
System.Delegate |
Kelas dasar dari semua delegate tipe. Lihat §21.1. |
System.Exception |
Kelas dasar dari semua jenis pengecualian. Lihat §22.3. |
8.2.3 Jenis objek
Jenis object kelas adalah kelas dasar utama dari semua jenis lainnya. Setiap jenis dalam C# secara langsung atau tidak langsung berasal dari object jenis kelas.
Kata kunci object hanyalah alias untuk kelas System.Objectyang telah ditentukan sebelumnya.
8.2.4 Jenis dinamis
Jenisnya dynamic , seperti object, dapat mereferensikan objek apa pun. Ketika operasi diterapkan ke ekspresi jenis dynamic, resolusinya ditangguhkan hingga program dijalankan. Dengan demikian, jika operasi tidak dapat diterapkan secara sah ke objek yang dirujuk, tidak ada kesalahan yang diberikan selama kompilasi. Sebaliknya, pengecualian akan dilepaskan ketika penyelesaian operasi gagal selama waktu eksekusi.
Jenis ini dynamic dijelaskan lebih lanjut dalam §8.7, dan pengikatan dinamis dalam §12.3.1.
8.2.5 Jenis string
Jenisnya string adalah jenis kelas tertutup yang mewarisi langsung dari object. Instans string kelas mewakili string karakter Unicode.
Nilai jenis string dapat ditulis sebagai literal string (§6.4.5.6).
Kata kunci string hanyalah alias untuk kelas System.Stringyang telah ditentukan sebelumnya.
8.2.6 Jenis antarmuka
Antarmuka mendefinisikan kontrak. Kelas atau struktur yang mengimplementasikan antarmuka harus mematuhi kontraknya. Antarmuka dapat mewarisi dari beberapa antarmuka dasar, dan kelas atau struktur dapat mengimplementasikan beberapa antarmuka.
Jenis antarmuka dijelaskan dalam §19.
8.2.7 Jenis array
Array adalah struktur data yang berisi nol atau lebih variabel, yang diakses melalui indeks yang dihitung. Variabel yang terkandung dalam array, juga disebut elemen array, semuanya dari jenis yang sama, dan jenis ini disebut jenis elemen array.
Jenis array dijelaskan dalam §17.
8.2.8 Jenis delegasi
Delegat adalah struktur data yang merujuk pada satu atau beberapa metode. Untuk metode instance, ini juga mengacu pada instance objek yang bersesuaian.
Catatan: Yang paling setara dengan delegasi di C atau C++ adalah penunjuk fungsi, tetapi sedangkan penunjuk fungsi hanya dapat mereferensikan fungsi statis, delegasi dapat mereferensikan metode statis dan instans. Dalam kasus terakhir, delegasi tidak hanya menyimpan referensi ke titik masuk metode, tetapi juga referensi ke instans objek untuk memanggil metode . catatan akhir
Jenis delegasi dijelaskan dalam §21.
8.3 Jenis nilai
8.3.1 Umum
Jenis nilai adalah jenis struct atau jenis enumerasi. C# menyediakan sekumpulan jenis struct yang telah ditentukan sebelumnya yang disebut jenis sederhana. Jenis sederhana diidentifikasi melalui kata kunci.
value_type
: non_nullable_value_type
| nullable_value_type
;
non_nullable_value_type
: struct_type
| enum_type
;
struct_type
: type_name
| simple_type
| tuple_type
;
simple_type
: numeric_type
| 'bool'
;
numeric_type
: integral_type
| floating_point_type
| 'decimal'
;
integral_type
: 'sbyte'
| 'byte'
| 'short'
| 'ushort'
| 'int'
| 'uint'
| 'long'
| 'ulong'
| 'char'
;
floating_point_type
: 'float'
| 'double'
;
tuple_type
: '(' tuple_type_element (',' tuple_type_element)+ ')'
;
tuple_type_element
: type identifier?
;
enum_type
: type_name
;
nullable_value_type
: non_nullable_value_type nullable_type_annotation
;
Tidak seperti variabel jenis referensi, variabel jenis nilai hanya dapat berisi nilai null jika jenis nilai adalah jenis nilai yang dapat diubah ke null (§8.3.12). Untuk setiap jenis nilai yang tidak dapat diubah ke null, ada jenis nilai nullable yang sesuai yang menunjukkan set nilai yang sama ditambah nilai null.
Penugasan suatu nilai ke variabel tipe nilai akan membuat sebuah salinan dari nilai yang ditugaskan. Ini berbeda dari penugasan ke variabel jenis referensi, yang menyalin referensi tetapi bukan objek yang diidentifikasi oleh referensi.
8.3.2 Jenis System.ValueType
Semua jenis nilai secara implisit mewarisi dari classSystem.ValueType, yang pada gilirannya, mewarisi dari kelas object. Jenis apa pun tidak dimungkinkan untuk berasal dari jenis nilai, dan jenis nilai dengan demikian secara implisit disegel (§15.2.2.3).
Perhatikan bahwa System.ValueType itu bukan value_type. Sebaliknya, ini adalah class_type dari mana semua jenis nilai secara otomatis diturunkan.
8.3.3 Konstruktor bawaan
Semua jenis nilai secara implisit mendeklarasikan konstruktor instans tanpa parameter publik yang disebut konstruktor default. Konstruktor bawaan mengembalikan instans yang diinisialisasi ke nol, dikenal sebagai nilai bawaan untuk jenis nilai.
- Untuk semua simple_type, nilai default adalah nilai yang dihasilkan oleh pola bit dari semua nol:
- Untuk
sbyte, ,byteshort,ushort,int,uint,long, danulong, nilai defaultnya adalah0. - Untuk
char, nilai defaultnya adalah'\x0000'. - Untuk
float, nilai defaultnya adalah0.0f. - Untuk
double, nilai defaultnya adalah0.0d. - Untuk
decimal, nilai defaultnya adalah0m(yaitu, nilai nol dengan skala 0). - Untuk
bool, nilai defaultnya adalahfalse. - Untuk enum_type
E, nilai default adalah0, yang dikonversi ke jenisE.
- Untuk
-
Untuk struct_type, nilai default adalah nilai yang dihasilkan dengan mengatur semua bidang jenis nilai ke nilai defaultnya dan semua bidang jenis referensi ke
null. - Nilai default untuk nullable_value_type adalah instance dari tipe tersebut yang
HasValuepropertinya salah. Nilai default juga dikenal sebagai nilai null dari jenis nilai nullable. Mencoba membaca properti dari nilai tersebutValuemenyebabkan pengecualian jenisSystem.InvalidOperationExceptiondilemparkan (§8.3.12).
Seperti konstruktor instans lainnya, konstruktor default dari jenis nilai dipanggil menggunakan new operator.
Catatan: Untuk alasan efisiensi, persyaratan ini tidak dimaksudkan untuk benar-benar memiliki implementasi yang menghasilkan panggilan konstruktor. Untuk jenis nilai, ekspresi nilai default (§12.8.21) menghasilkan hasil yang sama seperti menggunakan konstruktor default. catatan akhir
Contoh: Dalam kode di bawah ini, variabel
i,jdanksemuanya diinisialisasi menjadi nol.class A { void F() { int i = 0; int j = new int(); int k = default(int); } }contoh akhir
Karena setiap jenis nilai secara implisit memiliki konstruktor instans tanpa parameter publik, tidak dimungkinkan bagi jenis struct untuk berisi deklarasi eksplisit konstruktor tanpa parameter. Namun, jenis struct diizinkan untuk mendeklarasikan konstruktor instans berparameter (§16.4.9).
8.3.4 Jenis struktur
Jenis struct adalah jenis nilai yang dapat mendeklarasikan konstanta, bidang, metode, properti, peristiwa, pengindeks, operator, konstruktor instans, konstruktor statis, dan jenis berlapis. Deklarasi jenis struct dijelaskan dalam §16.
8.3.5 Jenis sederhana
C# menyediakan sekumpulan jenis yang telah struct ditentukan sebelumnya yang disebut jenis sederhana. Jenis sederhana diidentifikasi melalui kata kunci, tetapi kata kunci ini hanyalah alias untuk jenis yang telah struct ditentukan sebelumnya di System namespace, seperti yang dijelaskan dalam tabel di bawah ini.
| Kata kunci | Tipe beraliaskan |
|---|---|
sbyte |
System.SByte |
byte |
System.Byte |
short |
System.Int16 |
ushort |
System.UInt16 |
int |
System.Int32 |
uint |
System.UInt32 |
long |
System.Int64 |
ulong |
System.UInt64 |
char |
System.Char |
float |
System.Single |
double |
System.Double |
bool |
System.Boolean |
decimal |
System.Decimal |
Karena jenis sederhana pada dasarnya adalah alias dari jenis struct, setiap jenis sederhana memiliki anggota.
Contoh:
intmemiliki anggota yang dinyatakan diSystem.Int32dan anggota yang diwarisi dariSystem.Object, dan pernyataan berikut diperbolehkan:int i = int.MaxValue; // System.Int32.MaxValue constant string s = i.ToString(); // System.Int32.ToString() instance method string t = 123.ToString(); // System.Int32.ToString() instance methodcontoh akhir
Catatan: Jenis sederhana berbeda dari jenis struct lainnya karena mereka mengizinkan operasi tambahan tertentu:
- Sebagian besar jenis sederhana mengizinkan nilai untuk dibuat dengan menulis literal (§6.4.5), meskipun C# tidak membuat ketentuan untuk literal jenis struktur secara umum. Contoh:
123adalah jenis harfiahintdan'a'merupakan jenischarharfiah . contoh akhir- Ketika operand ekspresi adalah semua konstanta jenis sederhana, dimungkinkan bagi pengkompilasi untuk mengevaluasi ekspresi pada waktu kompilasi. Ekspresi seperti itu dikenal sebagai constant_expression (§12,25). Ekspresi yang melibatkan operator yang ditentukan oleh jenis struct lainnya tidak dianggap sebagai ekspresi konstanta
- Melalui
constdeklarasi, dimungkinkan untuk mendeklarasikan konstanta dari jenis sederhana (§15,4). Tidak dimungkinkan untuk memiliki konstanta jenis struct lainnya, tetapi efek serupa disediakan oleh bidang readonly statis.- Konversi yang melibatkan jenis sederhana dapat berpartisipasi dalam evaluasi operator konversi yang ditentukan oleh jenis struktur lain, tetapi operator konversi yang ditentukan pengguna tidak pernah dapat berpartisipasi dalam evaluasi operator konversi lain yang ditentukan pengguna (§10.5.3).
akhiri catatan.
8.3.6 Jenis integral
C# mendukung sembilan jenis integral: sbyte, , byte, short, ushortint, uint, long, ulong, , dan char. Jenis integral memiliki ukuran dan rentang nilai berikut:
- Tipe
sbytemewakili bilangan bulat 8-bit yang ditandatangani dengan nilai dari-128hingga127, termasuk. - Jenis
bytemewakili bilangan bulat 8-bit yang tidak bertanda dengan nilai dari0hingga255, termasuk. - Jenis
shortmewakili bilangan bulat 16-bit berjenis signed dengan nilai dari-32768hingga32767. - Jenis
ushortmewakili bilangan bulat 16-bit tanpa tanda dengan nilai dari0hingga65535, inklusif. - Jenis
intmewakili bilangan bulat 32-bit bertanda dengan nilai dari-2147483648sampai2147483647inklusif. -
uinttipe mewakili bilangan bulat 32-bit tanpa tanda dengan nilai dari0hingga4294967295, termasuk. - Tipe
longmewakili bilangan bulat 64-bit bertanda dengan nilai dari-9223372036854775808sampai9223372036854775807, inklusif. - Jenis
ulongmewakili bilangan bulat 64-bit yang tidak bertanda dengan nilai dari0hingga18446744073709551615, termasuk. - Jenis
charmewakili bilangan bulat 16-bit tanpa tanda dengan nilai dari0hingga65535, inklusif. Kumpulan nilai yang mungkin untuk tipecharsesuai dengan kumpulan karakter Unicode.Catatan: Meskipun
charmemiliki representasi yang sama denganushort, tidak semua operasi yang diizinkan pada satu jenis diizinkan di jenis lainnya. catatan akhir
Semua tipe bilangan bulat bertanda diwakili menggunakan format komplemen dua.
Operator integral_type unary dan biner selalu beroperasi dengan presisi 32-bit berpenanda, presisi 32-bit tanpa tanda, presisi 64-bit berpenanda, atau presisi 64-bit tanpa tanda, seperti yang dirinci dalam §12.4.7.
Jenis ini char diklasifikasikan sebagai jenis integral, tetapi berbeda dari jenis integral lainnya dengan dua cara:
- Tidak ada konversi implisit yang telah ditentukan sebelumnya dari jenis lain ke jenisnya
char. Secara khusus, meskipunbytedanushortjenis memiliki rentang nilai yang sepenuhnya dapat diwakili menggunakan jenischar, konversi implisit dari sbyte, byte, atauushortkechartidak ada. - Konstanta jenis
charharus ditulis sebagai character_literal atau sebagai integer_literal dalam kombinasi dengan casting ke tipe karakter.
Contoh:
(char)10sama'\x000A'dengan . contoh akhir
Operator dan pernyataan checked dan unchecked digunakan untuk mengontrol pemeriksaan overflow pada operasi aritmatika dan konversi tipe integral (§12.8.20).
checked Dalam konteks, luapan menghasilkan kesalahan waktu kompilasi atau menyebabkan System.OverflowException dilemparkan. Dalam konteks unchecked, limpahan diabaikan dan bit orde tinggi apa pun yang tidak sesuai dengan tipe tujuan dibuang.
8.3.7 Jenis titik mengambang
C# mendukung dua jenis floating-point: float dan double. Jenis float dan double diwakili menggunakan format presisi tunggal 32-bit dan presisi ganda 64-bit IEC 60559, yang menyediakan set nilai berikut:
- Nol positif dan nol negatif. Dalam kebanyakan situasi, nol positif dan nol negatif berperilaku identik sebagai nilai nol sederhana, tetapi operasi tertentu membedakan antara keduanya (§12.12.3).
- Tak terhingga positif dan tak terhingga negatif. Infinities diproduksi oleh operasi seperti membabungkan angka bukan nol dengan nol.
Contoh:
1.0 / 0.0menghasilkan tak terbatas positif, dan–1.0 / 0.0menghasilkan tak terbatas negatif. contoh akhir - Nilai Bukan Angka , sering disingkat NaN. NaN dihasilkan dari operasi floating-point yang tidak valid, seperti membagi nol dengan nol.
- Kumpulan nilai bukan nol terbatas dari bentuk s × m × 2ᵉ, di mana s adalah 1 atau −1, dan m dan e ditentukan oleh jenis titik mengambang tertentu: Untuk
float, 0 <m< 2²⁴ dan −149 ≤ e ≤ 104, dan untukdouble, 0 <m< 2⁵³ dan −1075 ≤ e ≤ 970. Angka floating-point yang didenormalisasi dianggap sebagai nilai bukan nol yang valid. C# tidak memerlukan atau melarang bahwa implementasi yang sesuai mendukung angka floating-point denormalisasi.
Jenis float dapat mewakili nilai mulai dari sekitar 1.5 × 10⁻⁴⁵ hingga 3.4 × 10³⁸ dengan presisi 7 digit.
Jenis ini double dapat mewakili nilai mulai dari sekitar 5,0 × 10⁻³²⁴ hingga 1,7 × 10³⁰⁸ dengan presisi 15-16 digit.
Jika salah satu operand operator biner adalah jenis floating-point, maka promosi numerik standar diterapkan, sebagaimana dirinci dalam §12.4.7, dan operasi dilakukan dengan float atau double presisi.
Operator floating-point, termasuk operator penugasan, tidak pernah menghasilkan pengecualian. Sebaliknya, dalam situasi luar biasa, operasi floating-point menghasilkan nol, tak terbatas, atau NaN, seperti yang dijelaskan di bawah ini:
- Hasil operasi floating-point dibulatkan ke nilai terdekat yang dapat diwakili dalam format tujuan.
- Jika besarnya hasil operasi floating-point terlalu kecil untuk format tujuan, hasil operasi menjadi nol positif atau nol negatif.
- Jika besarnya hasil operasi floating-point terlalu besar untuk format tujuan, hasil operasi menjadi tak terbatas positif atau negatif.
- Jika operasi floating-point tidak valid, hasil operasi menjadi NaN.
- Jika satu atau kedua operan dari operasi floating-point adalah NaN, hasil operasi menjadi NaN.
Operasi floating-point mungkin dilakukan dengan presisi lebih tinggi daripada tipe hasil dari operasi tersebut. Untuk memaksa nilai jenis floating-point ke presisi yang tepat dari jenisnya, cast eksplisit (§12.9.8) dapat digunakan.
Contoh: Beberapa arsitektur perangkat keras mendukung jenis floating-point "extended" atau "long double" dengan rentang dan presisi yang lebih besar daripada jenisnya
double, dan secara implisit melakukan semua operasi floating-point menggunakan jenis presisi yang lebih tinggi ini. Hanya dengan biaya yang berlebihan dalam performa, arsitektur perangkat keras tersebut dapat dibuat untuk melakukan operasi floating-point dengan presisi yang lebih sedikit , dan daripada memerlukan implementasi untuk kehilangan performa dan presisi, C# memungkinkan jenis presisi yang lebih tinggi untuk digunakan untuk semua operasi floating-point. Selain memberikan hasil yang lebih tepat, ini jarang memiliki efek terukur. Namun, dalam ekspresi formulirx * y / z, di mana perkalian menghasilkan hasil yang berada di luardoublerentang, tetapi pembagian berikutnya membawa hasil sementara kembali ke dalamdoublerentang, fakta bahwa ekspresi dievaluasi dalam format rentang yang lebih tinggi dapat menyebabkan hasil terbatas diproduksi alih-alih tak terbatas. contoh akhir
8.3.8 Jenis Desimal
Jenisnya decimal adalah jenis data 128-bit yang cocok untuk perhitungan keuangan dan moneter.
decimal jenis dapat mewakili nilai termasuk rentang dari setidaknya -7,9 × 10⁻²⁸ hingga 7,9 × 10²⁸, dengan setidaknya presisi 28 digit.
Sekumpulan nilai terbatas dari jenis decimal adalah bentuk (–1)v × c × 10⁻e, di mana tanda v adalah 0 atau 1, koefisien < diberikan oleh 0 ≤ c ≤ Cmax, dan skala e sedemikian sehingga Emin ≤ e ≤ Emax, di mana Cmax adalah setidaknya 1 × 10²⁸, Emin ≤ 0, dan Emax ≥ 28. Jenis decimal tidak harus mendukung nol bertanda, ketakterbatasan, atau NaN.
decimal direpresentasikan sebagai bilangan bulat yang diskalakan oleh kekuatan sepuluh. Untuk decimal yang memiliki nilai absolut kurang dari 1.0m, nilainya tepat hingga setidaknya tempat desimal ke-28. Untuk decimal dengan nilai absolut yang lebih besar dari atau sama dengan 1.0m, nilainya memiliki ketepatan setidaknya 28 digit. Bertentangan dengan float jenis data dan double , angka pecahan desimal seperti 0.1 dapat diwakili persis dalam representasi desimal. Dalam representasi float dan double, angka tersebut sering memiliki ekspansi biner yang tidak berakhir, membuat representasi tersebut lebih rentan terhadap kesalahan pembulatan.
Jika salah satu operan operator biner berjenis decimal maka promosi numerik standar diterapkan, sebagaimana dirinci dalam §12.4.7, dan operasi dilakukan dengan double presisi.
Hasil dari operasi pada nilai jenis decimal adalah yang dihasilkan dari menghitung hasil yang tepat (mempertahankan skala, seperti yang didefinisikan untuk setiap operator) dan kemudian dibulatkan agar sesuai dengan bentuk representasi. Hasil dibulatkan ke nilai terdekat yang dapat direpresentasikan, dan ketika hasilnya sama dekat dengan dua nilai yang dapat direpresentasikan, dibulatkan ke nilai yang digit paling tak berarti-nya adalah angka genap (ini dikenal sebagai "pembulatan bankir"). Artinya, hasilnya tepat sampai setidaknya angka desimal ke-28. Perhatikan bahwa pembulatan dapat menghasilkan nilai nol dari nilai yang bukan nol.
Jika operasi aritmatika decimal menghasilkan hasil yang besarnya terlalu besar untuk format decimal, System.OverflowException akan dilemparkan.
Tipe decimal ini memiliki presisi yang lebih besar tetapi mungkin memiliki rentang yang lebih kecil daripada jenis floating-point. Dengan demikian, konversi dari jenis floating-point ke decimal dapat menghasilkan pengecualian luapan, dan konversi dari decimal ke jenis floating-point dapat menyebabkan hilangnya presisi atau pengecualian luapan. Untuk alasan ini, tidak ada konversi implisit antara tipe floating-point dan decimal, dan tanpa cast eksplisit, kesalahan waktu kompilasi terjadi ketika floating-point dan decimal operan dicampurkan langsung ke dalam ekspresi yang sama.
8.3.9 Jenis Bool
Jenis bool mewakili nilai logis Boolean. Nilai jenis bool yang mungkin adalah true dan false. Representasi false dijelaskan dalam §8.3.3. Meskipun representasi true tidak ditentukan, itu akan berbeda dari false.
Tidak ada konversi standar antara bool dan jenis nilai lainnya. Secara khusus, bool jenisnya berbeda dan terpisah dari jenis integral, bool nilai tidak dapat digunakan sebagai ganti nilai integral, dan sebaliknya.
Catatan: Dalam bahasa C dan C++, nilai nol integral atau floating-point, atau pointer null dapat dikonversi ke nilai
falseBoolean , dan nilai integral atau floating-point bukan nol, atau pointer non-null dapat dikonversi ke nilaitrueBoolean . Dalam C#, konversi tersebut dicapai dengan secara eksplisit membandingkan nilai integral atau floating-point dengan nol, atau dengan secara eksplisit membandingkan referensi objek dengannull. catatan akhir
8.3.10 Jenis enumerasi
Jenis enumerasi adalah tipe yang berbeda dengan konstanta yang diberi nama. Setiap jenis enumerasi memiliki jenis yang mendasar, yang akan menjadi byte, , sbyte, short, ushortint, uint, long atau ulong. Sekumpulan nilai jenis enumerasi sama dengan kumpulan nilai dari jenis yang mendasar. Nilai jenis enumerasi tidak dibatasi hanya pada nilai konstanta yang dinamai. Jenis enumerasi didefinisikan melalui deklarasi enumerasi (§20,2).
8.3.11 Jenis tuple
Jenis tuple mewakili urutan nilai yang berurutan dengan panjang tetap, serta memiliki nama opsional dan tipe yang berbeda-beda. Jumlah elemen dalam jenis tuple disebut aritas-nya. Jenis tuple ditulis (T1 I1, ..., Tn In) dengan n ≥ 2, di mana pengidentifikasi I1...In adalah nama elemen tupleopsional s.
Sintaks ini adalah singkatan untuk tipe yang dibangun dengan tipe T1...Tn dari System.ValueTuple<...>, yang akan menjadi kumpulan struct generik yang mampu secara langsung mengekspresikan jenis tuple dengan aritas berapa pun antara dua hingga tujuh termasuk.
Tidak perlu adanya System.ValueTuple<...> deklarasi yang secara langsung sesuai dengan aritas setiap tipe tuple dengan jumlah parameter tipe yang bersesuaian. Sebaliknya, tuple dengan aritas yang lebih besar dari tujuh diwakili oleh tipe struct generik System.ValueTuple<T1, ..., T7, TRest> yang selain elemen tuple memiliki bidang Rest yang berisi nilai berlapis dari elemen yang tersisa, menggunakan tipe lain System.ValueTuple<...>. Bersarang seperti itu dapat diamati dengan berbagai cara, misalnya melalui keberadaan bidang Rest . Jika hanya satu bidang tambahan yang diperlukan, jenis System.ValueTuple<T1> struct generik digunakan; jenis ini tidak dianggap sebagai jenis tuple itu sendiri. Jika diperlukan lebih dari tujuh bidang tambahan, System.ValueTuple<T1, ..., T7, TRest> digunakan secara rekursif.
Nama elemen dalam jenis tuple harus berbeda. Nama elemen tuple dari bentuk ItemX, di mana X adalah urutan digit desimal yang tidak dimulai dengan 0 dan dapat mewakili posisi elemen tuple, hanya diperbolehkan di posisi yang ditentukan oleh X.
Nama elemen opsional tidak diwakili dalam tipe ValueTuple<...>, dan tidak disimpan dalam representasi runtime nilai tuple. Konversi identitas (§10.2.2) ada di antara tuple dengan urutan jenis elemen yang dapat dikonversi identitas.
Operator new§12.8.17.2 tidak dapat diterapkan dengan sintaks new (T1, ..., Tn)jenis tuple . Nilai tuple dapat dibuat dari ekspresi tuple (§12.8.6), atau dengan menerapkan new operator secara langsung pada tipe yang dibangun dari ValueTuple<...>.
Elemen Tuple adalah bidang publik dengan nama Item1, Item2 dll., dan dapat diakses melalui akses anggota pada nilai tuple (§12.8.7). Selain itu, jika jenis tuple memiliki nama untuk elemen tertentu, nama tersebut dapat digunakan untuk mengakses elemen yang dimaksud.
Catatan: Bahkan ketika tuple besar diwakili dengan nilai bersarang
System.ValueTuple<...>, setiap elemen tuple masih dapat diakses langsung dengan namaItem...yang sesuai dengan posisinya. catatan akhir
Contoh: Diberikan contoh-contoh berikut:
(int, string) pair1 = (1, "One"); (int, string word) pair2 = (2, "Two"); (int number, string word) pair3 = (3, "Three"); (int Item1, string Item2) pair4 = (4, "Four"); // Error: "Item" names do not match their position (int Item2, string Item123) pair5 = (5, "Five"); (int, string) pair6 = new ValueTuple<int, string>(6, "Six"); ValueTuple<int, string> pair7 = (7, "Seven"); Console.WriteLine($"{pair2.Item1}, {pair2.Item2}, {pair2.word}");Jenis tuple untuk
pair1,pair2, danpair3semuanya valid, dengan nama untuk tidak, beberapa atau semua elemen jenis tuple.Jenis tuple untuk
pair4valid karena namaItem1danItem2cocok dengan posisinya, sedangkan jenis tuple untukpair5tidak diizinkan, karena namaItem2danItem123tidak.Deklarasi untuk
pair6danpair7menunjukkan bahwa tipe tuple dapat dipertukarkan dengan tipe yang dibangun dalam bentukValueTuple<...>, dan bahwa operatornewdiizinkan dengan sintaks yang terakhir.Baris terakhir menunjukkan bahwa elemen tuple dapat diakses dengan nama
Itemyang sesuai dengan posisinya, serta dengan nama elemen tuple yang bersangkutan, jika ada dalam tipenya. contoh akhir
8.3.12 Jenis nilai yang dapat bernilai null
Tipe nilai nullable dapat mewakili semua nilai dari tipe dasarnya ditambah nilai null tambahan. Jenis nilai nullable ditulis T?, di mana T adalah jenis yang dasar. Sintaks ini singkatan untuk System.Nullable<T>, dan dua bentuk dapat digunakan secara bergantian.
Sebaliknya, jenis nilai yang tidak dapat diubah ke null adalah jenis nilai apa pun selain System.Nullable<T> dan singkatannya T? (untuk apa pun T), ditambah parameter jenis apa pun yang dibatasi menjadi jenis nilai yang tidak dapat diubah ke null (yaitu, parameter jenis apa pun dengan batasan jenis nilai (§15.2.5)). Jenis System.Nullable<T> menentukan batasan jenis nilai untuk T, yang berarti bahwa jenis dasar dari jenis nilai null dapat berupa jenis nilai yang non-nullable. Jenis dasar dari tipe nilai nullable tidak boleh berupa tipe nilai nullable atau tipe referensi. Misalnya, int?? adalah jenis yang tidak valid. Jenis referensi nullable tercakup dalam §8.9.
Sebuah instance dari tipe nilai yang dapat bernilai null memiliki dua properti publik yang hanya dapat dibaca:
- Properti
HasValuedari jenisbool - Properti
Valuedari jenisT
Instans yang HasValuetrue dikatakan non-null. Instans non-null berisi nilai yang diketahui dan Value mengembalikan nilai tersebut.
Instans yang HasValuefalse dikatakan null. Instans null memiliki nilai yang tidak ditentukan. Mencoba membaca Value instans null menyebabkan dilemparkan System.InvalidOperationException . Proses mengakses properti Value dari instance yang dapat bernilai null disebut sebagai unwrapping.
Selain konstruktor default, setiap tipe nilai nullable T? memiliki konstruktor publik dengan satu parameter bertipe T. Dengan nilai x bertipe T, pemanggilan konstruktor dalam bentuk
new T?(x)
membuat instans T? non-null yang Value propertinya adalah x. Proses pembuatan instans non-null dari jenis nilai nullable untuk nilai tertentu disebut sebagai pembungkus.
Konversi implisit tersedia dari null literal ke T? (§10.2.7) dan dari T ke T? (§10.2.6).
Jenis T? nilai nullable tidak mengimplementasikan antarmuka (§19). Secara khusus, ini berarti tidak mengimplementasikan antarmuka apa pun yang diterapkan oleh tipe dasar T.
8.3.13 Tinju dan pembukaan kotak
Konsep pembungkusan dan pembongkaran menyediakan jembatan antara value_type dan reference_type dengan mengizinkan nilai apa pun dari value_type untuk dikonversi ke dan dari jenis object. Boxing dan unboxing memungkinkan tampilan terpadu dari sistem tipe di mana nilai dari tipe apa pun pada akhirnya dapat diperlakukan sebagai object.
Tinju dijelaskan secara lebih rinci dalam §10.2.9 dan pembukaan kotak dijelaskan dalam §10.3.7.
8.4 Jenis konstruksi
8.4.1 Umum
Deklarasi jenis generik, dengan sendirinya, menunjukkan jenis generik yang tidak terikat yang digunakan sebagai "cetak biru" untuk membentuk berbagai jenis, dengan cara menerapkan argumen jenis. Argumen jenis ditulis dalam tanda kurung sudut (< dan >) segera mengikuti nama jenis generik. Jenis yang menyertakan setidaknya satu argumen jenis disebut jenis yang dibangun. Tipe yang dibangun dapat digunakan di sebagian besar tempat dalam bahasa di mana nama tipe dapat muncul. Jenis generik yang tidak terikat hanya dapat digunakan dalam typeof_expression (§12.8.18).
Jenis yang dibuat juga dapat digunakan dalam ekspresi sebagai nama sederhana (§12.8.4) atau saat mengakses anggota (§12.8.7).
Saat namespace_or_type_name dievaluasi, hanya jenis generik dengan jumlah parameter jenis yang benar yang dipertimbangkan. Dengan demikian, dimungkinkan untuk menggunakan pengidentifikasi yang sama untuk mengidentifikasi berbagai jenis, selama jenis memiliki jumlah parameter jenis yang berbeda. Ini berguna saat mencampur kelas generik dan non-generik dalam program yang sama.
Contoh:
namespace Widgets { class Queue {...} class Queue<TElement> {...} } namespace MyApplication { using Widgets; class X { Queue q1; // Non-generic Widgets.Queue Queue<int> q2; // Generic Widgets.Queue } }contoh akhir
Aturan terperinci untuk pencarian nama dalam produksi namespace_or_type_name dijelaskan dalam §7,8. Resolusi ambiguitas dalam produksi ini dijelaskan dalam §6.2.5.
type_name mungkin mengidentifikasi jenis yang dibangun meskipun tidak menentukan parameter jenis secara langsung. Ini dapat terjadi di mana tipe yang bersarang dalam deklarasi generik class, dan tipe instansi deklarasi yang berisi secara implisit digunakan untuk pencarian nama (§15.3.9.7).
Contoh:
class Outer<T> { public class Inner {...} public Inner i; // Type of i is Outer<T>.Inner }contoh akhir
Jenis non-enum yang dibangun tidak boleh digunakan sebagai unmanaged_type (§8.8).
8.4.2 Tipe argumen
Setiap argumen dalam daftar argumen jenis hanyalah jenis.
type_argument_list
: '<' type_argument (',' type_argument)* '>'
;
type_argument
: type
| type_parameter nullable_type_annotation?
;
Setiap argumen jenis harus memenuhi batasan apa pun pada parameter jenis yang sesuai (§15.2.5). Argumen jenis referensi yang nullability-nya tidak cocok dengan nullability parameter type memenuhi batasan; namun peringatan dapat dikeluarkan.
8.4.3 Jenis terbuka dan tertutup
Jenis apa pun dapat diklasifikasikan sebagai jenis terbuka atau jenis tertutup. Jenis terbuka adalah jenis yang melibatkan parameter jenis. Lebih spesifik:
- Parameter tipe mendefinisikan tipe yang terbuka.
- Jenis array adalah jenis terbuka jika dan hanya jika jenis elemennya adalah jenis terbuka.
- Jenis yang dibangun adalah jenis terbuka jika dan hanya jika satu atau beberapa argumen jenisnya adalah jenis terbuka. Jenis bersarang yang terbangun merupakan jenis terbuka jika dan hanya jika salah satu atau lebih argumen jenisnya atau argumen jenis dari satu atau lebih jenis yang mengandungnya merupakan jenis terbuka.
Jenis tertutup adalah tipe yang bukan tipe terbuka.
Pada run-time, semua kode dalam deklarasi tipe generik dijalankan dalam konteks tipe konstruksi tertutup yang dibuat dengan menerapkan argumen tipe ke deklarasi generik. Setiap parameter tipe dalam tipe generik terikat ke tipe waktu-nyata tertentu. Pemrosesan run-time dari semua pernyataan dan ekspresi selalu terjadi dengan tipe tertutup, dan tipe terbuka hanya terjadi selama pemrosesan waktu kompilasi.
Dua tipe terkontruksi tertutup dapat dikonversi secara identitas (§10.2.2) jika dibangun dari tipe generik tak terikat yang sama, dan konversi identitas ada di antara setiap argumen tipe yang bersesuaian. Argumen jenis yang sesuai dapat berupa jenis konstruk atau tuple yang dibuat terbatas yang dapat dikonversikan identitasnya. Jenis konstruksi tertutup yang dapat dikonversi identitas berbagi satu set variabel statis. Jika tidak, setiap jenis yang dibangun tertutup memiliki sekumpulan variabel statisnya sendiri. Karena jenis terbuka tidak ada pada run-time, tidak ada variabel statis yang terkait dengan jenis terbuka.
8.4.4 Jenis terikat dan tidak terikat
Istilah jenis tidak terikat mengacu pada jenis non-generik atau jenis generik yang tidak terikat. Istilah jenis terikat mengacu pada jenis non-generik atau jenis yang dibangun.
Jenis yang tidak terikat mengacu pada entitas yang dideklarasikan oleh deklarasi jenis. Jenis generik yang tidak terikat bukan tipe, dan tidak dapat digunakan sebagai jenis variabel, argumen, atau nilai pengembalian, atau sebagai jenis dasar. Satu-satunya konstruksi di mana jenis generik yang tidak terikat dapat direferensikan adalah typeof ekspresi (§12.8.18).
8.4.5 Memenuhi batasan
Setiap kali jenis yang dibangun atau metode generik direferensikan, argumen jenis yang disediakan diperiksa terhadap batasan parameter jenis yang dideklarasikan pada jenis atau metode generik (§15.2.5). Untuk setiap where klausa, argumen A jenis yang sesuai dengan parameter jenis bernama diperiksa terhadap setiap batasan sebagai berikut:
- Jika batasan adalah
classjenis, jenis antarmuka, atau parameter jenis, biarkanCmewakili batasan tersebut dengan argumen jenis yang disediakan diganti untuk parameter jenis apa pun yang muncul dalam batasan. Untuk memenuhi pengekangan, harus ada kasus di mana jenisAdapat dikonversi menjadi tipeCmelalui salah satu metode berikut: - Jika batasan adalah batasan jenis referensi (
class), jenisAharus memenuhi salah satu hal berikut:-
Aadalah jenis antarmuka, jenis kelas, jenis delegasi, jenis array, atau jenis dinamis.
Catatan:
System.ValueTypedanSystem.Enummerupakan jenis referensi yang memenuhi batasan ini. catatan akhir-
Aadalah parameter jenis yang dikenal sebagai jenis referensi (§8.2).
-
- Jika batasan adalah batasan jenis nilai (
struct), jenisAharus memenuhi salah satu hal berikut:-
Aadalah tipestructatau tipeenum, tetapi bukan tipe nilai yang dapat bernilai null.
Catatan:
System.ValueTypedanSystem.Enummerupakan jenis referensi yang tidak memenuhi batasan ini. catatan akhir-
Aadalah parameter jenis yang memiliki batasan jenis nilai (§15.2.5).
-
- Jika batasan adalah batasan konstruktor
new(), jenisnyaAtidak bolehabstractdan harus memiliki konstruktor tanpa parameter publik. Ini terpenuhi jika salah satu hal berikut ini benar:-
Aadalah jenis nilai, karena semua jenis nilai memiliki konstruktor default publik (§8.3.3). -
Aadalah parameter jenis yang memiliki batasan konstruktor (§15.2.5). -
Aadalah parameter jenis yang memiliki batasan jenis nilai (§15.2.5). -
Aadalahclassyang tidak abstrak dan berisi konstruktor publik yang dideklarasikan secara eksplisit tanpa parameter. -
Atidakabstractdan memiliki konstruktor default (§15.11.5).
-
Kesalahan waktu kompilasi terjadi jika satu atau beberapa batasan parameter jenis tidak terpenuhi oleh argumen jenis yang diberikan.
Karena parameter jenis tidak diwariskan, batasan juga tidak pernah diwariskan.
Contoh: Dalam hal berikut,
Dperlu menentukan batasan pada parameterTjenisnya sehinggaTmemenuhi batasan yang diberlakukan oleh dasarclassB<T>. Sebaliknya,classEtidak perlu menentukan batasan, karenaList<T>mengimplementasikanIEnumerableuntuk setiapT.class B<T> where T: IEnumerable {...} class D<T> : B<T> where T: IEnumerable {...} class E<T> : B<List<T>> {...}contoh akhir
8.5 Jenis parameter
Parameter jenis adalah pengidentifikasi yang menunjuk jenis nilai atau jenis referensi yang terikat parameter pada run-time.
type_parameter
: identifier
;
Karena parameter jenis dapat dibuat dengan banyak argumen jenis yang berbeda, parameter jenis memiliki operasi dan pembatasan yang sedikit berbeda dari jenis lainnya.
Catatan: Ini termasuk:
- Parameter jenis tidak dapat digunakan langsung untuk mendeklarasikan kelas dasar (§15.2.4.2) atau antarmuka (§19.2.4).
- Aturan untuk pencarian anggota pada parameter jenis bergantung pada batasan, jika ada, diterapkan ke parameter jenis. Mereka dirinci dalam §12.5.
- Konversi yang tersedia untuk parameter jenis bergantung pada batasan, jika ada, diterapkan ke parameter jenis. Mereka dirinci dalam §10.2.12 dan §10.3.8.
- Literal
nulltidak dapat dikonversi ke jenis yang diberikan oleh parameter jenis, kecuali jika parameter jenis diketahui sebagai jenis referensi (§10.2.12). Namun, ekspresi default (§12.8.21) dapat digunakan sebagai gantinya. Selain itu, nilai dengan jenis yang diberikan oleh parameter jenis dapat dibandingkan dengan null menggunakan==dan!=(§12.14.7) kecuali parameter jenis memiliki batasan jenis nilai.- Ekspresi (
new) hanya dapat digunakan dengan parameter jenis jika parameter jenis dibatasi oleh constructor_constraint atau batasan jenis nilai (§15.2.5).- Parameter jenis tidak dapat digunakan di mana saja dalam atribut.
- Parameter jenis tidak dapat digunakan dalam akses anggota (§12.8.7) atau nama jenis (§7,8) untuk mengidentifikasi anggota statis atau jenis berlapis.
- Parameter jenis tidak dapat digunakan sebagai unmanaged_type (§8,8).
catatan akhir
Sebagai jenis, parameter jenis murni konstruksi waktu kompilasi. Selama waktu eksekusi, setiap parameter jenis diikat ke jenis yang berlaku selama waktu eksekusi, yang telah ditentukan dengan memberikan argumen jenis pada deklarasi tipe generik. Dengan demikian, jenis variabel yang dideklarasikan dengan parameter jenis akan, pada run-time, menjadi jenis konstruksi tertutup §8.4.3. Eksekusi waktu jalan semua pernyataan dan ekspresi yang melibatkan parameter tipe menggunakan tipe yang disediakan sebagai argumen tipe untuk parameter tersebut.
8.6 Jenis pohon ekspresi
Pohon ekspresi memungkinkan ekspresi lambda direpresentasikan sebagai struktur data alih-alih kode yang dapat dieksekusi. Pohon ekspresi adalah nilai jenis pohon ekspresi dari formulir System.Linq.Expressions.Expression<TDelegate>, di mana TDelegate adalah jenis delegasi apa pun. Untuk sisa spesifikasi ini, jenis ini akan dirujuk menggunakan singkatan Expression<TDelegate>.
Jika ada konversi dari ekspresi lambda ke jenis delegasi D, maka juga ada konversi ke jenis pohon ekspresi Expression<TDelegate>. Sedangkan konversi ekspresi lambda ke jenis delegasi menghasilkan delegasi yang mereferensikan kode yang dapat dieksekusi untuk ekspresi lambda, konversi ke jenis pohon ekspresi membuat representasi pohon ekspresi dari ekspresi lambda. Detail lebih lanjut dari konversi ini disediakan dalam §10.7.3.
Contoh: Program berikut mewakili ekspresi lambda baik sebagai kode yang dapat dieksekusi maupun sebagai pohon ekspresi. Karena konversi ada ke
Func<int,int>, konversi juga ada keExpression<Func<int,int>>:Func<int,int> del = x => x + 1; // Code Expression<Func<int,int>> exp = x => x + 1; // DataSetelah penugasan ini, delegasi
delmerujuk metode yang mengembalikanx + 1, dan pohon ekspresi exp merujuk struktur data yang menjelaskan ekspresix => x + 1.contoh akhir
Expression<TDelegate> menyediakan metode Compile instans yang menghasilkan delegasi jenis TDelegate:
Func<int,int> del2 = exp.Compile();
Memanggil delegasi ini menyebabkan kode yang diwakili oleh pohon ekspresi dijalankan. Dengan demikian, mengingat definisi di atas, del dan del2 setara, dan dua pernyataan berikut akan memiliki efek yang sama:
int i1 = del(1);
int i2 = del2(1);
Setelah menjalankan kode ini, i1 dan i2 keduanya akan memiliki nilai 2.
Permukaan API yang disediakan oleh Expression<TDelegate> ditentukan implementasi di luar persyaratan untuk metode yang Compile dijelaskan di atas.
Catatan: Meskipun detail API yang disediakan untuk pohon ekspresi ditentukan implementasi, diharapkan implementasi akan:
- Mengaktifkan kode untuk memeriksa dan merespons struktur pohon ekspresi yang dibuat sebagai hasil konversi dari ekspresi lambda
- Mengaktifkan pohon ekspresi untuk dibuat secara terprogram dalam kode pengguna
catatan akhir
8.7 Jenis dinamis
Jenis dynamic ini menggunakan pengikatan dinamis, seperti yang dijelaskan secara rinci dalam §12.3.2, dibandingkan dengan pengikatan statis yang digunakan oleh semua jenis lainnya.
Jenis dynamic ini dianggap identik dengan object kecuali dalam hal-hal berikut:
- Operasi pada ekspresi jenis
dynamicdapat terikat secara dinamis (§12.3.3). - Inferensi jenis (§12.6.3) akan lebih memilih
dynamicdaripadaobjectjika keduanya adalah kandidat. -
dynamictidak dapat digunakan sebagai- jenis dalam object_creation_expression (§12.8.17.2)
- class_base (§15.2.4)
- predefined_type dalam member_access (§12.8.7.1)
- operan dari operator
typeof - argumen atribut
- batasan
- jenis metode ekstensi
- setiap bagian dari argumen tipe dalam struct_interfaces (§16.2.5) atau interface_type_list (§15.2.4.1).
Karena kesetaraan ini, berikut ini berlaku:
- Ada konversi identitas implisit
- antara
objectdandynamic - antara tipe yang dibangun yang identik ketika mengganti
dynamicdenganobject - antara jenis tuple yang sama saat mengganti
dynamicdenganobject
- antara
- Konversi implisit dan eksplisit ke dan dari
objectjuga berlaku ke dan daridynamic. - Tanda tangan yang sama saat mengganti
dynamicdenganobjectdianggap sebagai tanda tangan yang sama. - Jenis
dynamicini tidak dapat dibedakan dari jenisobjectpada run-time. - Ekspresi jenis
dynamicdisebut sebagai ekspresi dinamis.
8.8 Jenis tidak terkelola
unmanaged_type
: value_type
| pointer_type // unsafe code support
;
unmanaged_type adalah jenis apa pun yang bukan reference_type atau type_parameter yang tidak dibatasi untuk tidak dikelola, dan tidak berisi bidang instans yang jenisnya bukan unmanaged_type. Dengan kata lain, unmanaged_type adalah salah satu hal berikut:
-
sbyte,byte,short,ushort,int,uint,long,ulong,char,float,double,decimal, ataubool. - Setiap enum_type.
- Setiap struktur struct_type yang didefinisikan pengguna dan hanya berisikan bidang instance dari unmanaged_type.
- Parameter jenis apa pun yang dibatasi untuk tidak dikelola.
- Setiap pointer_type (§24,3).
8.9 Jenis Referensi dan penghilangan nilai
8.9.1 Umum
Tipe referensi yang dapat bernilai null diindikasikan dengan menambahkan nullable_type_annotation () ke tipe referensi yang tidak bernilai null. Tidak ada perbedaan semantik antara jenis referensi yang tidak dapat diubah ke null dan jenis nullable yang sesuai, keduanya dapat menjadi referensi ke objek atau null. Kehadiran atau tidak adanya nullable_type_annotation menyatakan apakah ekspresi dimaksudkan untuk mengizinkan nilai null atau tidak. Pengkompilasi dapat memberikan diagnostik ketika ekspresi tidak digunakan sesuai dengan niat tersebut. Status null ekspresi ditentukan dalam §8.9.5. Konversi identitas ada di antara jenis referensi nullable dan jenis referensi non-nullable yang bersesuaian (§10.2.2).
Ada dua bentuk kemungkinan bernilai null untuk tipe referensi.
- nullable: Jenis referensi nullable dapat ditetapkan . Status null bawaan adalah mungkin-null.
-
tidak dapat bernilai null: Referensi yang tidak dapat bernilai null tidak boleh diberi
nullnilai. Status null bawaan adalah tidak null.
Catatan: Jenis
RdanR?diwakili oleh jenis yang mendasar yang sama,R. Variabel dari jenis yang mendasar tersebut dapat berisi referensi ke objek atau menjadi nilainull, yang menunjukkan "tidak ada referensi." catatan akhir
Perbedaan sintaktik antara jenis referensi nullable dan jenis referensi non-nullable yang sesuai memungkinkan pengkompilasi untuk menghasilkan diagnostik. Pengkompilasi harus mengizinkan nullable_type_annotation seperti yang didefinisikan dalam §8.2.1. Diagnostik harus terbatas pada peringatan. Apakah ada atau tidaknya anotasi nullable, maupun status konteks nullable tidak dapat mengubah waktu kompilasi atau perilaku runtime program, kecuali pada perubahan pesan diagnostik yang dihasilkan pada waktu kompilasi.
8.9.2 Jenis referensi yang tidak dapat diubah ke null
Jenis referensi non-nullable adalah tipe referensi dalam bentuk T, di mana T adalah nama dari jenis tersebut. Status null default dari variabel yang tidak dapat bernilai null adalah tidak-null. Peringatan dapat dihasilkan ketika ekspresi yang mungkin-null digunakan di mana nilai bukan null diperlukan.
8.9.3 Jenis referensi nullable
Jenis referensi formulir (seperti T?) adalah jenisstring? null. Status null default dari variabel nullable adalah mungkin null. Anotasi ? menunjukkan niat bahwa variabel jenis ini dapat diubah ke null. Pengkompilasi dapat mengenali niat ini untuk mengeluarkan peringatan. Ketika konteks anotasi nullable dinonaktifkan, menggunakan anotasi ini dapat menghasilkan peringatan.
8.9.4 Konteks nullable
8.9.4.1 Umum
Setiap baris kode sumber memiliki konteks nullable. Anotasi dan tanda peringatan untuk kontrol konteks nullable dari anotasi nullable (§8.9.4.3) dan peringatan terkait nullable (§8.9.4.4), masing-masing. Setiap bendera dapat diaktifkan atau dinonaktifkan. Pengkompilasi dapat menggunakan analisis aliran statis untuk menentukan status null dari variabel referensi apa pun. Status null variabel referensi (§8.9.5) bukan null, mungkin null, atau mungkin default.
Konteks nullable dapat ditentukan dalam kode sumber melalui direktif nullable (§6.5.9) dan/atau melalui beberapa mekanisme khusus implementasi di luar kode sumber. Jika kedua pendekatan digunakan, arahan nullable menggantikan pengaturan yang dibuat melalui mekanisme eksternal.
Keadaan default dari konteks nullable ditentukan oleh implementasi.
Sepanjang spesifikasi ini, semua kode C# yang tidak berisi direktif nullable, atau tentang mana tidak ada pernyataan yang dibuat mengenai status konteks nullable saat ini, harus diasumsikan telah dikompilasi menggunakan konteks nullable di mana anotasi dan peringatan diaktifkan.
Catatan: Konteks nullable di mana kedua bendera dinonaktifkan cocok dengan perilaku standar sebelumnya untuk jenis referensi. catatan akhir
8.9.4.2 Nonaktifkan Nullable
Ketika bendera peringatan dan anotasi dinonaktifkan, konteks nullable dinonaktifkan.
Ketika konteks nullable dinonaktifkan:
- Tidak ada peringatan yang akan dihasilkan ketika variabel dari jenis referensi yang tidak diannotasi diinisialisasi dengan, atau diberi nilai,
null. - Tidak ada peringatan yang akan dihasilkan ketika variabel jenis referensi yang mungkin memiliki nilai null.
- Untuk jenis
Treferensi apa pun , anotasi?dalamT?menghasilkan pesan dan jenisnyaT?sama denganT. - Untuk batasan
where T : C?parameter jenis apa pun , anotasi?dalamC?menghasilkan pesan dan jenisnyaC?sama denganC. - Untuk batasan
where T : U?parameter jenis apa pun , anotasi?dalamU?menghasilkan pesan dan jenisnyaU?sama denganU. - Batasan
class?generik menghasilkan pesan peringatan. Parameter jenis harus berupa jenis referensi.Catatan: Pesan ini ditandai sebagai "informasi" daripada "peringatan," agar tidak membingungkannya dengan status pengaturan peringatan nullable, yang tidak terkait. catatan akhir
- Operator
!pengampunan null (§12.8.9) tidak berpengaruh.
Contoh:
#nullable disable annotations string? s1 = null; // Informational message; ? is ignored string s2 = null; // OK; null initialization of a reference s2 = null; // OK; null assignment to a reference char c1 = s2[1]; // OK; no warning on dereference of a possible null; // throws NullReferenceException c1 = s2![1]; // OK; ! is ignoredcontoh akhir
8.9.4.3 Anotasi nullable
Ketika bendera peringatan dinonaktifkan dan bendera anotasi diaktifkan, konteks nullable adalah anotasi.
Ketika konteks nullable adalah anotasi:
- Untuk jenis referensi
Tapa pun, anotasi?dalamT?menunjukkan bahwaT?adalah jenis yang dapat bernilai null, sedangkan yang tidak dianotasiTtidak dapat bernilai null. - Tidak ada peringatan diagnostik yang terkait dengan nullability yang dihasilkan.
- Operator
!null-forgiving (§12.8.9) dapat mengubah status null operand yang dianalisis dan menentukan peringatan diagnostik apa yang muncul saat waktu kompilasi.
Contoh:
#nullable disable warnings #nullable enable annotations string? s1 = null; // OK; ? makes s2 nullable string s2 = null; // OK; warnings are disabled s2 = null; // OK; warnings are disabled char c1 = s2[1]; // OK; warnings are disabled; throws NullReferenceException c1 = s2![1]; // No warningscontoh akhir
8.9.4.4 Peringatan nullable
Ketika bendera peringatan diaktifkan dan bendera anotasi dinonaktifkan, konteks nullable adalah peringatan.
Ketika konteks nullable adalah peringatan, pengkompilasi dapat menghasilkan diagnostik dalam kasus berikut:
- Variabel referensi yang telah ditentukan sebagai mungkin null telah didereferensi.
- Variabel referensi dari jenis non-nullable diberikan ke ekspresi yang mungkin null.
-
?digunakan untuk mencatat jenis referensi yang dapat diubah ke null. - Operator null-forgiving
!(§12.8.9) digunakan untuk mengatur status null operandnya menjadi tidak null.
Contoh:
#nullable disable annotations #nullable enable warnings string? s1 = null; // OK; ? makes s2 nullable string s2 = null; // OK; null-state of s2 is "maybe null" s2 = null; // OK; null-state of s2 is "maybe null" char c1 = s2[1]; // Warning; dereference of a possible null; // throws NullReferenceException c1 = s2![1]; // The warning is suppressedcontoh akhir
8.9.4.5 Aktifkan Nullable
Ketika bendera peringatan dan bendera anotasi diaktifkan, konteks nullable diaktifkan.
Saat konteks nullable diaktifkan:
- Untuk jenis
Treferensi apa pun , anotasi?dalamT?membuatT?jenis nullable, sedangkan yang tidak diannotasiTtidak dapat diubah ke null. - Pengkompilasi dapat menggunakan analisis aliran statis untuk menentukan status null dari variabel referensi apa pun. Ketika peringatan null diaktifkan, status null variabel referensi (§8.9.5) bukan null, mungkin null, atau mungkin default dan
- Operator null-forgiving
!(§12.8.9) mengatur status null operand-nya menjadi tidak null. - Pengkompilasi dapat mengeluarkan peringatan, jika nullability dari parameter jenis tidak sesuai dengan nullability dari argumen jenis yang bersesuaian.
8.9.5 Ke-null-an dan status null
8.9.5.1 Umum
Pengkompilasi tidak diharuskan melakukan analisis statis, juga tidak diharuskan untuk menghasilkan peringatan diagnostik yang terkait dengan nullability.
Sisa subklasul ini bersifat normatif secara kondisional.
8.9.5.2 Analisis alur
Pengkompilasi yang menghasilkan peringatan diagnostik sesuai dengan aturan ini.
Setiap ekspresi memiliki salah satu dari tiga statusnull:
- mungkin null: Nilai ekspresi mungkin bernilai null.
- mungkin default: Nilai ekspresi dapat dievaluasi ke nilai default untuk jenis tersebut.
- bukan null: Nilai ekspresi tidak null.
Status null default ekspresi ditentukan oleh jenisnya, dan status bendera anotasi saat dideklarasikan:
- Status null default dari jenis referensi nullable adalah:
- Mungkin null ketika deklarasinya ada di teks di mana penanda anotasi diaktifkan.
- Tidak null ketika deklarasinya berada dalam teks di mana pengaturan anotasi dinonaktifkan.
- Status null baku dari tipe referensi yang tidak dapat menerima null adalah bukan null.
Catatan: Status default mungkin digunakan dengan parameter jenis yang tidak dibatasi saat jenisnya adalah jenis yang tidak dapat diubah ke null, seperti
stringdan ekspresinyadefault(T)adalah nilai null. Karena null tidak ada di domain untuk jenis yang tidak dapat diubah ke null, statusnya mungkin default. catatan akhir
Diagnostik dapat diproduksi ketika variabel (§9.2.1) dari jenis referensi yang tidak dapat diubah ke null diinisialisasi atau ditetapkan ke ekspresi yang mungkin null ketika variabel tersebut dideklarasikan dalam teks tempat bendera anotasi diaktifkan.
Contoh: Pertimbangkan metode berikut di mana parameter dapat bernilai null dan nilai tersebut ditetapkan ke jenis yang tidak dapat bernilai null:
#nullable enable public class C { public void M(string? p) { // Warning: Assignment of maybe null value to non-nullable variable string s = p; } }
Pengkompilasi dapat mengeluarkan peringatan di mana parameter yang mungkin null ditetapkan ke variabel yang seharusnya tidak null. Jika parameter diperiksa null sebelum penugasan, pengkompilasi dapat menggunakannya dalam analisis status nullable-nya dan tidak mengeluarkan peringatan:
#nullable enable public class C { public void M(string? p) { if (p != null) { string s = p; // No warning // Use s } } }contoh akhir
Pengkompilasi dapat memperbarui status null variabel sebagai bagian dari analisisnya.
Contoh: Pengkompilasi dapat memilih untuk memperbarui status berdasarkan pernyataan apa pun dalam program Anda:
#nullable enable public void M(string? p) { int length = p.Length; // Warning: p is maybe null string s = p; // No warning. p is not null if (s != null) { int l2 = s.Length; // No warning. s is not null } int l3 = s.Length; // Warning. s is maybe null }Dalam contoh sebelumnya, kompilator dapat memutuskan bahwa setelah pernyataan
int length = p.Length;, status nullpbukan null. Jika bernilai null, pernyataan itu akan menghasilkanNullReferenceException. Ini mirip dengan perilaku jika kode telah didahului olehif (p == null) throw NullReferenceException();kecuali bahwa kode seperti yang ditulis dapat menghasilkan peringatan, tujuannya adalah untuk memperingatkan bahwa pengecualian dapat dilemparkan secara implisit. contoh akhir
Kemudian dalam metode, kode memeriksa bahwa s bukan referensi null. Status null s dapat berubah menjadi mungkin null setelah blok yang diperiksa null ditutup. Pengkompilasi dapat menyimpulkan bahwa s mungkin null karena kode ditulis untuk mengasumsikan bahwa kode tersebut mungkin null. Umumnya, ketika kode berisi pemeriksaan null, pengkompilasi dapat menyimpulkan bahwa nilainya mungkin null:
Contoh: Setiap ekspresi berikut menyertakan beberapa bentuk pemeriksaan nilai null. Status null
odapat berubah dari tidak null menjadi mungkin null setelah setiap pernyataan ini:#nullable enable public void M(string s) { int length = s.Length; // No warning. s is not null _ = s == null; // Null check by testing equality. The null state of s // is maybe null length = s.Length; // Warning, and changes the null state of s // to not null _ = s?.Length; // The ?. is a null check and changes the null state of s // to maybe null if (s.Length > 4) // Warning. Changes null state of s to not null { _ = s?[4]; // ?[] is a null check and changes the null state of s // to maybe null _ = s.Length; // Warning. s is maybe null } }
Baik deklarasi properti otomatis maupun peristiwa yang menyerupai bidang memanfaatkan bidang dukungan yang dihasilkan oleh kompilator. Analisis status null dapat menyimpulkan bahwa penetapan pada event atau properti adalah penugasan ke bidang penyangga yang dihasilkan kompilator.
Contoh: Sebuah pengompilasi dapat menentukan bahwa ketika menulis properti otomatis atau peristiwa yang mirip bidang, itu menulis ke bidang penyimpanan yang dihasilkan oleh pengompilasi yang sesuai. Status null properti cocok dengan field pencadangan.
class Test { public string P { get; set; } public Test() {} // Warning. "P" not set to a non-null value. static void Main() { var t = new Test(); int len = t.P.Length; // No warning. Null state is not null. } }Dalam contoh sebelumnya, konstruktor tidak mengatur
Pke nilai bukan null, dan pengkompilasi dapat mengeluarkan peringatan. Tidak ada peringatan ketika propertiPdiakses, karena jenis properti adalah jenis referensi yang tidak dapat diubah ke null. contoh akhir
Pengkompilasi dapat memperlakukan properti (§15,7) sebagai variabel dengan status, atau sebagai aksesor get dan set independen (§15,7,3).
Contoh: Kompilator dapat memilih apakah penulisan ke properti mengubah status null dari pembacaan properti, atau jika pembacaan properti tersebut mengubah status null dari properti itu.
class Test { private string? _field; public string? DisappearingProperty { get { string tmp = _field; _field = null; return tmp; } set { _field = value; } } static void Main() { var t = new Test(); if (t.DisappearingProperty != null) { int len = t.DisappearingProperty.Length; // No warning. A compiler can // assume property is stateful } } }Dalam contoh sebelumnya, bidang pencadangan untuk
DisappearingPropertydiatur ke null saat dibaca. Namun, pengkompilasi dapat mengasumsikan bahwa membaca properti tidak mengubah status null ekspresi tersebut. contoh akhir
Pengkompilasi dapat menggunakan ekspresi apa pun yang mendereferensikan variabel, properti, atau peristiwa untuk mengatur status null ke bukan null. Jika bernilai null, ekspresi dereferensi akan memunculkan NullReferenceException:
Contoh:
public class C { private C? child; public void M() { _ = child.child.child; // Warning. Dereference possible null value var greatGrandChild = child.child.child; // No warning. } }contoh akhir
8.9.5.3 Konversi tipe
Pengkompilasi yang menghasilkan peringatan diagnostik sesuai dengan aturan ini.
Nota: Perbedaan dalam anotasi nullability tingkat atas atau berlapis dalam jenis tidak memengaruhi apakah konversi antara jenis diizinkan, karena tidak ada perbedaan semantik antara jenis referensi yang tidak dapat diubah ke null dan jenis nullable yang sesuai (§8.9.1). catatan akhir
Compiler dapat mengeluarkan peringatan ketika anotasi nullability berbeda antara dua tipe, baik tipe tingkat atas maupun tipe yang terbenam, ketika terjadi konversi yang mempersempit.
Contoh: Jenis yang berbeda dalam anotasi tingkat atas
#nullable enable public class C { public void M1(string p) { _ = (string?)p; // No warning, widening } public void M2(string? p) { _ = (string)p; // Warning, narrowing _ = (string)p!; // No warning, suppressed } }contoh akhir
Contoh: Jenis yang berbeda dalam anotasi nullability berlapis
#nullable enable public class C { public void M1((string, string) p) { _ = ((string?, string?))p; // No warning, widening } public void M2((string?, string?) p) { _ = ((string, string))p; // Warning, narrowing _ = ((string, string))p!; // No warning, suppressed } }contoh akhir
Kompilator dapat mengikuti aturan untuk varian antarmuka (§19.2.3.3), mendelegasikan varians (§21,4), dan kovarian array (§17,6) dalam menentukan apakah akan mengeluarkan peringatan untuk konversi jenis.
#nullable enable public class C { public void M1(IEnumerable<string> p) { IEnumerable<string?> v1 = p; // No warning } public void M2(IEnumerable<string?> p) { IEnumerable<string> v1 = p; // Warning IEnumerable<string> v2 = p!; // No warning } public void M3(Action<string?> p) { Action<string> v1 = p; // No warning } public void M4(Action<string> p) { Action<string?> v1 = p; // Warning Action<string?> v2 = p!; // No warning } public void M5(string[] p) { string?[] v1 = p; // No warning } public void M6(string?[] p) { string[] v1 = p; // Warning string[] v2 = p!; // No warning } }contoh akhir
Pengkompilasi dapat mengeluarkan peringatan ketika nullability berbeda dalam salah satu arah dalam jenis yang tidak mengizinkan konversi varian.
#nullable enable public class C { public void M1(List<string> p) { List<string?> v1 = p; // Warning List<string?> v2 = p!; // No warning } public void M2(List<string?> p) { List<string> v1 = p; // Warning List<string> v2 = p!; // No warning } }contoh akhir
Akhir teks normatif kondisional
ECMA C# draft specification