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.
9.1 Umum
Variabel mewakili lokasi penyimpanan. Setiap variabel memiliki jenis yang menentukan nilai apa yang dapat disimpan dalam variabel. C# adalah bahasa yang aman jenis, dan pengkompilasi C# menjamin bahwa nilai yang disimpan dalam variabel selalu dari jenis yang sesuai. Nilai variabel dapat diubah melalui penugasan atau melalui penggunaan ++ operator dan -- .
Variabel pasti akan ditetapkan (§9,4) sebelum nilainya dapat diperoleh.
Seperti yang dijelaskan dalam subklasus berikut, variabel awalnya ditetapkan atau awalnya tidak ditetapkan. Variabel yang awalnya ditetapkan memiliki nilai awal yang terdefinisi dengan baik dan selalu dianggap pasti ditetapkan. Variabel yang awalnya tidak ditetapkan tidak memiliki nilai awal. Agar variabel yang awalnya tidak ditetapkan dianggap pasti ditetapkan di lokasi tertentu, penugasan ke variabel akan terjadi di setiap jalur eksekusi yang mungkin mengarah ke lokasi tersebut.
9.2 Kategori variabel
9.2.1 Umum
C# mendefinisikan delapan kategori variabel: variabel statis, variabel instans, elemen array, parameter nilai, parameter input, parameter referensi, parameter output, dan variabel lokal. Subklaus yang mengikuti menjelaskan masing-masing kategori ini.
Contoh: Dalam kode berikut
class A { public static int x; int y; void F(int[] v, int a, ref int b, out int c, in int d) { int i = 1; c = a + b++ + d; } }
xadalah variabel statis,yadalah variabel instans,v[0]adalah elemen array,aadalah parameter nilai,badalah parameter referensi,cadalah parameter output,dadalah parameter input, danimerupakan variabel lokal. contoh akhir
9.2.2 Variabel statis
Bidang yang dideklarasikan dengan pengubah static adalah variabel statis. Variabel statis muncul sebelum eksekusi static konstruktor (§15.12) untuk jenis penampungnya, dan berhenti ada ketika domain aplikasi terkait berhenti ada.
Nilai awal variabel statis adalah nilai default (§9,3) dari jenis variabel.
Untuk tujuan pemeriksaan penetapan pasti, variabel statis dianggap awalnya ditetapkan.
9.2.3 Variabel instans
9.2.3.1 Umum
Bidang yang dideklarasikan tanpa pengubah static adalah variabel instans.
9.2.3.2 Variabel instans di kelas
Variabel instans kelas muncul ketika instans baru kelas tersebut dibuat, dan berhenti ada ketika tidak ada referensi ke instans tersebut dan finalizer instans (jika ada) telah dijalankan.
Nilai awal variabel instans kelas adalah nilai default (§9,3) dari jenis variabel.
Untuk tujuan pemeriksaan penetapan pasti, variabel instans kelas dianggap awalnya ditetapkan.
9.2.3.3 Variabel instans dalam struktur
Variabel instans dari struct memiliki masa pakai yang sama persis dengan variabel struct tempatnya berada. Dengan kata lain, ketika variabel jenis struct muncul atau berhenti ada, begitu juga variabel instans dari struct.
Status penugasan awal variabel instans dari struct sama dengan variabel yang berisi struct . Dengan kata lain, ketika variabel struct dianggap awalnya ditetapkan, demikian juga variabel instansnya, dan ketika variabel struct dianggap awalnya tidak ditetapkan, variabel instansnya juga tidak ditetapkan.
9.2.4 Elemen array
Elemen array muncul ketika instans array dibuat, dan berhenti ada ketika tidak ada referensi ke instans array tersebut.
Nilai awal dari setiap elemen array adalah nilai default (§9,3) dari jenis elemen array.
Untuk tujuan pemeriksaan penetapan pasti, elemen array dianggap awalnya ditetapkan.
9.2.5 Parameter nilai
Parameter nilai muncul setelah pemanggilan anggota fungsi (metode, konstruktor instans, aksesor, atau operator) atau fungsi anonim tempat parameter berada, dan diinisialisasi dengan nilai argumen yang diberikan dalam pemanggilan. Parameter nilai biasanya berhenti ada ketika eksekusi isi fungsi selesai. Namun, jika parameter nilai ditangkap oleh fungsi anonim (§12.21.6.2), masa pakainya diperpanjang setidaknya sampai delegasi atau pohon ekspresi yang dibuat dari fungsi anonim tersebut memenuhi syarat untuk pengumpulan sampah.
Untuk tujuan pemeriksaan penetapan pasti, parameter nilai dianggap awalnya ditetapkan.
Parameter nilai dibahas lebih lanjut dalam §15.6.2.2.
9.2.6 Parameter referensi
Parameter referensi adalah variabel referensi (§9,7) yang muncul setelah pemanggilan anggota fungsi, delegasi, fungsi anonim, atau fungsi lokal dan referensinya diinisialisasi ke variabel yang diberikan sebagai argumen dalam pemanggilan tersebut. Parameter referensi berhenti ada ketika eksekusi isi fungsi selesai. Tidak seperti parameter nilai parameter referensi tidak akan diambil (§9.7.2.9).
Aturan penetapan pasti berikut berlaku untuk parameter referensi.
Catatan: Aturan untuk parameter output berbeda, dan dijelaskan dalam (§9.2.7). catatan akhir
- Variabel pasti akan ditetapkan (§9,4) sebelum dapat diteruskan sebagai parameter referensi dalam anggota fungsi atau mendelegasikan pemanggilan.
- Dalam anggota fungsi atau fungsi anonim, parameter referensi dianggap awalnya ditetapkan.
Parameter referensi dibahas lebih lanjut dalam §15.6.2.3.3.
9.2.7 Parameter output
Parameter output adalah variabel referensi (§9,7) yang muncul setelah pemanggilan anggota fungsi, delegasi, fungsi anonim, atau fungsi lokal dan referensinya diinisialisasi ke variabel yang diberikan sebagai argumen dalam pemanggilan tersebut. Parameter output berhenti ada ketika eksekusi isi fungsi selesai. Tidak seperti parameter nilai parameter output tidak boleh diambil (§9.7.2.9).
Aturan penetapan pasti berikut berlaku untuk parameter output.
Catatan: Aturan untuk parameter referensi berbeda, dan dijelaskan dalam (§9.2.6). catatan akhir
- Variabel tidak perlu ditetapkan secara pasti sebelum dapat diteruskan sebagai parameter output dalam anggota fungsi atau mendelegasikan pemanggilan.
- Setelah penyelesaian normal anggota fungsi atau mendelegasikan pemanggilan, setiap variabel yang diteruskan sebagai parameter output dianggap ditetapkan dalam jalur eksekusi tersebut.
- Dalam anggota fungsi atau fungsi anonim, parameter output dianggap awalnya tidak ditetapkan.
- Setiap parameter output anggota fungsi, fungsi anonim, atau fungsi lokal harus benar-benar ditetapkan (§9,4) sebelum anggota fungsi, fungsi anonim, atau fungsi lokal kembali secara normal.
Parameter output dibahas lebih lanjut dalam §15.6.2.3.4.
9.2.8 Parameter input
Parameter input adalah variabel referensi (§9,7) yang muncul setelah pemanggilan anggota fungsi, delegasi, fungsi anonim, atau fungsi lokal dan referensinya diinisialisasi ke variable_reference yang diberikan sebagai argumen dalam pemanggilan tersebut. Parameter input berhenti ada ketika eksekusi isi fungsi selesai. Tidak seperti parameter nilai parameter input tidak akan diambil (§9.7.2.9).
Aturan penetapan pasti berikut berlaku untuk parameter input.
- Variabel pasti akan ditetapkan (§9,4) sebelum dapat diteruskan sebagai parameter input dalam anggota fungsi atau mendelegasikan pemanggilan.
- Dalam anggota fungsi, fungsi anonim, atau fungsi lokal, parameter input dianggap awalnya ditetapkan.
Parameter input dibahas lebih lanjut dalam §15.6.2.3.2.
9.2.9 Variabel lokal
9.2.9.1 Umum
Variabel lokal dideklarasikan oleh local_variable_declaration, declaration_expression, foreach_statement, atau specific_catch_clausetry_statement. Variabel lokal juga dapat dideklarasikan oleh jenis pola tertentu (§11). Untuk foreach_statement, variabel lokal adalah variabel iterasi (§13.9.5). Untuk specific_catch_clause, variabel lokal adalah variabel pengecualian (§13.11). Variabel lokal yang dideklarasikan oleh foreach_statement atau specific_catch_clause dianggap awalnya ditetapkan.
Local_variable_declaration dapat terjadi di blok, for_statement, switch_block, atau using_statement.
Declaration_expression dapat terjadi sebagai outargument_value, dan sebagai tuple_element yang merupakan target penugasan dekonstruksi (§12.23.2).
Masa pakai variabel lokal adalah bagian dari eksekusi program di mana penyimpanan dijamin akan dicadangkan untuk itu. Masa pakai ini meluas dari entri ke dalam cakupan yang terkait dengannya, setidaknya sampai eksekusi cakupan tersebut berakhir dalam beberapa cara. (Memasukkan blok tertutup, memanggil metode, atau menghasilkan nilai dari blok iterator menangguhkan, tetapi tidak berakhir, eksekusi cakupan saat ini.) Jika variabel lokal ditangkap oleh fungsi anonim (§12.21.6.2), masa pakainya meluas setidaknya hingga delegasi atau pohon ekspresi yang dibuat dari fungsi anonim, bersama dengan objek lain yang mereferensikan variabel yang ditangkap, memenuhi syarat untuk pengumpulan sampah. Jika cakupan induk dimasukkan secara rekursif atau berulang, instans baru variabel lokal dibuat setiap kali, dan inisialisasinya, jika ada, dievaluasi setiap kali.
Catatan: Variabel lokal dibuat setiap kali cakupannya dimasukkan. Perilaku ini terlihat oleh kode pengguna yang berisi metode anonim. catatan akhir
Catatan: Masa pakai variabel iterasi (§13.9.5) yang dideklarasikan oleh foreach_statement adalah perulangan tunggal dari pernyataan tersebut. Setiap perulangan membuat variabel baru. catatan akhir
Catatan: Masa pakai aktual variabel lokal bergantung pada implementasi. Misalnya, pengkompilasi mungkin secara statis menentukan bahwa variabel lokal dalam blok hanya digunakan untuk sebagian kecil blok tersebut. Dengan menggunakan analisis ini, kompilator dapat menghasilkan kode yang mengakibatkan penyimpanan variabel memiliki masa pakai yang lebih pendek daripada blok yang berisi.
Penyimpanan yang dimaksud oleh variabel referensi lokal direklamasi secara independen dari masa pakai variabel referensi lokal tersebut (§7,9).
catatan akhir
Variabel lokal yang diperkenalkan oleh local_variable_declaration atau declaration_expression tidak diinisialisasi secara otomatis dan dengan demikian tidak memiliki nilai default. Variabel lokal seperti itu dianggap awalnya tidak ditetapkan.
Catatan: Local_variable_declaration yang menyertakan penginisialisasi awalnya masih belum ditetapkan. Eksekusi deklarasi berperilaku persis seperti penugasan ke variabel (§9.4.4.5). Menggunakan variabel sebelum penginisialisasinya dijalankan; misalnya, dalam ekspresi penginisialisasi itu sendiri atau dengan menggunakan goto_statement yang melewati penginisialisasi; adalah kesalahan waktu kompilasi:
goto L; int x = 1; // never executed L: x += 1; // error: x not definitely assignedDalam cakupan variabel lokal, ini adalah kesalahan waktu kompilasi untuk merujuk ke variabel lokal tersebut dalam posisi tekstual yang mendahului deklaratornya.
catatan akhir
9.2.9.2 Pembuangan
Buang adalah variabel lokal yang tidak memiliki nama. Buang diperkenalkan oleh ekspresi deklarasi (§12.19) dengan pengidentifikasi _; dan secara implisit diketik (_ atau var _) atau diketik secara eksplisit (T _).
Catatan:
_adalah pengidentifikasi yang valid dalam banyak bentuk deklarasi. catatan akhir
Karena buang tidak memiliki nama, satu-satunya referensi ke variabel yang diwakilinya adalah ekspresi yang memperkenalkannya.
Catatan: Buang namun dapat diteruskan sebagai argumen output, memungkinkan parameter output yang sesuai untuk menunjukkan lokasi penyimpanan terkait. catatan akhir
Buang awalnya tidak ditetapkan, jadi selalu kesalahan untuk mengakses nilainya.
Contoh:
_ = "Hello".Length; (int, int, int) M(out int i1, out int i2, out int i3) { ... } (int _, var _, _) = M(out int _, out var _, out _);Contoh mengasumsikan bahwa tidak ada deklarasi nama
_dalam cakupan.Penugasan untuk
_menunjukkan pola sederhana untuk mengabaikan hasil ekspresi. PanggilanMmenunjukkan berbagai bentuk pembuangan yang tersedia dalam tuple dan sebagai parameter output.contoh akhir
9.3 Nilai default
Kategori variabel berikut secara otomatis diinisialisasi ke nilai defaultnya:
- Variabel statis.
- Variabel instans instans instans kelas.
- Elemen array.
Nilai default variabel tergantung pada jenis variabel dan ditentukan sebagai berikut:
- Untuk variabel value_type, nilai defaultnya sama dengan nilai yang dihitung oleh konstruktor default value_type (§8.3.3).
- Untuk variabel reference_type, nilai defaultnya adalah
null.
Catatan: Inisialisasi ke nilai default biasanya dilakukan dengan meminta manajer memori atau pengumpul sampah menginisialisasi memori ke all-bits-zero sebelum dialokasikan untuk digunakan. Untuk alasan ini, lebih mudah untuk menggunakan all-bits-zero untuk mewakili referensi null. catatan akhir
9.4 Penetapan pasti
9.4.1 Umum
Pada lokasi tertentu dalam kode yang dapat dieksekusi dari anggota fungsi atau fungsi anonim, variabel dikatakan pasti ditetapkan jika pengompilasi dapat membuktikan, dengan analisis aliran statis tertentu (§9,4,4), bahwa variabel telah secara otomatis diinisialisasi atau telah menjadi target setidaknya satu penugasan.
Catatan: Dinyatakan secara informal, aturan penetapan pasti adalah:
- Variabel yang awalnya ditetapkan (§9.4.2) selalu dianggap pasti ditetapkan.
- Variabel yang awalnya tidak ditetapkan (§9.4.3) dianggap pasti ditetapkan di lokasi tertentu jika semua jalur eksekusi yang mungkin mengarah ke lokasi tersebut berisi setidaknya salah satu dari yang berikut ini:
- Penugasan sederhana (§12.23.2) di mana variabel adalah operan kiri.
- Ekspresi pemanggilan (§12.8.10) atau ekspresi pembuatan objek (§12.8.17.2) yang meneruskan variabel sebagai parameter output.
- Untuk variabel lokal, deklarasi variabel lokal untuk variabel (§13.6.2) yang menyertakan penginisialisasi variabel.
Spesifikasi formal yang mendasar aturan informal di atas dijelaskan dalam §9.4.2, §9.4.3, dan §9.4.4.
catatan akhir
Status penetapan pasti variabel instans dari variabel struct_type dilacak secara individual serta secara kolektif. Selain aturan yang dijelaskan dalam §9.4.2, §9.4.3, dan §9.4.4, aturan berikut berlaku untuk variabel struct_type dan variabel instansnya:
- Variabel instans dianggap pasti ditetapkan jika yang berisi variabel struct_type dianggap pasti ditetapkan.
- Variabel struct_type dianggap pasti ditetapkan jika setiap variabel instansnya dianggap pasti ditetapkan.
Penetapan pasti adalah persyaratan dalam konteks berikut:
Variabel pasti akan ditetapkan di setiap lokasi tempat nilainya diperoleh.
Catatan: Ini memastikan bahwa nilai yang tidak terdefinisi tidak pernah terjadi. catatan akhir
Kemunculan variabel dalam ekspresi dianggap untuk mendapatkan nilai variabel, kecuali ketika
- variabel adalah operan kiri dari penugasan sederhana,
- variabel diteruskan sebagai parameter output, atau
- variabel adalah variabel struct_type dan terjadi sebagai operand kiri akses anggota.
Variabel pasti akan ditetapkan di setiap lokasi tempat variabel diteruskan sebagai parameter referensi.
Catatan: Ini memastikan bahwa anggota fungsi yang dipanggil dapat mempertimbangkan parameter referensi yang awalnya ditetapkan. catatan akhir
Variabel pasti akan ditetapkan di setiap lokasi tempat variabel diteruskan sebagai parameter input.
Catatan: Ini memastikan bahwa anggota fungsi yang dipanggil dapat mempertimbangkan parameter input yang awalnya ditetapkan. catatan akhir
Semua parameter output anggota fungsi harus ditugaskan di setiap lokasi tempat anggota fungsi mengembalikan (melalui pernyataan pengembalian atau melalui eksekusi yang mencapai akhir isi anggota fungsi).
Catatan: Ini memastikan bahwa anggota fungsi tidak mengembalikan nilai yang tidak ditentukan dalam parameter output, sehingga memungkinkan pengkompilasi untuk mempertimbangkan pemanggilan anggota fungsi yang mengambil variabel sebagai parameter output yang setara dengan penugasan ke variabel. catatan akhir
Variabel
thiskonstruktor instans struct_type pasti akan ditetapkan di setiap lokasi tempat konstruktor instans tersebut kembali.
9.4.2 Variabel awal yang ditetapkan
Kategori variabel berikut diklasifikasikan sebagai awalnya ditetapkan:
- Variabel statis.
- Variabel instans instans instans kelas.
- Variabel instans dari variabel struct yang awalnya ditetapkan.
- Elemen array.
- Parameter nilai.
- Parameter referensi.
- Parameter input.
- Variabel dideklarasikan dalam
catchklausa atauforeachpernyataan.
9.4.3 Variabel awalnya tidak ditetapkan
Kategori variabel berikut diklasifikasikan sebagai awalnya tidak ditetapkan:
- Variabel instans dari variabel struct yang awalnya tidak ditetapkan.
- Parameter output, termasuk
thisvariabel konstruktor instans struct tanpa inisialisasi konstruktor. - Variabel lokal, kecuali yang dideklarasikan dalam
catchklausul atauforeachpernyataan.
9.4.4 Aturan yang tepat untuk menentukan penetapan yang pasti
9.4.4.1 Umum
Untuk menentukan bahwa setiap variabel yang digunakan pasti ditetapkan, pengkompilasi harus menggunakan proses yang setara dengan yang dijelaskan dalam subklasul ini.
Isi anggota fungsi dapat mendeklarasikan satu atau beberapa variabel yang awalnya tidak ditetapkan. Untuk setiap variabel yang awalnya tidak ditetapkan v, pengkompilasi harus menentukan status penetapan untuk v pada setiap titik berikut dalam anggota fungsi:
- Di awal setiap pernyataan
- Pada titik akhir (§13,2) dari setiap pernyataan
- Pada setiap busur yang mentransfer kontrol ke pernyataan lain atau ke titik akhir pernyataan
- Di awal setiap ekspresi
- Di akhir setiap ekspresi
Status penetapan pasti v dapat berupa:
- Pasti ditugaskan. Ini menunjukkan bahwa pada semua kemungkinan alur kontrol ke titik ini, v telah diberi nilai.
- Tidak pasti ditugaskan. Untuk status variabel di akhir ekspresi jenis
bool, status variabel yang tidak pasti ditetapkan mungkin (tetapi tidak selalu) termasuk dalam salah satu sub-status berikut:- Pasti ditetapkan setelah ekspresi benar. Status ini menunjukkan bahwa v pasti ditetapkan jika ekspresi Boolean dievaluasi sebagai true, tetapi belum tentu ditetapkan jika ekspresi Boolean dievaluasi sebagai false.
- Pasti ditetapkan setelah ekspresi palsu. Status ini menunjukkan bahwa v pasti ditetapkan jika ekspresi Boolean dievaluasi sebagai false, tetapi belum tentu ditetapkan jika ekspresi Boolean dievaluasi sebagai true.
Aturan berikut mengatur bagaimana status variabel v ditentukan di setiap lokasi.
9.4.4.2 Aturan umum untuk pernyataan
- v tidak pasti ditetapkan di awal isi anggota fungsi.
- Status penetapan pasti v di awal pernyataan lain ditentukan dengan memeriksa status penetapan v yang ditentukan pada semua transfer alur kontrol yang menargetkan awal pernyataan tersebut. Jika (dan hanya jika) v pasti ditetapkan pada semua transfer alur kontrol tersebut, maka v pasti ditetapkan di awal pernyataan. Kumpulan kemungkinan transfer alur kontrol ditentukan dengan cara yang sama seperti untuk memeriksa keterjangkauan pernyataan (§13.2).
- Status penetapan pasti v di titik
blockakhir dari pernyataan , , ,checkedunchecked,ifwhiledoforforeachlockusing, atauswitchditentukan dengan memeriksa status penetapan pasti v pada semua transfer alur kontrol yang menargetkan titik akhir pernyataan tersebut. Jika v pasti ditetapkan pada semua transfer alur kontrol tersebut, maka v pasti ditetapkan di titik akhir pernyataan. Jika tidak, v tidak pasti ditetapkan di titik akhir pernyataan. Kumpulan kemungkinan transfer alur kontrol ditentukan dengan cara yang sama seperti untuk memeriksa keterjangkauan pernyataan (§13.2).
Catatan: Karena tidak ada jalur kontrol ke pernyataan yang tidak dapat dijangkau, v pasti ditetapkan di awal pernyataan yang tidak dapat dijangkau. catatan akhir
9.4.4.3 Pernyataan blokir, diperiksa, dan tidak dicentang pernyataan
Status penetapan pasti v pada transfer kontrol ke pernyataan pertama daftar pernyataan di blok (atau ke titik akhir blok, jika daftar pernyataan kosong) sama dengan pernyataan penetapan yang ditentukan v sebelum blok, checked, atau unchecked pernyataan.
9.4.4.4 Pernyataan ekspresi
Untuk pernyataan ekspresi stmt yang terdiri dari ekspresi expr:
- v memiliki status penetapan yang sama di awal expr seperti pada awal stmt.
- Jika v jika pasti ditetapkan di akhir expr, itu pasti ditetapkan di titik akhir stmt; jika tidak, itu tidak pasti ditetapkan di titik akhir stmt.
9.4.4.5 Pernyataan deklarasi
- Jika stmt adalah pernyataan deklarasi tanpa penginisialisasi, maka v memiliki status penetapan yang sama di titik akhir stmt seperti pada awal stmt.
- Jika stmt adalah pernyataan deklarasi dengan penginisialisasi, maka status penetapan pasti untuk v ditentukan seolah-olah stmt adalah daftar pernyataan, dengan satu pernyataan penugasan untuk setiap deklarasi dengan inisialisasi (dalam urutan deklarasi).
9.4.4.6 Jika pernyataan
Untuk pernyataan stmt formulir:
if ( «expr» ) «then_stmt» else «else_stmt»
- v memiliki status penetapan yang sama di awal expr seperti pada awal stmt.
- Jika v pasti ditetapkan di akhir expr, maka pasti ditetapkan pada transfer alur kontrol ke then_stmt dan ke else_stmt atau ke titik akhir stmt jika tidak ada klausul lain.
- Jika v memiliki status "pasti ditetapkan setelah ekspresi benar" di akhir expr, maka pasti ditetapkan pada transfer alur kontrol ke then_stmt, dan tidak pasti ditetapkan pada transfer alur kontrol ke else_stmt atau ke titik akhir stmt jika tidak ada klausul lain.
- Jika v memiliki status "pasti ditetapkan setelah ekspresi palsu" di akhir expr, maka pasti ditetapkan pada transfer alur kontrol ke else_stmt, dan tidak pasti ditetapkan pada transfer alur kontrol ke then_stmt. Ini pasti ditetapkan di titik akhir stmt jika dan hanya jika pasti ditetapkan di titik akhir then_stmt.
- Jika tidak, v dianggap tidak pasti ditetapkan pada transfer alur kontrol ke then_stmt atau else_stmt, atau ke titik akhir stmt jika tidak ada klausul lain.
9.4.4.7 Pernyataan pengalihan
Untuk pernyataan switch dengan ekspresi pengontrol expr:
Status penetapan pasti v di awal expr sama dengan status v di awal stmt.
Status penetapan pasti v di awal klausul penjaga kasus adalah
- Jika v adalah variabel pola yang dideklarasikan dalam switch_label: "pasti ditetapkan".
- Jika label sakelar yang berisi klausul penjaga (§13.8.3) tidak dapat dijangkau: "pasti ditetapkan".
- Jika tidak, status v sama dengan status v setelah expr.
Contoh: Aturan kedua menghilangkan kebutuhan kompilator untuk mengeluarkan kesalahan jika variabel yang tidak ditetapkan diakses dalam kode yang tidak dapat dijangkau. Status b "pasti ditetapkan" dalam label
case 2 when bsakelar yang tidak dapat dijangkau .bool b; switch (1) { case 2 when b: // b is definitely assigned here. break; }contoh akhir
Status penetapan pasti v pada transfer alur kontrol ke daftar pernyataan blok sakelar yang dapat dijangkau adalah
- Jika transfer kontrol disebabkan oleh pernyataan 'goto case' atau 'goto default', maka status v sama dengan status di awal pernyataan 'goto'.
- Jika transfer kontrol disebabkan oleh
defaultlabel sakelar, maka status v sama dengan status v setelah expr. - Jika transfer kontrol disebabkan oleh label sakelar yang tidak dapat dijangkau, maka status v "pasti ditetapkan".
- Jika transfer kontrol disebabkan oleh label sakelar yang dapat dijangkau dengan klausul penjaga, maka status v sama dengan status v setelah klausul penjaga.
- Jika transfer kontrol disebabkan oleh label sakelar yang dapat dijangkau tanpa klausul penjaga, status v adalah
- Jika v adalah variabel pola yang dideklarasikan dalam switch_label: "pasti ditetapkan".
- Jika tidak, status v sama dengan statistik v setelah expr.
Konsekuensi dari aturan ini adalah bahwa variabel pola yang dideklarasikan dalam switch_label akan "tidak pasti ditetapkan" dalam pernyataan bagian pengalihannya jika bukan satu-satunya label sakelar yang dapat dijangkau di bagiannya.
Contoh:
public static double ComputeArea(object shape) { switch (shape) { case Square s when s.Side == 0: case Circle c when c.Radius == 0: case Triangle t when t.Base == 0 || t.Height == 0: case Rectangle r when r.Length == 0 || r.Height == 0: // none of s, c, t, or r is definitely assigned return 0; case Square s: // s is definitely assigned return s.Side * s.Side; case Circle c: // c is definitely assigned return c.Radius * c.Radius * Math.PI; … } }contoh akhir
9.4.4.8 Sementara pernyataan
Untuk pernyataan stmt formulir:
while ( «expr» ) «while_body»
- v memiliki status penetapan yang sama di awal expr seperti pada awal stmt.
- Jika v pasti ditetapkan di akhir expr, maka pasti ditetapkan pada transfer alur kontrol ke while_body dan ke titik akhir stmt.
- Jika v memiliki status "pasti ditetapkan setelah ekspresi benar" di akhir expr, maka pasti ditetapkan pada transfer alur kontrol ke while_body, tetapi tidak pasti ditetapkan di titik akhir stmt.
- Jika v memiliki status "pasti ditetapkan setelah ekspresi palsu" di akhir expr, maka pasti ditetapkan pada transfer alur kontrol ke titik akhir stmt, tetapi tidak pasti ditetapkan pada transfer alur kontrol ke while_body.
9.4.4.9 Pernyataan do
Untuk pernyataan stmt formulir:
do «do_body» while ( «expr» ) ;
- v memiliki status penetapan yang sama pada transfer alur kontrol dari awal stmt ke do_body seperti pada awal stmt.
- v memiliki status penetapan yang sama di awal expr seperti pada titik akhir do_body.
- Jika v pasti ditetapkan di akhir expr, maka pasti ditetapkan pada transfer alur kontrol ke titik akhir stmt.
- Jika v memiliki status "pasti ditetapkan setelah ekspresi palsu" di akhir expr, maka pasti ditetapkan pada transfer alur kontrol ke titik akhir stmt, tetapi tidak pasti ditetapkan pada transfer alur kontrol ke do_body.
9.4.4.10 Untuk pernyataan
Untuk pernyataan formulir:
for ( «for_initializer» ; «for_condition» ; «for_iterator» )
«embedded_statement»
pemeriksaan penetapan pasti dilakukan seolah-olah pernyataan ditulis:
{
«for_initializer» ;
while ( «for_condition» )
{
«embedded_statement» ;
LLoop: «for_iterator» ;
}
}
dengan continue pernyataan yang menargetkan pernyataan yang for diterjemahkan ke goto pernyataan yang menargetkan label LLoop.
Jika for_condition dihilangkan dari for pernyataan, maka evaluasi penugasan pasti berlangsung seolah-olah for_condition diganti dengan benar dalam ekspansi di atas.
9.4.4.11 Pernyataan break, continue, dan goto
Status penetapan pasti v pada transfer alur kontrol yang disebabkan oleh pernyataan , , breakatau continue sama dengan gotostatus penetapan v yang ditentukan di awal pernyataan.
9.4.4.12 Melempar pernyataan
Untuk pernyataan stmt formulir:
throw «expr» ;
status penetapan pasti v di awal expr sama dengan status penetapan pasti v di awal stmt.
9.4.4.13 Mengembalikan pernyataan
Untuk pernyataan stmt formulir:
return «expr» ;
- Status penetapan pasti v di awal expr sama dengan status penetapan pasti v di awal stmt.
- Jika v adalah parameter output, maka pasti akan ditetapkan:
- setelah expr
- atau di akhir
finallybloktry-finallyatautry-catch-finallyyang menutupireturnpernyataan.
Untuk pernyataan stmt formulir:
return ;
- Jika v adalah parameter output, maka pasti akan ditetapkan:
- sebelum stmt
- atau di akhir
finallybloktry-finallyatautry-catch-finallyyang menutupireturnpernyataan.
9.4.4.14 Pernyataan try-catch
Untuk pernyataan stmt formulir:
try «try_block»
catch ( ... ) «catch_block_1»
...
catch ( ... ) «catch_block_n»
- Status penetapan pasti v di awal try_block sama dengan status penetapan v yang ditentukan pada awal stmt.
- Status penetapan pasti v di awal catch_block_i (untuk i) sama dengan status penetapan v di awal stmt.
- Status penetapan pasti v pada titik akhir stmt pasti ditetapkan jika (dan hanya jika) v pasti ditetapkan pada titik akhir try_block dan setiap catch_block_i (untuk setiap i dari 1 hingga n).
9.4.4.15 Pernyataan try-finally
Untuk pernyataan stmt formulir:
try «try_block» finally «finally_block»
- Status penetapan pasti v di awal try_block sama dengan status penetapan v yang ditentukan pada awal stmt.
- Status penetapan pasti v di awal finally_block sama dengan status penetapan pasti v di awal stmt.
- Status penetapan pasti v di titik akhir stmt pasti ditetapkan jika (dan hanya jika) setidaknya salah satu hal berikut ini benar:
- v pasti ditetapkan pada titik akhir try_block
- v pasti ditetapkan di titik akhir finally_block
Jika transfer alur kontrol (seperti goto pernyataan) dibuat yang dimulai dalam try_block, dan berakhir di luar try_block, maka v juga dianggap pasti ditetapkan pada transfer alur kontrol tersebut jika v pasti ditetapkan di titik akhir finally_block. (Ini bukan hanya jika—jika v pasti ditetapkan karena alasan lain pada transfer alur kontrol ini, maka masih dianggap pasti ditetapkan.)
9.4.4.16 Pernyataan try-catch-finally
Untuk pernyataan formulir:
try «try_block»
catch ( ... ) «catch_block_1»
...
catch ( ... ) «catch_block_n»
finally «finally_block»
analisis penetapan pasti dilakukan seolah-olah pernyataan itu adalah try-finally pernyataan yang try-catch menyertakan pernyataan:
try
{
try «try_block»
catch ( ... ) «catch_block_1»
...
catch ( ... ) «catch_block_n»
}
finally «finally_block»
Contoh: Contoh berikut menunjukkan bagaimana blok pernyataan yang
tryberbeda (§13.11) memengaruhi penetapan yang pasti.class A { static void F() { int i, j; try { goto LABEL; // neither i nor j definitely assigned i = 1; // i definitely assigned } catch { // neither i nor j definitely assigned i = 3; // i definitely assigned } finally { // neither i nor j definitely assigned j = 5; // j definitely assigned } // i and j definitely assigned LABEL: ; // j definitely assigned } }contoh akhir
9.4.4.17 Pernyataan Foreach
Untuk pernyataan stmt formulir:
foreach ( «type» «identifier» in «expr» ) «embedded_statement»
- Status penetapan pasti v di awal expr sama dengan status v di awal stmt.
- Status penetapan pasti v pada transfer alur kontrol ke embedded_statement atau ke titik akhir stmt sama dengan status v di akhir expr.
9.4.4.18 Menggunakan pernyataan
Untuk pernyataan stmt formulir:
using ( «resource_acquisition» ) «embedded_statement»
- Status penetapan pasti v di awal resource_acquisition sama dengan status v di awal stmt.
- Status penetapan pasti v pada transfer alur kontrol ke embedded_statement sama dengan status v di akhir resource_acquisition.
9.4.4.19 Pernyataan kunci
Untuk pernyataan stmt formulir:
lock ( «expr» ) «embedded_statement»
- Status penetapan pasti v di awal expr sama dengan status v di awal stmt.
- Status penetapan pasti v pada transfer alur kontrol ke embedded_statement sama dengan status v di akhir expr.
9.4.4.20 Pernyataan hasil
Untuk pernyataan stmt formulir:
yield return «expr» ;
- Status penetapan pasti v di awal expr sama dengan status v di awal stmt.
- Status penetapan pasti v di akhir stmt sama dengan status v di akhir expr.
Pernyataan yield break tidak berpengaruh pada status penetapan yang pasti.
9.4.4.21 Aturan umum untuk ekspresi konstanta
Pernyataan berikut berlaku untuk setiap ekspresi konstanta dan memiliki prioritas lebih tinggi dibandingkan aturan dari subklausa berikut yang mungkin berlaku:
Untuk ekspresi konstanta dengan nilai true:
- Jika v pasti ditetapkan sebelum ekspresi, maka v pasti ditetapkan setelah ekspresi.
- Jika tidak , v "pasti ditetapkan setelah ekspresi palsu" setelah ekspresi.
Contoh:
int x; if (true) {} else { Console.WriteLine(x); }contoh akhir
Untuk ekspresi konstanta dengan nilai false:
- Jika v pasti ditetapkan sebelum ekspresi, maka v pasti ditetapkan setelah ekspresi.
- Jika tidak , v "pasti ditetapkan setelah ekspresi benar" setelah ekspresi.
Contoh:
int x; if (false) { Console.WriteLine(x); }contoh akhir
Untuk semua ekspresi konstanta lainnya, status penetapan v yang ditentukan setelah ekspresi sama dengan status penetapan v sebelum ekspresi.
9.4.4.22 Aturan umum untuk ekspresi sederhana
Aturan berikut berlaku untuk jenis ekspresi ini: literal (§12.8.2), nama sederhana (§12.8.4), ekspresi akses anggota (§12.8.7), ekspresi akses dasar yang tidak diindeks (§12.8.15), typeof ekspresi (§12.8.18), ekspresi nilai default (§12.8.21), nameof ekspresi (§12.8.23), dan ekspresi deklarasi (§12,19).
- Status penetapan-pasti v di akhir ekspresi tersebut sama dengan status penetapan-pasti v di awal ekspresi.
9.4.4.23 Aturan umum untuk ekspresi dengan ekspresi yang disematkan
Aturan berikut berlaku untuk jenis ekspresi ini: ekspresi yang dikurung (§12.8.5), ekspresi tuple (§12.8.6), ekspresi akses elemen (§12.8.12), ekspresi akses dasar dengan pengindeksan (§12.8.12), ekspresi akses dasar dengan pengindeksan (§12.8.12), ekspresi akses dasar dengan pengindeksan (§12.8.12), ekspresi akses dasar dengan pengindeksan (§12.8.12), ekspresi akses dasar dengan pengindeksan (§12.8.12), ekspresi akses dasar dengan pengindeksan (§12.8.12), ekspresi akses dasar dengan pengindeksan (§12.8.12), ekspresi akses dasar dengan penginde 12.8.15), ekspresi kenaikan dan penurunan (§12.8.16, §12.9.7), ekspresi transmisi (§12.9.8), unary +, -, ~, * ekspresi, biner +, -, *, /, %, <<, >>, <, <=, , >, >=, , ==, !=, asis, &, |, ^ ekspresi (§12.12, §12.13, §12.14, §12.15), ekspresi penetapan gabungan (§12.23.4), checked dan unchecked ekspresi (§12.8.20), ekspresi pembuatan array dan delegasi (§12.8.17), dan await ekspresi (§12.9.9).
Masing-masing ekspresi ini memiliki satu atau beberapa subekspresi yang dievaluasi tanpa syarat dalam urutan tetap.
Contoh: Operator biner
%mengevaluasi sisi kiri operator, lalu sisi kanan. Operasi pengindeksan mengevaluasi ekspresi terindeks, lalu mengevaluasi setiap ekspresi indeks, secara berurutan dari kiri ke kanan. contoh akhir
Untuk expr ekspresi, yang memiliki subekspresi expr₁, expr₂, ..., exprₓ, dievaluasi dalam urutan tersebut:
- Status penetapan pasti v pada awal expr₁ sama dengan status penetapan yang ditentukan pada awal expr.
- Status penetapan pasti v pada awal expri (saya lebih besar dari satu) sama dengan status penetapan yang ditentukan pada akhir expri₋₁.
- Status penetapan pasti v di akhir expr sama dengan status penetapan pasti di akhir exprₓ.
9.4.4.24 Ekspresi pemanggilan dan ekspresi pembuatan objek
Jika metode yang akan dipanggil adalah metode parsial yang tidak memiliki deklarasi metode parsial, atau merupakan metode bersyarat yang panggilannya dihilangkan (§23.5.3.2), maka status penugasan pasti v setelah pemanggilan sama dengan status penetapan pasti v sebelum pemanggilan. Jika tidak, aturan berikut berlaku:
Untuk ekspresi pemanggilan expr formulir:
«primary_expression» ( «arg₁», «arg₂», … , «argₓ» )
atau ekspresi pembuatan objek kedaluwarsa formulir:
new «type» ( «arg₁», «arg₂», … , «argₓ» )
- Untuk ekspresi pemanggilan, status penetapan v yang pasti sebelum primary_expression sama dengan status v sebelum expr.
- Untuk ekspresi pemanggilan, status penugasan pasti v sebelum arg₁ sama dengan status v setelah primary_expression.
- Untuk ekspresi pembuatan objek, status penetapan v sebelum arg₁ sama dengan status v sebelum expr.
- Untuk setiap argi argumen
- Untuk setiap argi argumen untuk setiap yang lebih besar dari satu, status penugasan pasti v sebelum argi sama dengan status v setelah argi₋₁.
- Jika variabel v diteruskan sebagai
outargumen (yaitu, argumen formulir "out v") dalam salah satu argumen, maka status v setelah expr pasti ditetapkan. Jika tidak, status v setelah expr sama dengan status v setelah argₓ. - Untuk penginisialisasi array (§12.8.17.4), penginisialisasi objek (§12.8.17.2.2), penginisialisasi koleksi (§12.8.17.2.3) dan penginisialisasi objek anonim (§12.8.17.3), status penetapan pasti ditentukan oleh perluasan yang menjadi dasar penentuan konstruksi ini.
9.4.4.25 Ekspresi penetapan sederhana
Biarkan kumpulan target penugasan dalam ekspresi e didefinisikan sebagai berikut:
- Jika e adalah ekspresi tuple, maka target penugasan dalam e adalah penyatuan target penugasan dari elemen e.
- Jika tidak, target penugasan dalam e adalah e.
Untuk ekspresi kedaluwarsa formulir:
«expr_lhs» = «expr_rhs»
- Status penetapan pasti v sebelum expr_lhs sama dengan status penetapan pasti v sebelum expr.
- Status penetapan pasti v sebelum expr_rhs sama dengan status penetapan v yang pasti setelah expr_lhs.
- Jika v adalah target penugasan expr_lhs, maka status penugasan pasti v setelah expr pasti ditetapkan. Jika tidak, jika penugasan terjadi dalam konstruktor instans dari jenis struct, dan v adalah bidang pencadangan tersembunyi dari properti yang diimplementasikan secara otomatis P pada instans yang sedang dibangun, dan akses properti yang menunjuk P adalah target penugasan expr_lhs, maka status penugasan pasti v setelah expr pasti ditetapkan. Jika tidak, status penetapan pasti v setelah expr sama dengan status penetapan v yang pasti setelah expr_rhs.
Contoh: Dalam kode berikut
class A { static void F(int[] arr) { int x; arr[x = 1] = x; // ok } }variabel
xdianggap pasti ditetapkan setelaharr[x = 1]dievaluasi sebagai sisi kiri penetapan sederhana kedua.contoh akhir
9.4.4.26 & ekspresi
Untuk ekspresi kedaluwarsa formulir:
«expr_first» && «expr_second»
- Status penetapan pasti v sebelum expr_first sama dengan status penetapan yang ditentukan v sebelum expr.
- Status penetapan pasti v sebelum expr_second pasti ditetapkan jika dan hanya jika status v setelah expr_first pasti ditetapkan atau "pasti ditetapkan setelah ekspresi benar". Jika tidak, itu tidak pasti ditetapkan.
- Status penetapan pasti v setelah expr ditentukan oleh:
- Jika status v setelah expr_first pasti ditetapkan, maka status v setelah expr pasti ditetapkan.
- Jika tidak, jika status v setelah expr_second pasti ditetapkan, dan status v setelah expr_first "pasti ditetapkan setelah ekspresi palsu", maka status v setelah expr pasti ditetapkan.
- Jika tidak, jika status v setelah expr_second pasti ditetapkan atau "pasti ditetapkan setelah ekspresi benar", maka status v setelah expr "pasti ditetapkan setelah ekspresi benar".
- Jika tidak, jika status v setelah expr_first "pasti ditetapkan setelah ekspresi palsu", dan status v setelah expr_second "pasti ditetapkan setelah ekspresi palsu", maka status v setelah expr "pasti ditetapkan setelah ekspresi palsu".
- Jika tidak, status v setelah expr tidak pasti ditetapkan.
Contoh: Dalam kode berikut
class A { static void F(int x, int y) { int i; if (x >= 0 && (i = y) >= 0) { // i definitely assigned } else { // i not definitely assigned } // i not definitely assigned } }variabel
idianggap pasti ditetapkan dalam salah satu pernyataan pernyataan yangifdisematkan tetapi tidak di yang lain.ifDalam pernyataan dalam metodeF, variabelipasti ditetapkan dalam pernyataan pertama yang disematkan karena eksekusi ekspresi(i = y)selalu mendahului eksekusi pernyataan yang disematkan ini. Sebaliknya, variabelitidak pasti ditetapkan dalam pernyataan tertanam kedua,x >= 0karena mungkin telah menguji false, yang mengakibatkan variabelitidak ditetapkan.contoh akhir
9.4.4.27 || Ekspresi
Untuk ekspresi kedaluwarsa formulir:
«expr_first» || «expr_second»
- Status penetapan pasti v sebelum expr_first sama dengan status penetapan yang ditentukan v sebelum expr.
- Status penetapan pasti v sebelum expr_second pasti ditetapkan jika dan hanya jika status v setelah expr_first pasti ditetapkan atau "pasti ditetapkan setelah ekspresi palsu". Jika tidak, itu tidak pasti ditetapkan.
- Pernyataan penetapan pasti v setelah expr ditentukan oleh:
- Jika status v setelah expr_first pasti ditetapkan, maka status v setelah expr pasti ditetapkan.
- Jika tidak, jika status v setelah expr_second pasti ditetapkan, dan status v setelah expr_first "pasti ditetapkan setelah ekspresi benar", maka status v setelah expr pasti ditetapkan.
- Jika tidak, jika status v setelah expr_second pasti ditetapkan atau "pasti ditetapkan setelah ekspresi palsu", maka status v setelah expr "pasti ditetapkan setelah ekspresi palsu".
- Jika tidak, jika status v setelah expr_first "pasti ditetapkan setelah ekspresi benar", dan status v setelah expr_ detik "pasti ditetapkan setelah ekspresi benar", maka status v setelah expr "pasti ditetapkan setelah ekspresi benar".
- Jika tidak, status v setelah expr tidak pasti ditetapkan.
Contoh: Dalam kode berikut
class A { static void G(int x, int y) { int i; if (x >= 0 || (i = y) >= 0) { // i not definitely assigned } else { // i definitely assigned } // i not definitely assigned } }variabel
idianggap pasti ditetapkan dalam salah satu pernyataan pernyataan yangifdisematkan tetapi tidak di yang lain.ifDalam pernyataan dalam metodeG, variabelipasti ditetapkan dalam pernyataan tersemat kedua karena eksekusi ekspresi(i = y)selalu mendahului eksekusi pernyataan yang disematkan ini. Sebaliknya, variabelitidak pasti ditetapkan dalam pernyataan pertama yang disematkan, karenax >= 0mungkin telah menguji true, yang mengakibatkan variabelitidak ditetapkan.contoh akhir
9.4.4.28 ! ekspresi
Untuk ekspresi kedaluwarsa formulir:
! «expr_operand»
- Status penetapan pasti v sebelum expr_operand sama dengan status penetapan v sebelum expr.
- Status penetapan pasti v setelah expr ditentukan oleh:
- Jika status
vsetelah expr_operand pasti ditetapkan, maka statusvsetelah expr pasti ditetapkan. - Jika tidak, jika status
vsetelah expr_operand "pasti ditetapkan setelah ekspresi palsu", maka statusvsetelah expr "pasti ditetapkan setelah ekspresi benar". - Jika tidak, jika status
vsetelah expr_operand "pasti ditetapkan setelah ekspresi benar", maka status v setelah expr "pasti ditetapkan setelah ekspresi palsu". - Jika tidak, status
vsetelah expr tidak pasti ditetapkan.
- Jika status
9.4.4.29 ?? ekspresi
Untuk ekspresi kedaluwarsa formulir:
«expr_first» ?? «expr_second»
- Status penetapan pasti v sebelum expr_first sama dengan status penetapan yang ditentukan v sebelum expr.
- Status penetapan pasti v sebelum expr_second sama dengan status penetapan v yang pasti setelah expr_first.
- Pernyataan penetapan pasti v setelah expr ditentukan oleh:
- Jika expr_first adalah ekspresi konstanta (§12,25) dengan nilai
null, maka status v setelah expr sama dengan status v setelah expr_second. - Jika tidak, status v setelah expr sama dengan status penetapan v yang ditentukan setelah expr_first.
- Jika expr_first adalah ekspresi konstanta (§12,25) dengan nilai
9.4.4.30 ?: ekspresi
Untuk ekspresi kedaluwarsa formulir:
«expr_cond» ? «expr_true» : «expr_false»
- Status penetapan pasti v sebelum expr_cond sama dengan status v sebelum expr.
- Status penetapan pasti v sebelum expr_true pasti ditetapkan jika status v setelah expr_cond pasti ditetapkan atau "pasti ditetapkan setelah ekspresi benar".
- Status penetapan pasti v sebelum expr_false pasti ditetapkan jika status v setelah expr_cond pasti ditetapkan atau "pasti ditetapkan setelah ekspresi palsu".
- Status penetapan pasti v setelah expr ditentukan oleh:
- Jika expr_cond adalah ekspresi konstanta (§12,25) dengan nilai
truemaka status v setelah expr sama dengan status v setelah expr_true. - Jika tidak, jika expr_cond adalah ekspresi konstanta (§12,25) dengan nilai
falsemaka status v setelah expr sama dengan status v setelah expr_false. - Jika tidak, jika status v setelah expr_true pasti ditetapkan dan status v setelah expr_false pasti ditetapkan, maka status v setelah expr pasti ditetapkan.
- Jika tidak, status v setelah expr tidak pasti ditetapkan.
- Jika expr_cond adalah ekspresi konstanta (§12,25) dengan nilai
9.4.4.31 Fungsi anonim
Untuk lambda_expression atau anonymous_method_expression expr dengan isi (blokatau ekspresi):
- Status penetapan pasti parameter sama dengan untuk parameter metode bernama (§9.2.6, §9.2.7, §9.2.8).
- Status penetapan pasti dari variabel luar v sebelum isi sama dengan status v sebelum expr. Artinya, status penetapan pasti variabel luar diwarisi dari konteks fungsi anonim.
- Status penetapan pasti dari variabel luar v setelah expr sama dengan status v sebelum expr.
Contoh: Contoh
class A { delegate bool Filter(int i); void F() { int max; // Error, max is not definitely assigned Filter f = (int n) => n < max; max = 5; DoWork(f); } void DoWork(Filter f) { ... } }menghasilkan kesalahan waktu kompilasi karena maks tidak pasti ditetapkan di mana fungsi anonim dideklarasikan.
contoh akhir
Contoh: Contoh
class A { delegate void D(); void F() { int n; D d = () => { n = 1; }; d(); // Error, n is not definitely assigned Console.WriteLine(n); } }juga menghasilkan kesalahan waktu kompilasi karena penugasan ke
ndalam fungsi anonim tidak memengaruhi statusnpenetapan pasti di luar fungsi anonim.contoh akhir
9.4.4.32 Lempar ekspresi
Untuk ekspresi kedaluwarsa formulir:
throw
thrown_expr
- Status penetapan pasti v sebelum thrown_expr sama dengan status v sebelum expr.
- Status penetapan v yang pasti setelah expr "pasti ditetapkan".
9.4.4.33 Aturan untuk variabel dalam fungsi lokal
Fungsi lokal dianalisis dalam konteks metode induknya. Ada dua jalur alur kontrol yang penting untuk fungsi lokal: panggilan fungsi dan konversi delegasi.
Penetapan pasti untuk isi setiap fungsi lokal didefinisikan secara terpisah untuk setiap situs panggilan. Pada setiap pemanggilan, variabel yang diambil oleh fungsi lokal dianggap pasti ditetapkan jika mereka pasti ditetapkan pada titik panggilan. Jalur alur kontrol juga ada ke isi fungsi lokal pada titik ini dan dianggap dapat dijangkau. Setelah panggilan ke fungsi lokal, variabel yang ditangkap yang pasti ditetapkan di setiap titik kontrol yang meninggalkan fungsi (return pernyataan, yield pernyataan, await ekspresi) dianggap pasti ditetapkan setelah lokasi panggilan.
Mendelegasikan konversi memiliki jalur alur kontrol ke isi fungsi lokal. Variabel yang diambil pasti ditetapkan untuk isi jika pasti ditetapkan sebelum konversi. Variabel yang ditetapkan oleh fungsi lokal tidak dianggap ditetapkan setelah konversi.
Catatan: hal di atas menyiratkan bahwa isi dianalisis kembali untuk penugasan pasti di setiap pemanggilan fungsi lokal atau mendelegasikan konversi. Pengkompilasi tidak diperlukan untuk menganalisis ulang isi fungsi lokal pada setiap pemanggilan atau mendelegasikan konversi. Implementasi harus menghasilkan hasil yang setara dengan deskripsi tersebut. catatan akhir
Contoh: Contoh berikut menunjukkan penetapan pasti untuk variabel yang diambil dalam fungsi lokal. Jika fungsi lokal membaca variabel yang diambil sebelum menulisnya, variabel yang ditangkap harus benar-benar ditetapkan sebelum memanggil fungsi lokal. Fungsi
F1lokal membacastanpa menetapkannya. Ini adalah kesalahan jikaF1dipanggil sebelumnyaspasti ditetapkan.F2imenetapkan sebelum membacanya. Ini mungkin dipanggil sebelumnyaipasti ditetapkan. Selain itu,F3dapat dipanggil setelahF2karenas2pasti ditetapkan dalamF2.void M() { string s; int i; string s2; // Error: Use of unassigned local variable s: F1(); // OK, F2 assigns i before reading it. F2(); // OK, i is definitely assigned in the body of F2: s = i.ToString(); // OK. s is now definitely assigned. F1(); // OK, F3 reads s2, which is definitely assigned in F2. F3(); void F1() { Console.WriteLine(s); } void F2() { i = 5; // OK. i is definitely assigned. Console.WriteLine(i); s2 = i.ToString(); } void F3() { Console.WriteLine(s2); } }contoh akhir
9.4.4.34 ekspresi is-pattern
Untuk ekspresi kedaluwarsa formulir:
expr_operand adalah pola
- Status penetapan pasti v sebelum expr_operand sama dengan status penetapan v sebelum expr.
- Jika variabel 'v' dideklarasikan dalam pola, maka status penugasan pasti 'v' setelah expr "pasti ditetapkan ketika benar".
- Jika tidak, status penetapan pasti 'v' setelah expr sama dengan status penetapan pasti 'v' setelah expr_operand.
9.5 Referensi variabel
variable_reference adalah ekspresi yang diklasifikasikan sebagai variabel. variable_reference menunjukkan lokasi penyimpanan yang dapat diakses baik untuk mengambil nilai saat ini maupun untuk menyimpan nilai baru.
variable_reference
: expression
;
Catatan: Di C dan C++, variable_reference dikenal sebagai lvalue. catatan akhir
9.6 Atomitas referensi variabel
Membaca dan menulis jenis data berikut harus atom: bool, , char, byte, sbyte, shortushort, uint, int, , float, dan jenis referensi. Selain itu, membaca dan menulis jenis enum dengan jenis yang mendasar dalam daftar sebelumnya juga harus atomik. Membaca dan menulis jenis lain, termasuk long, , ulong, doubledan decimal, serta jenis yang ditentukan pengguna, tidak perlu atomik. Selain fungsi pustaka yang dirancang untuk tujuan tersebut, tidak ada jaminan baca-ubah-tulis atomik, seperti dalam kasus kenaikan atau penurunan.
9.7 Variabel referensi dan pengembalian
9.7.1 Umum
Variabel referensi adalah variabel yang mengacu pada variabel lain, yang disebut referensi (§9.2.6). Variabel referensi adalah variabel lokal yang dideklarasikan dengan pengubah ref .
Variabel referensi menyimpan variable_reference (§9,5) ke referensinya dan bukan nilai referensinya. Ketika variabel referensi digunakan di mana nilai diperlukan nilai referensinya dikembalikan; demikian pula ketika variabel referensi adalah target penugasan, variabel tersebut adalah referensi yang ditetapkan. Variabel yang dirujuk variabel referensi, yaitu variable_reference yang disimpan
Contoh: Contoh berikut menunjukkan variabel referensi lokal yang referensinya adalah elemen array:
public class C { public void M() { int[] arr = new int[10]; // element is a reference variable that refers to arr[5] ref int element = ref arr[5]; element += 5; // arr[5] has been incremented by 5 } }contoh akhir
Pengembalian referensi adalah variable_reference yang dikembalikan dari metode returns-by-ref (§15.6.1). variable_reference ini adalah referensi dari pengembalian referensi.
Contoh: Contoh berikut menunjukkan pengembalian referensi yang referensinya adalah elemen bidang array:
public class C { private int[] arr = new int[10]; public ref readonly int M() { // element is a reference variable that refers to arr[5] ref int element = ref arr[5]; return ref element; // return reference to arr[5]; } }contoh akhir
9.7.2 Konteks aman Ref
9.7.2.1 Umum
Semua variabel referensi mematuhi aturan keamanan yang memastikan konteks ref-safe dari variabel referensi tidak lebih besar dari konteks ref-safe-referen-nya.
Catatan: Gagasan terkait tentang konteks aman ditentukan dalam (§16.4.15), bersama dengan batasan terkait. catatan akhir
Untuk variabel apa pun, konteks ref-safe dari variabel tersebut adalah konteks di mana variable_reference (§9,5) ke variabel tersebut valid. Referensi variabel referensi harus memiliki konteks ref-safe yang setidaknya seluas konteks ref-safe dari variabel referensi itu sendiri.
Note: Pengkompilasi menentukan konteks ref-safe melalui analisis statis teks program. Konteks ref-safe mencerminkan masa pakai variabel pada runtime. catatan akhir
Ada tiga konteks ref-safe:
: Konteks ref-safe darideklarasi-blok variable_reference ke variabel lokal (§9.2.9.1 ) adalah cakupan variabel lokal tersebut (§13,6,2 ), termasukpernyataan tersematberlapis dalam cakupan tersebut. Variable_reference ke variabel lokal adalah referensi yang valid untuk variabel referensi hanya jika variabel referensi dideklarasikan dalam konteks ref-safe dari variabel tersebut.
anggota fungsi: Dalam fungsi variable_reference ke salah satu hal berikut ini memiliki konteks ref-safe-function-member:
- Parameter nilai (§15.6.2.2) pada deklarasi anggota fungsi, termasuk implisit
thisfungsi anggota kelas; dan - Parameter referensi implisit (
ref) (§15.6.2.3.3)thisdari fungsi anggota struct, bersama dengan bidangnya.
variable_reference dengan ref-safe-context of function-member adalah referensi yang valid hanya jika variabel referensi dideklarasikan dalam anggota fungsi yang sama.
- Parameter nilai (§15.6.2.2) pada deklarasi anggota fungsi, termasuk implisit
caller-context: Dalam fungsi variable_reference ke salah satu hal berikut ini memiliki konteks ref-safe-caller-context:
- Parameter referensi (§9.2.6) selain implisit
thisdari fungsi anggota struct; - Bidang anggota dan elemen parameter tersebut;
- Bidang anggota parameter jenis kelas; dan
- Elemen parameter jenis array.
- Parameter referensi (§9.2.6) selain implisit
Variable_reference dengan konteks konteks pemanggil yang aman-ref dapat menjadi referensi pengembalian referensi.
Nilai-nilai ini membentuk hubungan berlapis dari tersempit (deklarasi-blok) ke terluas (caller-context). Setiap blok berlapis mewakili konteks yang berbeda.
Contoh: Kode berikut menunjukkan contoh konteks ref-safe yang berbeda. Deklarasi menunjukkan konteks ref-safe untuk referensi menjadi ekspresi inisialisasi untuk
refvariabel. Contoh menunjukkan konteks ref-safe untuk pengembalian referensi:public class C { // ref safe context of arr is "caller-context". // ref safe context of arr[i] is "caller-context". private int[] arr = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; // ref safe context is "caller-context" public ref int M1(ref int r1) { return ref r1; // r1 is safe to ref return } // ref safe context is "function-member" public ref int M2(int v1) { return ref v1; // error: v1 isn't safe to ref return } public ref int M3() { int v2 = 5; return ref arr[v2]; // arr[v2] is safe to ref return } public void M4(int p) { int v3 = 6; // context of r2 is declaration-block, // ref safe context of p is function-member ref int r2 = ref p; // context of r3 is declaration-block, // ref safe context of v3 is declaration-block ref int r3 = ref v3; // context of r4 is declaration-block, // ref safe context of arr[v3] is caller-context ref int r4 = ref arr[v3]; } }contoh akhir.
Contoh: Untuk
structjenis, parameter implisitthisditeruskan sebagai parameter referensi. Konteks ref-safe dari bidang jenisstructsebagai anggota fungsi mencegah mengembalikan bidang tersebut berdasarkan pengembalian referensi. Aturan ini mencegah kode berikut:public struct S { private int n; // Disallowed: returning ref of a field. public ref int GetN() => ref n; } class Test { public ref int M() { S s = new S(); ref int numRef = ref s.GetN(); return ref numRef; // reference to local variable 'numRef' returned } }contoh akhir.
9.7.2.2 Konteks aman ref variabel lokal
Untuk variabel vlokal :
- Jika
vmerupakan variabel referensi, konteks ref-safe-nya sama dengan konteks ref-safe dari ekspresi inisialisasinya. - Jika tidak, konteks ref-safe-nya adalah blok deklarasi.
9.7.2.3 Konteks aman parameter ref
Untuk parameter p:
- Jika
pmerupakan parameter referensi atau input, konteks ref-safe-nya adalah konteks pemanggil. Jikapmerupakan parameter input, parameter tersebut tidak dapat dikembalikan sebagai dapat ditulisreftetapi dapat dikembalikan sebagairef readonly. - Jika
padalah parameter output, konteks ref-safe-nya adalah konteks pemanggil. - Jika tidak, jika
padalahthisparameter jenis struct, konteks ref-safe-nya adalah anggota fungsi. - Jika tidak, parameter adalah parameter nilai, dan konteks ref-safe-nya adalah anggota fungsi.
9.7.2.4 Konteks aman ref bidang
Untuk variabel yang menunjuk referensi ke bidang, e.F:
- Jika
eberjenis referensi, konteks ref-safe-nya adalah konteks pemanggil. - Jika tidak, jika
edari jenis nilai, konteks ref-safe-nya sama dengan konteks ref-safe-context .e
9.7.2.5 Operator
Operator bersyarkat (§12.20), c ? ref e1 : ref e2, dan operator penetapan referensi, = ref e (§12.23.1) memiliki variabel referensi sebagai operand dan menghasilkan variabel referensi. Bagi operator tersebut, konteks ref-safe dari hasil adalah konteks tersempit di antara konteks ref-safe dari semua ref operand.
9.7.2.6 Pemanggilan fungsi
Untuk variabel c yang dihasilkan dari pemanggilan fungsi pengembalian ref, konteks ref-safe-nya adalah yang tersempit dari konteks berikut:
- Konteks pemanggil.
- Konteks ref-safe dari semua
refekspresi argumen , ,outdanin(tidak termasuk penerima). - Untuk setiap parameter input, jika ada ekspresi yang sesuai yang merupakan variabel dan ada konversi identitas antara jenis variabel dan jenis parameter, konteks ref-safe-context variabel, jika tidak, konteks penutup terdekat.
- Konteks aman (§16.4.15) dari semua ekspresi argumen (termasuk penerima).
Contoh: poin terakhir diperlukan untuk menangani kode seperti
ref int M2() { int v = 5; // Not valid. // ref safe context of "v" is block. // Therefore, ref safe context of the return value of M() is block. return ref M(ref v); } ref int M(ref int p) { return ref p; }contoh akhir
Pemanggilan properti dan pemanggilan pengindeks (baik get atau set) diperlakukan sebagai pemanggilan fungsi aksesor yang mendasar oleh aturan di atas. Pemanggilan fungsi lokal adalah pemanggilan fungsi.
9.7.2.7 Nilai
Konteks ref-safe-value adalah konteks penutup terdekat.
Catatan: Ini terjadi dalam pemanggilan seperti
M(ref d.Length)di manadberjenisdynamic. Ini juga konsisten dengan argumen yang sesuai dengan parameter input. catatan akhir
9.7.2.8 Pemanggilan konstruktor
Ekspresi new yang memanggil konstruktor mematuhi aturan yang sama dengan pemanggilan metode (§9.7.2.6) yang dianggap mengembalikan jenis yang sedang dibangun.
9.7.2.9 Batasan pada variabel referensi
- Baik parameter referensi, maupun parameter output, atau parameter input, atau
reflokal, atau parameter atau lokal dariref structjenis harus ditangkap oleh ekspresi lambda atau fungsi lokal. - Baik parameter referensi, maupun parameter output, atau parameter input, atau parameter jenis
ref structtidak akan menjadi argumen untuk metode iterator atauasyncmetode. -
refBaik lokal, maupun lokal dari jenisref structharus dalam konteks pada titikyield returnpernyataan atauawaitekspresi. - Untuk penugasan
e1 = ref e2ulang ref, kontekse2ref-safe-dari harus setidaknya seluas konteks sebagai ref-safe-context .e1 - Untuk pernyataan
return ref e1pengembalian ref , kontekse1ref-safe-harus menjadi konteks pemanggil.
ECMA C# draft specification