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 dan jenis referensi mungkin jenis generik, yang mengambil satu atau beberapa parameter tipe. Parameter jenis dapat menunjuk jenis nilai dan jenis referensi.
type
: reference_type
| value_type
| type_parameter
| pointer_type // unsafe code support
;
pointer_type (§23.3) hanya tersedia dalam kode tidak aman (§23).
Jenis nilai berbeda dari jenis referensi dalam hal variabel dari jenis nilai langsung mengandung datanya, sementara variabel dari jenis referensi menyimpan referensi ke data mereka, yang terakhir ini 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, atau jenisnya dynamic
. 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 yang tidak aman (§23.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 fungsi (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 §19,5. |
System.Array |
Kelas dasar dari semua jenis array. Lihat §17.2.2. |
System.Delegate |
Kelas dasar dari semua delegate tipe. Lihat §20.1. |
System.Exception |
Kelas dasar dari semua jenis pengecualian. Lihat §21.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.Object
yang 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.String
yang 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 §18.
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 §20.
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 class
System.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
, ,byte
short
,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
HasValue
propertinya salah. Nilai default juga dikenal sebagai nilai null dari jenis nilai nullable. Mencoba membaca properti dari nilai tersebutValue
menyebabkan pengecualian jenisSystem.InvalidOperationException
dilemparkan (§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
,j
dank
semuanya 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:
int
memiliki anggota yang dinyatakan diSystem.Int32
dan 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 method
contoh 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:
123
adalah jenis harfiahint
dan'a'
merupakan jenischar
harfiah . 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.23). Ekspresi yang melibatkan operator yang ditentukan oleh jenis struct lainnya tidak dianggap sebagai ekspresi konstanta
- Melalui
const
deklarasi, 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
, ushort
int
, uint
, long
, ulong
, , dan char
. Jenis integral memiliki ukuran dan rentang nilai berikut:
- Tipe
sbyte
mewakili bilangan bulat 8-bit yang ditandatangani dengan nilai dari-128
hingga127
, termasuk. - Jenis
byte
mewakili bilangan bulat 8-bit yang tidak bertanda dengan nilai dari0
hingga255
, termasuk. - Jenis
short
mewakili bilangan bulat 16-bit berjenis signed dengan nilai dari-32768
hingga32767
. - Jenis
ushort
mewakili bilangan bulat 16-bit tanpa tanda dengan nilai dari0
hingga65535
, inklusif. - Jenis
int
mewakili bilangan bulat 32-bit bertanda dengan nilai dari-2147483648
sampai2147483647
inklusif. -
uint
tipe mewakili bilangan bulat 32-bit tanpa tanda dengan nilai dari0
hingga4294967295
, termasuk. - Tipe
long
mewakili bilangan bulat 64-bit bertanda dengan nilai dari-9223372036854775808
sampai9223372036854775807
, inklusif. - Jenis
ulong
mewakili bilangan bulat 64-bit yang tidak bertanda dengan nilai dari0
hingga18446744073709551615
, termasuk. - Jenis
char
mewakili bilangan bulat 16-bit tanpa tanda dengan nilai dari0
hingga65535
, inklusif. Kumpulan nilai yang mungkin untuk tipechar
sesuai dengan kumpulan karakter Unicode.Catatan: Meskipun
char
memiliki 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, meskipunbyte
danushort
jenis memiliki rentang nilai yang sepenuhnya dapat diwakili menggunakan jenischar
, konversi implisit dari sbyte, byte, atauushort
kechar
tidak ada. - Konstanta jenis
char
harus ditulis sebagai character_literal atau sebagai integer_literal dalam kombinasi dengan casting ke tipe karakter.
Contoh:
(char)10
sama'\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.10.3).
- Tak terhingga positif dan tak terhingga negatif. Infinities diproduksi oleh operasi seperti membabungkan angka bukan nol dengan nol.
Contoh:
1.0 / 0.0
menghasilkan tak terbatas positif, dan–1.0 / 0.0
menghasilkan 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 tipe floating-point menjadi presisi yang tepat dari tipe tersebut, cast eksplisit (§12.9.7) 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 luardouble
rentang, tetapi pembagian berikutnya membawa hasil sementara kembali ke dalamdouble
rentang, 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
false
Boolean , dan nilai integral atau floating-point bukan nol, atau pointer non-null dapat dikonversi ke nilaitrue
Boolean . 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
, ushort
int
, 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 (§19,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
memiliki nama elemen tuple yang opsional.
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
, danpair3
semuanya valid, dengan nama untuk tidak, beberapa atau semua elemen jenis tuple.Jenis tuple untuk
pair4
valid karena namaItem1
danItem2
cocok dengan posisinya, sedangkan jenis tuple untukpair5
tidak diizinkan, karena namaItem2
danItem123
tidak.Deklarasi untuk
pair6
danpair7
menunjukkan bahwa tipe tuple dapat dipertukarkan dengan tipe yang dibangun dalam bentukValueTuple<...>
, dan bahwa operatornew
diizinkan dengan sintaks yang terakhir.Baris terakhir menunjukkan bahwa elemen tuple dapat diakses dengan nama
Item
yang 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
HasValue
dari jenisbool
- Properti
Value
dari jenisT
Instans yang HasValue
true
dikatakan non-null. Instans non-null berisi nilai yang diketahui dan Value
mengembalikan nilai tersebut.
Instans yang HasValue
false
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 nilai nullable T?
tidak mengimplementasikan antarmuka (§18). 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
Semua jenis 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
class
jenis, jenis antarmuka, atau parameter jenis, biarkanC
mewakili 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 jenisA
dapat dikonversi menjadi tipeC
melalui salah satu metode berikut: - Jika batasan adalah batasan jenis referensi (
class
), jenisA
harus memenuhi salah satu hal berikut:-
A
adalah jenis antarmuka, jenis kelas, jenis delegasi, jenis array, atau jenis dinamis.
Catatan:
System.ValueType
danSystem.Enum
merupakan jenis referensi yang memenuhi batasan ini. catatan akhir-
A
adalah parameter jenis yang dikenal sebagai jenis referensi (§8.2).
-
- Jika batasan adalah batasan jenis nilai (
struct
), jenisA
harus memenuhi salah satu hal berikut:-
A
adalah tipestruct
atau tipeenum
, tetapi bukan tipe nilai yang dapat bernilai null.
Catatan:
System.ValueType
danSystem.Enum
merupakan jenis referensi yang tidak memenuhi batasan ini. catatan akhir-
A
adalah parameter jenis yang memiliki batasan jenis nilai (§15.2.5).
-
- Jika batasan adalah batasan konstruktor
new()
, jenisnyaA
tidak bolehabstract
dan harus memiliki konstruktor tanpa parameter publik. Ini terpenuhi jika salah satu hal berikut ini benar:-
A
adalah jenis nilai, karena semua jenis nilai memiliki konstruktor default publik (§8.3.3). -
A
adalah parameter jenis yang memiliki batasan konstruktor (§15.2.5). -
A
adalah parameter jenis yang memiliki batasan jenis nilai (§15.2.5). -
A
adalahclass
yang tidak abstrak dan berisi konstruktor publik yang dideklarasikan secara eksplisit tanpa parameter. -
A
tidakabstract
dan 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,
D
perlu menentukan batasan pada parameterT
jenisnya sehinggaT
memenuhi batasan yang diberlakukan oleh dasarclass
B<T>
. Sebaliknya,class
E
tidak perlu menentukan batasan, karenaList<T>
mengimplementasikanIEnumerable
untuk 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 (§18.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
null
tidak 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.12.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 mengizinkan ekspresi lambda direpresentasikan sebagai struktur data alih-alih kode yang dapat dieksekusi. Pohon ekspresi adalah nilai dari jenis pohon ekspresi berbentuk System.Linq.Expressions.Expression<TDelegate>
, di mana TDelegate
adalah tipe 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; // Data
Setelah penugasan ini, delegasi
del
merujuk 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
dynamic
dapat terikat secara dinamis (§12.3.3). - Inferensi jenis (§12.6.3) akan lebih memilih
dynamic
daripadaobject
jika keduanya adalah kandidat. -
dynamic
tidak 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
object
dandynamic
- antara tipe yang dibangun yang identik ketika mengganti
dynamic
denganobject
- antara jenis tuple yang sama saat mengganti
dynamic
denganobject
- antara
- Konversi implisit dan eksplisit ke dan dari
object
juga berlaku ke dan daridynamic
. - Tanda tangan yang sama saat mengganti
dynamic
denganobject
dianggap sebagai tanda tangan yang sama. - Jenis
dynamic
ini tidak dapat dibedakan dari jenisobject
pada run-time. - Ekspresi jenis
dynamic
disebut 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 (§23.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
null
nilai. Status null bawaan adalah tidak null.
Catatan: Jenis
R
danR?
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
T
referensi 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 ignored
contoh 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
T
apa pun, anotasi?
dalamT?
menunjukkan bahwaT?
adalah jenis yang dapat bernilai null, sedangkan yang tidak dianotasiT
tidak 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 warnings
contoh 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 suppressed
contoh akhir
8.9.4.5 Aktifkan Nullable
Ketika bendera peringatan dan bendera anotasi diaktifkan, konteks nullable diaktifkan.
Saat konteks nullable diaktifkan:
- Untuk jenis
T
referensi apa pun , anotasi?
dalamT?
membuatT?
jenis nullable, sedangkan yang tidak diannotasiT
tidak 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
string
dan 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 nullp
bukan 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
o
dapat 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
P
ke nilai bukan null, dan pengkompilasi dapat mengeluarkan peringatan. Tidak ada peringatan ketika propertiP
diakses, 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
DisappearingProperty
diatur 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
Pengkompilasi dapat mengikuti aturan untuk varian antarmuka (§18.2.3.3), mendelegasikan varians (§20,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 dari teks yang bersifat normatif kondisional
ECMA C# draft specification