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.
13.1 Umum
C# menyediakan berbagai pernyataan.
Catatan: Sebagian besar pernyataan ini akan akrab bagi pengembang yang telah diprogram di C dan C++. catatan akhir
statement
: labeled_statement
| declaration_statement
| embedded_statement
;
embedded_statement
: block
| empty_statement
| expression_statement
| selection_statement
| iteration_statement
| jump_statement
| try_statement
| checked_statement
| unchecked_statement
| lock_statement
| using_statement
| yield_statement
| unsafe_statement // unsafe code support
| fixed_statement // unsafe code support
;
unsafe_statement (§24.2) dan fixed_statement (§24.7) hanya tersedia dalam kode yang tidak aman (§24).
Nonterminal embedded_statement digunakan untuk pernyataan yang muncul dalam pernyataan lain. Penggunaan embedded_statement daripada pernyataan mengecualikan penggunaan pernyataan deklarasi dan pernyataan berlabel dalam konteks ini.
Contoh: Kode
void F(bool b) { if (b) int i = 44; }menghasilkan kesalahan waktu kompilasi karena
ifpernyataan memerlukan embedded_statement daripada pernyataan untuk cabangnyaif. Jika kode ini diizinkan, maka variabeliakan dideklarasikan, tetapi tidak pernah dapat digunakan. Namun, perhatikan bahwa dengan menempatkanideklarasi dalam blok, contohnya valid.contoh akhir
13.2 Titik akhir dan keterjangkauan
Setiap pernyataan memiliki titik akhir. Dalam istilah intuitif, titik akhir pernyataan adalah lokasi yang segera mengikuti pernyataan. Aturan eksekusi untuk pernyataan komposit (pernyataan yang berisi pernyataan yang disematkan) menentukan tindakan yang diambil saat kontrol mencapai titik akhir pernyataan yang disematkan.
Contoh: Ketika kontrol mencapai titik akhir pernyataan dalam blok, kontrol ditransfer ke pernyataan berikutnya di blok. contoh akhir
Jika pernyataan mungkin dapat dicapai dengan eksekusi, pernyataan tersebut dikatakan dapat dijangkau. Sebaliknya, jika tidak ada kemungkinan bahwa pernyataan akan dijalankan, pernyataan tersebut dikatakan tidak dapat dijangkau.
Contoh: Dalam kode berikut
void F() { Console.WriteLine("reachable"); goto Label; Console.WriteLine("unreachable"); Label: Console.WriteLine("reachable"); }pemanggilan konsol.WriteLine kedua tidak dapat dijangkau karena tidak ada kemungkinan bahwa pernyataan akan dijalankan.
contoh akhir
Peringatan dilaporkan jika pernyataan selain throw_statement, blokir, atau empty_statement tidak dapat dijangkau. Ini secara khusus bukan kesalahan agar pernyataan tidak dapat dijangkau.
Catatan: Untuk menentukan apakah pernyataan atau titik akhir tertentu dapat dijangkau, pengkompilasi melakukan analisis alur sesuai dengan aturan keterjangkauan yang ditentukan untuk setiap pernyataan. Analisis alur memperhitungkan nilai ekspresi konstanta (§12,25) yang mengontrol perilaku pernyataan, tetapi kemungkinan nilai ekspresi non-konstan tidak dipertimbangkan. Dengan kata lain, untuk tujuan analisis alur kontrol, ekspresi non-konstan dari jenis tertentu dianggap memiliki nilai yang mungkin dari jenis tersebut.
Dalam contoh
void F() { const int i = 1; if (i == 2) Console.WriteLine("unreachable"); }ekspresi Boolean dari
ifpernyataan adalah ekspresi konstan==karena kedua operan operator adalah konstanta. Karena ekspresi konstan dievaluasi pada waktu kompilasi, menghasilkan nilaifalse,Console.WriteLinepemanggilan dianggap tidak dapat dijangkau. Namun, jikaidiubah menjadi variabel lokalvoid F() { int i = 1; if (i == 2) Console.WriteLine("reachable"); }pemanggilan
Console.WriteLinedianggap dapat dijangkau, meskipun, pada kenyataannya, itu tidak akan pernah dijalankan.catatan akhir
Blok anggota fungsi atau fungsi anonim selalu dianggap dapat dijangkau. Dengan secara berturut-turut mengevaluasi aturan keterjangkauan setiap pernyataan dalam blok, keterjangkauan pernyataan tertentu dapat ditentukan.
Contoh: Dalam kode berikut
void F(int x) { Console.WriteLine("start"); if (x < 0) Console.WriteLine("negative"); }keterjangkauan yang kedua
Console.WriteLineditentukan sebagai berikut:
- Pernyataan ekspresi pertama
Console.WriteLinedapat dijangkau karena blokFmetode dapat dijangkau (§13.3).- Titik akhir pernyataan ekspresi pertama
Console.WriteLinedapat dijangkau karena pernyataan tersebut dapat dijangkau (§13,7 dan §13,3).- Pernyataan
ifdapat dijangkau karena titik akhir pernyataan ekspresi pertamaConsole.WriteLinedapat dijangkau (§13,7 dan §13,3).- Pernyataan ekspresi kedua
Console.WriteLinedapat dijangkau karena ekspresi Boolean dariifpernyataan tidak memiliki nilaifalsekonstanta .contoh akhir
Ada dua situasi di mana itu adalah kesalahan waktu kompilasi agar titik akhir pernyataan dapat dijangkau:
switchKarena pernyataan tidak mengizinkan bagian pengalihan untuk "jatuh melalui" ke bagian sakelar berikutnya, itu adalah kesalahan waktu kompilasi untuk titik akhir daftar pernyataan bagian sakelar agar dapat dijangkau. Jika kesalahan ini terjadi, biasanya merupakan indikasi bahwabreakpernyataan hilang.Ini adalah kesalahan waktu kompilasi untuk titik akhir blok anggota fungsi atau fungsi anonim yang menghitung nilai yang dapat dijangkau. Jika kesalahan ini terjadi, biasanya merupakan indikasi bahwa
returnpernyataan hilang (§13.10.5).
13.3 Blok
13.3.1 Umum
Blok mengizinkan beberapa pernyataan ditulis dalam konteks di mana satu pernyataan diizinkan.
block
: '{' statement_list? '}'
;
Blok terdiri dari statement_list opsional (§13.3.2), diapit kurung kurawal. Jika daftar pernyataan dihilangkan, blok tersebut dikatakan kosong.
Blok mungkin berisi pernyataan deklarasi (§13.6). Cakupan variabel lokal atau konstanta yang dideklarasikan dalam blok adalah blok .
Blok dijalankan sebagai berikut:
- Jika blok kosong, kontrol ditransfer ke titik akhir blok.
- Jika blok tidak kosong, kontrol akan ditransfer ke daftar pernyataan. Kapan dan jika kontrol mencapai titik akhir daftar pernyataan, kontrol ditransfer ke titik akhir blok.
Daftar pernyataan blok dapat dijangkau jika blok itu sendiri dapat dijangkau.
Titik akhir blok dapat dijangkau jika blok kosong atau jika titik akhir daftar pernyataan dapat dijangkau.
Blok yang berisi satu atau beberapa yield pernyataan (§13.15) disebut blok iterator. Blok iterator digunakan untuk mengimplementasikan anggota fungsi sebagai iterator (§15,15). Beberapa batasan tambahan berlaku untuk blok iterator:
- Ini adalah kesalahan waktu kompilasi agar
returnpernyataan muncul di blok iterator (tetapiyield returnpernyataan diizinkan). - Ini adalah kesalahan waktu kompilasi untuk blok iterator untuk berisi konteks yang tidak aman (§24.2). Blok iterator selalu mendefinisikan konteks yang aman, bahkan ketika deklarasinya disarangkan dalam konteks yang tidak aman.
13.3.2 Daftar pernyataan
Daftar pernyataan terdiri dari satu atau beberapa pernyataan yang ditulis secara berurutan. Daftar pernyataan terjadi dalam blok (§13,3) dan dalam switch_blocks (§13.8.3).
statement_list
: statement+
;
Daftar pernyataan dijalankan dengan mentransfer kontrol ke pernyataan pertama. Kapan dan jika kontrol mencapai titik akhir pernyataan, kontrol ditransfer ke pernyataan berikutnya. Kapan dan jika kontrol mencapai titik akhir pernyataan terakhir, kontrol ditransfer ke titik akhir daftar pernyataan.
Pernyataan dalam daftar pernyataan dapat dijangkau jika setidaknya salah satu hal berikut ini benar:
- Pernyataan tersebut adalah pernyataan pertama dan daftar pernyataan itu sendiri dapat dijangkau.
- Titik akhir pernyataan sebelumnya dapat dijangkau.
- Pernyataan tersebut adalah pernyataan berlabel dan label direferensikan oleh pernyataan yang dapat dijangkau
goto.
Titik akhir daftar pernyataan dapat dijangkau jika titik akhir pernyataan terakhir dalam daftar dapat dijangkau.
13.4 Pernyataan kosong
Empty_statement tidak melakukan apa-apa.
empty_statement
: ';'
;
Pernyataan kosong digunakan ketika tidak ada operasi untuk dilakukan dalam konteks di mana pernyataan diperlukan.
Eksekusi pernyataan kosong hanya mentransfer kontrol ke titik akhir pernyataan. Dengan demikian, titik akhir pernyataan kosong dapat dijangkau jika pernyataan kosong dapat dijangkau.
Contoh: Pernyataan kosong dapat digunakan saat menulis
whilepernyataan dengan isi null:bool ProcessMessage() {...} void ProcessMessages() { while (ProcessMessage()) ; }Selain itu, pernyataan kosong dapat digunakan untuk mendeklarasikan label tepat sebelum penutupan "
}" blok:void F(bool done) { ... if (done) { goto exit; } ... exit: ; }contoh akhir
13.5 Pernyataan berlabel
labeled_statement mengizinkan pernyataan diawali dengan label. Pernyataan berlabel diizinkan dalam blok, tetapi tidak diizinkan sebagai pernyataan yang disematkan.
labeled_statement
: identifier ':' statement
;
Pernyataan berlabel mendeklarasikan label dengan nama yang diberikan oleh pengidentifikasi. Cakupan label adalah seluruh blok tempat label dideklarasikan, termasuk blok berlapis apa pun. Ini adalah kesalahan waktu kompilasi untuk dua label dengan nama yang sama untuk memiliki cakupan yang tumpang tindih.
Label dapat dirujuk dari goto pernyataan (§13.10.4) dalam cakupan label.
Catatan: Ini berarti bahwa
gotopernyataan dapat mentransfer kontrol dalam blok dan di luar blok, tetapi tidak pernah menjadi blok. catatan akhir
Label memiliki ruang deklarasi sendiri dan tidak mengganggu pengidentifikasi lainnya.
Contoh: Contoh
int F(int x) { if (x >= 0) { goto x; } x = -x; x: return x; }valid dan menggunakan nama x sebagai parameter dan label.
contoh akhir
Eksekusi pernyataan berlabel persis sesuai dengan eksekusi pernyataan setelah label.
Selain keterjangkauan yang disediakan oleh aliran kontrol normal, pernyataan berlabel dapat dijangkau jika label dirujuk oleh pernyataan yang dapat goto dijangkau, kecuali goto pernyataan berada di dalam try blok atau catch blok try_statement yang mencakup finally blok yang titik akhirnya tidak dapat dijangkau, dan pernyataan berlabel berada di luar try_statement.
13.6 Pernyataan deklarasi
13.6.1 Umum
declaration_statement mendeklarasikan satu atau beberapa variabel lokal, satu atau beberapa konstanta lokal, atau fungsi lokal. Pernyataan deklarasi diizinkan dalam blok dan blok sakelar, tetapi tidak diizinkan sebagai pernyataan yang disematkan.
declaration_statement
: local_variable_declaration ';'
| local_constant_declaration ';'
| local_function_declaration
;
Variabel lokal dinyatakan menggunakan local_variable_declaration (§13.6.2). Konstanta lokal dinyatakan menggunakan local_constant_declaration (§13.6.3). Fungsi lokal dinyatakan menggunakan local_function_declaration (§13.6.4).
Nama yang dideklarasikan dimasukkan ke dalam ruang deklarasi penutup terdekat (§7,3).
13.6.2 Deklarasi variabel lokal
13.6.2.1 Umum
local_variable_declaration mendeklarasikan satu atau beberapa variabel lokal.
local_variable_declaration
: implicitly_typed_local_variable_declaration
| explicitly_typed_local_variable_declaration
| explicitly_typed_ref_local_variable_declaration
;
Deklarasi yang diketik secara implisit berisi kata kunci kontekstual (§6.4.4) var menghasilkan ambiguitas sinaks antara tiga kategori yang diselesaikan sebagai berikut:
- Jika tidak ada jenis bernama
vardalam cakupan dan input cocok dengan implicitly_typed_local_variable_declaration maka dipilih; - Jika tidak, jika jenis bernama
varberada dalam cakupan, implicitly_typed_local_variable_declaration tidak dianggap sebagai kecocokan yang mungkin.
Dalam local_variable_declaration setiap variabel diperkenalkan oleh deklarator, yang merupakan salah satu variabel lokal implicitly_typed_local_variable_declarator, explicitly_typed_local_variable_declarator atau ref_local_variable_declarator untuk masing-masing variabel lokal yang diketik secara implisit, diketik secara eksplisit, dan ref. Deklarator mendefinisikan nama (pengidentifikasi) dan nilai awal, jika ada, dari variabel yang diperkenalkan.
Jika ada beberapa deklarator dalam deklarasi maka mereka diproses, termasuk ekspresi inisialisasi apa pun, untuk kiri ke kanan (§9.4.4.5).
Catatan: Untuk local_variable_declaration yang tidak terjadi sebagai for_initializer (§13.9.4) atau resource_acquisition (§13.14) urutan kiri ke kanan ini setara dengan setiap deklarator yang berada dalam local_variable_declaration terpisah. Contohnya:
void F() { int x = 1, y, z = x * 2; }setara dengan:
void F() { int x = 1; int y; int z = x * 2; }catatan akhir
Nilai variabel lokal diperoleh dalam ekspresi menggunakan simple_name (§12.8.4). Variabel lokal pasti akan ditetapkan (§9,4) di setiap lokasi tempat nilainya diperoleh. Setiap variabel lokal yang diperkenalkan oleh local_variable_declaration awalnya tidak ditetapkan (§9.4.3). Jika deklarator memiliki ekspresi inisialisasi, variabel lokal yang diperkenalkan diklasifikasikan seperti yang ditetapkan di akhir deklarator (§9.4.4.5).
Cakupan variabel lokal yang diperkenalkan oleh local_variable_declaration didefinisikan sebagai berikut (§7.7):
- Jika deklarasi terjadi sebagai for_initializer maka cakupannya adalah for_initializer, for_condition, for_iterator, dan embedded_statement (§13.9.4);
- Jika deklarasi terjadi sebagai resource_acquisition maka cakupan adalah blok terluar dari ekspansi using_statement yang setara secara semantik (§13,14);
- Jika tidak, cakupan adalah blok tempat deklarasi terjadi.
Ini adalah kesalahan untuk merujuk ke variabel lokal berdasarkan nama dalam posisi tekstual yang mendahului deklaratornya, atau dalam ekspresi inisialisasi apa pun dalam deklaratornya. Dalam cakupan variabel lokal, ini adalah kesalahan waktu kompilasi untuk mendeklarasikan variabel lokal lain, fungsi lokal, atau konstanta dengan nama yang sama.
Konteks ref-safe (§9,7.2) dari variabel lokal ref adalah konteks ref-safe dari variable_reference inisialisasinya. Konteks ref-safe dari variabel lokal non-ref adalah blok deklarasi.
13.6.2.2 Deklarasi variabel lokal yang diketik secara implisit
implicitly_typed_local_variable_declaration
: 'var' implicitly_typed_local_variable_declarator
| ref_kind 'var' ref_local_variable_declarator
;
implicitly_typed_local_variable_declarator
: identifier '=' expression
;
Implicitly_typed_local_variable_declaration memperkenalkan satu variabel lokal, pengidentifikasi.
Ekspresi atau variable_reference harus memiliki jenis waktu kompilasi, T. Alternatif pertama mendeklarasikan variabel dengan nilai awal ekspresi; jenisnya adalah T? ketika T adalah jenis referensi yang tidak dapat diubah ke null, jika tidak, jenisnya adalah T. Alternatif kedua mendeklarasikan variabel ref dengan nilai refawal variable_reference; jenisnya adalah ref T? ketika T adalah jenis referensi yang tidak dapat diubah ke null, jika tidak, jenisnya adalah ref T. (ref_kind dijelaskan dalam §15.6.1.)
Contoh:
var i = 5; var s = "Hello"; var d = 1.0; var numbers = new int[] {1, 2, 3}; var orders = new Dictionary<int,Order>(); ref var j = ref i; ref readonly var k = ref i;Deklarasi variabel lokal yang diketik secara implisit di atas justru setara dengan deklarasi yang diketik secara eksplisit berikut:
int i = 5; string s = "Hello"; double d = 1.0; int[] numbers = new int[] {1, 2, 3}; Dictionary<int,Order> orders = new Dictionary<int,Order>(); ref int j = ref i; ref readonly int k = ref i;Berikut ini adalah deklarasi variabel lokal yang salah yang diketik secara implisit:
var x; // Error, no initializer to infer type from var y = {1, 2, 3}; // Error, array initializer not permitted var z = null; // Error, null does not have a type var u = x => x + 1; // Error, anonymous functions do not have a type var v = v++; // Error, initializer cannot refer to v itselfcontoh akhir
13.6.2.3 Deklarasi variabel lokal yang diketik secara eksplisit
explicitly_typed_local_variable_declaration
: type explicitly_typed_local_variable_declarators
;
explicitly_typed_local_variable_declarators
: explicitly_typed_local_variable_declarator
(',' explicitly_typed_local_variable_declarator)*
;
explicitly_typed_local_variable_declarator
: identifier ('=' local_variable_initializer)?
;
local_variable_initializer
: expression
| array_initializer
;
Explicitly_typed_local_variable_declaration memperkenalkan satu atau beberapa variabel lokal dengan jenis yang ditentukan.
Jika ada local_variable_initializer maka jenisnya harus sesuai dengan aturan penetapan sederhana (§12.23.2) atau inisialisasi array (§17,7) dan nilainya ditetapkan sebagai nilai awal variabel.
13.6.2.4 Deklarasi variabel lokal ref yang diketik secara eksplisit
explicitly_typed_ref_local_variable_declaration
: ref_kind type ref_local_variable_declarators
;
ref_local_variable_declarators
: ref_local_variable_declarator (',' ref_local_variable_declarator)*
;
ref_local_variable_declarator
: identifier '=' 'ref' variable_reference
;
inisialisasi variable_reference harus memiliki jenis dan memenuhi persyaratan yang sama seperti untuk penugasan ref (§12.23.3).
Jika ref_kind adalah ref readonly, pengidentifikasi yang dideklarasikan adalah referensi ke variabel yang diperlakukan sebagai baca-saja. Jika tidak, jika ref_kind adalah ref, pengidentifikasiyang dinyatakan adalah referensi ke variabel yang akan dapat ditulis.
Ini adalah kesalahan saat waktu kompilasi untuk mendeklarasikan variabel lokal ref, atau variabel tipe ref struct, dalam metode yang dideklarasikan dengan method_modifierasync, atau dalam iterator (§15.15).
13.6.3 Deklarasi konstanta lokal
local_constant_declaration mendeklarasikan satu atau beberapa konstanta lokal.
local_constant_declaration
: 'const' type constant_declarators
;
constant_declarators
: constant_declarator (',' constant_declarator)*
;
constant_declarator
: identifier '=' constant_expression
;
Jenislocal_constant_declaration menentukan jenis konstanta yang diperkenalkan oleh deklarasi. Jenisnya diikuti oleh daftar constant_declarator, yang masing-masing memperkenalkan konstanta baru.
constant_declarator terdiri dari pengidentifikasi yang memberi nama konstanta, diikuti dengan token ""=, diikuti oleh constant_expression (§12,25) yang memberikan nilai konstanta.
Jenis dan constant_expression deklarasi konstanta lokal harus mengikuti aturan yang sama dengan deklarasi anggota konstanta (§15.4).
Nilai konstanta lokal diperoleh dalam ekspresi menggunakan simple_name (§12.8.4).
Cakupan konstanta lokal adalah blok tempat deklarasi terjadi. Ini adalah kesalahan untuk merujuk ke konstanta lokal dalam posisi tekstual yang mendahului akhir constant_declarator.
Deklarasi konstanta lokal yang menyatakan beberapa konstanta setara dengan beberapa deklarasi konstanta tunggal dengan jenis yang sama.
13.6.4 Deklarasi fungsi lokal
local_function_declaration mendeklarasikan fungsi lokal.
local_function_declaration
: local_function_modifier* return_type local_function_header
local_function_body
| ref_local_function_modifier* ref_kind ref_return_type
local_function_header ref_local_function_body
;
local_function_header
: identifier '(' parameter_list? ')'
| identifier type_parameter_list '(' parameter_list? ')'
type_parameter_constraints_clause*
;
local_function_modifier
: ref_local_function_modifier
| 'async'
;
ref_local_function_modifier
: 'static'
| unsafe_modifier // unsafe code support
;
local_function_body
: block
| '=>' null_conditional_invocation_expression ';'
| '=>' expression ';'
;
ref_local_function_body
: block
| '=>' 'ref' variable_reference ';'
;
Catatan tata bahasa: Saat mengenali local_function_body jika alternatif null_conditional_invocation_expression dan ekspresi berlaku maka yang pertama akan dipilih. (§15.6.1)
Contoh: Ada dua kasus penggunaan umum untuk fungsi lokal: metode iterator dan metode asinkron. Dalam metode iterator, pengecualian apa pun diamati hanya ketika memanggil kode yang menghitung urutan yang dikembalikan. Dalam metode asinkron, pengecualian apa pun hanya diamati ketika Tugas yang dikembalikan ditunggu. Contoh berikut menunjukkan pemisahan validasi parameter dari implementasi iterator menggunakan fungsi lokal:
public static IEnumerable<char> AlphabetSubset(char start, char end) { if (start < 'a' || start > 'z') { throw new ArgumentOutOfRangeException(paramName: nameof(start), message: "start must be a letter"); } if (end < 'a' || end > 'z') { throw new ArgumentOutOfRangeException(paramName: nameof(end), message: "end must be a letter"); } if (end <= start) { throw new ArgumentException( $"{nameof(end)} must be greater than {nameof(start)}"); } return AlphabetSubsetImplementation(); IEnumerable<char> AlphabetSubsetImplementation() { for (var c = start; c < end; c++) { yield return c; } } }contoh akhir
Kecuali ditentukan sebaliknya di bawah ini, semantik semua elemen tata bahasa sama dengan untuk method_declaration (§15.6.1), baca dalam konteks fungsi lokal alih-alih metode.
Pengidentifikasi local_function_declaration harus unik dalam cakupan blok yang dinyatakan, termasuk ruang deklarasi variabel lokal yang mencakup. Salah satu konsekuensi dari ini adalah bahwa local_function_declarationyang kelebihan beban tidak diizinkan.
Local_function_declaration dapat mencakup satu async pengubah (§15,14) dan satu unsafe pengubah (§24,1). Jika deklarasi mencakup pengubah async , maka jenis pengembaliannya adalah void atau «TaskType» jenis (§15.14.1). Jika deklarasi menyertakan pengubah static , fungsinya adalah fungsi lokal statis; jika tidak, itu adalah fungsi lokal non-statis. Ini adalah kesalahan waktu kompilasi untuk type_parameter_list atau parameter_list untuk berisi atribut. Jika fungsi lokal dinyatakan dalam konteks tidak aman (§24.2), fungsi lokal mungkin menyertakan kode yang tidak aman, bahkan jika deklarasi fungsi lokal tidak menyertakan pengubah unsafe .
Fungsi lokal dideklarasikan pada cakupan blok. Fungsi lokal non-statis dapat mengambil variabel dari cakupan penutup sementara fungsi lokal statis tidak boleh (sehingga tidak memiliki akses ke lokal, parameter, fungsi lokal non-statis, atau this). Ini adalah kesalahan waktu kompilasi jika variabel yang ditangkap dibaca oleh isi fungsi lokal non-statis tetapi tidak pasti ditetapkan sebelum setiap panggilan ke fungsi. Kompilator harus menentukan variabel mana yang pasti ditetapkan saat pengembalian (§9.4.4.33).
Ketika jenis this adalah jenis struct, itu adalah kesalahan waktu kompilasi bagi isi fungsi lokal untuk mengakses this. Ini benar apakah akses eksplisit (seperti dalam this.x) atau implisit (seperti di x mana x adalah anggota instans struct). Aturan ini hanya melarang akses tersebut dan tidak memengaruhi apakah pencarian anggota menghasilkan anggota struktur.
Ini adalah kesalahan waktu kompilasi bagi isi fungsi lokal untuk berisi goto pernyataan, break pernyataan, atau continue pernyataan yang targetnya berada di luar isi fungsi lokal.
Catatan: aturan di atas untuk
thisdangotomencerminkan aturan untuk fungsi anonim dalam §12.21.3. catatan akhir
Fungsi lokal dapat dipanggil dari titik leksikal sebelum deklarasinya. Namun, ini adalah kesalahan waktu kompilasi agar fungsi dideklarasikan secara leksikal sebelum deklarasi variabel yang digunakan dalam fungsi lokal (§7,7).
Ini adalah kesalahan waktu kompilasi bagi fungsi lokal untuk mendeklarasikan parameter, parameter jenis, atau variabel lokal dengan nama yang sama dengan yang dideklarasikan dalam ruang deklarasi variabel lokal yang mencakup.
Badan fungsi lokal selalu dapat dijangkau. Titik akhir deklarasi fungsi lokal dapat dijangkau jika titik awal deklarasi fungsi lokal dapat dijangkau.
Contoh: Dalam contoh berikut, isi
Ldapat dijangkau meskipun titikLawal tidak dapat dijangkau. Karena titikLawal tidak dapat dijangkau, pernyataan setelah titikLakhir tidak dapat dijangkau:class C { int M() { L(); return 1; // Beginning of L is not reachable int L() { // The body of L is reachable return 2; } // Not reachable, because beginning point of L is not reachable return 3; } }Dengan kata lain, lokasi deklarasi fungsi lokal tidak memengaruhi keterjangkauan pernyataan apa pun dalam fungsi yang berisi. contoh akhir
Jika jenis argumen ke fungsi lokal adalah dynamic, fungsi yang akan dipanggil harus diselesaikan pada waktu kompilasi, bukan runtime.
Fungsi lokal tidak boleh digunakan dalam pohon ekspresi.
Fungsi lokal statis
- Dapat mereferensikan anggota statis, parameter jenis, definisi konstanta, dan fungsi lokal statis dari cakupan penutup.
- Tidak boleh mereferensikan
thisataubaseatau anggota instans dari referensi implisitthis, atau variabel lokal, parameter, atau fungsi lokal non-statis dari cakupan penutup. Namun, semua ini diizinkan dalamnameof()ekspresi.
13.7 Pernyataan ekspresi
Expression_statement mengevaluasi ekspresi tertentu. Nilai yang dihitung oleh ekspresi, jika ada, dibuang.
expression_statement
: statement_expression ';'
;
statement_expression
: null_conditional_invocation_expression
| invocation_expression
| object_creation_expression
| assignment
| post_increment_expression
| post_decrement_expression
| pre_increment_expression
| pre_decrement_expression
| await_expression
;
Tidak semua ekspresi diizinkan sebagai pernyataan.
Catatan: Secara khusus, ekspresi seperti
x + ydanx == 1, yang hanya menghitung nilai (yang akan dibuang), tidak diizinkan sebagai pernyataan. catatan akhir
Eksekusi expression_statement mengevaluasi ekspresi yang terkandung lalu mentransfer kontrol ke titik akhir expression_statement. Titik akhir expression_statement dapat dijangkau jika expression_statement tersebut dapat dijangkau.
13.8 Pernyataan pemilihan
13.8.1 Umum
Pernyataan pilihan memilih salah satu dari sejumlah pernyataan yang mungkin untuk eksekusi berdasarkan nilai beberapa ekspresi.
selection_statement
: if_statement
| switch_statement
;
13.8.2 Pernyataan if
Pernyataan if memilih pernyataan untuk eksekusi berdasarkan nilai ekspresi Boolean.
if_statement
: 'if' '(' boolean_expression ')' embedded_statement
| 'if' '(' boolean_expression ')' embedded_statement
'else' embedded_statement
;
Bagian else dikaitkan dengan pendahuluan if terdekat secara leksikal yang diizinkan oleh sintaks.
Contoh: Dengan demikian, pernyataan
ifformulirif (x) if (y) F(); else G();setara dengan:
if (x) { if (y) { F(); } else { G(); } }contoh akhir
Pernyataan if dijalankan sebagai berikut:
- boolean_expression (§12.26) dievaluasi.
- Jika ekspresi Boolean menghasilkan
true, kontrol ditransfer ke pernyataan pertama yang disematkan. Kapan dan jika kontrol mencapai titik akhir pernyataan tersebut, kontrol ditransfer ke titikifakhir pernyataan. - Jika ekspresi Boolean menghasilkan
falsedan jika adaelsebagian, kontrol ditransfer ke pernyataan tersemat kedua. Kapan dan jika kontrol mencapai titik akhir pernyataan tersebut, kontrol ditransfer ke titikifakhir pernyataan. - Jika ekspresi Boolean menghasilkan
falsedan jika bagianelsetidak ada, kontrol ditransfer ke titikifakhir pernyataan.
Pernyataan pertama yang disematkan dari pernyataan if dapat dijangkau jika if pernyataan dapat dijangkau dan ekspresi Boolean tidak memiliki nilai falsekonstanta .
Pernyataan pernyataan kedua yang if disematkan, jika ada, dapat dijangkau jika if pernyataan dapat dijangkau dan ekspresi Boolean tidak memiliki nilai truekonstanta .
Titik if akhir pernyataan dapat dijangkau jika titik akhir setidaknya salah satu pernyataan yang disematkan dapat dijangkau. Selain itu, titik if akhir pernyataan tanpa else bagian tidak dapat dijangkau jika if pernyataan dapat dijangkau dan ekspresi Boolean tidak memiliki nilai truekonstanta .
13.8.3 Pernyataan pengalihan
Pernyataan switch memilih untuk eksekusi daftar pernyataan yang memiliki label sakelar terkait yang sesuai dengan nilai selector_expression sakelar.
switch_statement
: 'switch' selector_expression switch_block
;
selector_expression
: '(' expression ')'
| tuple_expression
;
switch_block
: '{' switch_section* '}'
;
switch_section
: switch_label+ statement_list
;
switch_label
: 'case' pattern case_guard? ':'
| 'default' ':'
;
case_guard
: 'when' null_coalescing_expression
;
switch_statement terdiri dari kata kunci switch, diikuti oleh ekspresi tuple_expression atau kurung (yang masing-masing disebut selector_expression), diikuti oleh switch_block.
switch_block terdiri dari nol atau lebih switch_section, diapit kurung kurawal. Setiap switch_section terdiri dari satu atau beberapa switch_labeldiikuti oleh statement_list (§13.3.2). Setiap switch_label yang berisi case memiliki pola terkait (§11) di mana nilai selector_expression sakelar diuji. Jika case_guard ada, ekspresinya akan secara implisit dapat dikonversi ke jenis bool dan ekspresi tersebut dievaluasi sebagai kondisi tambahan agar kasus dianggap puas.
Catatan: Untuk kenyamanan, tanda kurung dalam switch_statement dapat dihilangkan saat selector_expression adalah tuple_expression. Misalnya,
switch ((a, b)) …dapat ditulis sebagaiswitch (a, b) …. catatan akhir
Jenis pernyataan yang switch mengatur ditetapkan oleh selector_expression sakelar.
- Jika jenis selector_expression sakelar adalah
sbyte, ,byte, ,ushortintcharulonguintshortboolstringlong, atau enum_type, atau jika itu adalah jenis nilai nullable yang sesuai dengan salah satu jenis ini, maka itu adalah jenisswitchpernyataan yang mengatur. - Jika tidak, jika persis satu konversi implisit yang ditentukan pengguna ada dari jenis selector_expression sakelar ke salah satu jenis tata kelola yang mungkin berikut:
sbyte,intuintlongushortbyteshortulong,char,stringatau, jenis nilai nullable yang sesuai dengan salah satu jenis tersebut, maka jenis yang dikonversi adalah jenisswitchpernyataan yang mengatur. - Jika tidak, jenis pernyataan yang
switchmengatur adalah jenis selector_expression sakelar. Ini adalah kesalahan jika tidak ada jenis seperti itu.
Mungkin ada paling banyak satu default label dalam pernyataan switch .
Ini adalah kesalahan jika pola label sakelar apa pun tidak berlaku (§11.2.1) ke jenis ekspresi input.
Ini adalah kesalahan jika pola label sakelar apa pun disubsumsikan oleh (§11.3) kumpulan pola label switch sebelumnya dari pernyataan pengalihan yang tidak memiliki penjaga kasus atau yang penjaga kasusnya adalah ekspresi konstan dengan nilai benar.
Contoh:
switch (shape) { case var x: break; case var _: // error: pattern subsumed, as previous case always matches break; default: break; // warning: unreachable, all possible values already handled. }contoh akhir
Pernyataan switch dijalankan sebagai berikut:
- selector_expression switch dievaluasi dan dikonversi ke jenis yang mengatur.
- Kontrol ditransfer sesuai dengan nilai selector_expression sakelar yang dikonversi:
- Pola pertama leksikal dalam kumpulan
caselabel dalam pernyataan yang samaswitchyang cocok dengan nilai selector_expression sakelar, dan di mana ekspresi penjaga tidak ada atau dievaluasi ke true, menyebabkan kontrol ditransfer ke daftar pernyataan mengikuti label yang cocokcase. - Jika tidak, jika
defaultlabel ada, kontrol akan ditransfer ke daftar pernyataan setelahdefaultlabel. - Jika tidak, kontrol ditransfer ke titik
switchakhir pernyataan.
- Pola pertama leksikal dalam kumpulan
Catatan: Urutan pola yang dicocokkan pada runtime tidak ditentukan. Pengkompilasi diizinkan (tetapi tidak diperlukan) untuk mencocokkan pola secara tidak berurutan, dan untuk menggunakan kembali hasil pola yang sudah cocok untuk menghitung hasil pencocokan pola lain. Namun demikian, kompilator diperlukan untuk menentukan pola pertama secara leksikal yang cocok dengan ekspresi dan yang klausul penjaganya tidak ada atau dievaluasi menjadi
true. catatan akhir
Jika titik akhir daftar pernyataan bagian sakelar dapat dijangkau, kesalahan waktu kompilasi terjadi. Ini dikenal sebagai aturan "tidak jatuh".
Contoh: Contoh
switch (i) { case 0: CaseZero(); break; case 1: CaseOne(); break; default: CaseOthers(); break; }valid karena tidak ada bagian sakelar yang memiliki titik akhir yang dapat dijangkau. Tidak seperti C dan C++, eksekusi bagian sakelar tidak diizinkan untuk "jatuh" ke bagian sakelar berikutnya, dan contohnya
switch (i) { case 0: CaseZero(); case 1: CaseZeroOrOne(); default: CaseAny(); }menghasilkan kesalahan waktu kompilasi. Ketika eksekusi bagian switch akan diikuti dengan eksekusi bagian switch lain, eksplisit
goto caseataugoto defaultpernyataan akan digunakan:switch (i) { case 0: CaseZero(); goto case 1; case 1: CaseZeroOrOne(); goto default; default: CaseAny(); break; }contoh akhir
Beberapa label diizinkan dalam switch_section.
Contoh: Contoh
switch (i) { case 0: CaseZero(); break; case 1: CaseOne(); break; case 2: default: CaseTwo(); break; }valid. Contoh tidak melanggar aturan "no fall through" karena label
case 2:dandefault:merupakan bagian dari switch_section yang sama.contoh akhir
Catatan: Aturan "no fall through" mencegah kelas umum bug yang terjadi di C dan C++ ketika
breakpernyataan dihilangkan secara tidak sengaja. Misalnya, bagian pernyataan diswitchatas dapat dibalik tanpa memengaruhi perilaku pernyataan:switch (i) { default: CaseAny(); break; case 1: CaseZeroOrOne(); goto default; case 0: CaseZero(); goto case 1; }catatan akhir
Catatan: Daftar pernyataan bagian pengalihan biasanya berakhiran
breakpernyataan , ,goto caseataugoto default, tetapi konstruksi apa pun yang merender titik akhir daftar pernyataan yang tidak dapat dijangkau diizinkan. Misalnya, pernyataan yangwhiledikendalikan oleh ekspresitrueBoolean diketahui tidak pernah mencapai titik akhirnya. Demikian juga, pernyataanthrowataureturnselalu mentransfer kontrol di tempat lain dan tidak pernah mencapai titik akhirnya. Dengan demikian, contoh berikut valid:switch (i) { case 0: while (true) { F(); } case 1: throw new ArgumentException(); case 2: return; }catatan akhir
Contoh: Jenis pernyataan yang
switchmengatur dapat berupa jenisstring. Contohnya:void DoCommand(string command) { switch (command.ToLower()) { case "run": DoRun(); break; case "save": DoSave(); break; case "quit": DoQuit(); break; default: InvalidCommand(command); break; } }contoh akhir
Catatan: Seperti operator kesetaraan string (§12.14.8),
switchpernyataan peka huruf besar/kecil dan akan menjalankan bagian sakelar tertentu hanya jika string selector_expression sakelar sama persis dengancasekonstanta label. catatan akhir
Saat jenis pernyataan yang switch mengatur adalah string atau jenis nilai nullable, nilai null diizinkan sebagai case konstanta label.
statement_listdari switch_block mungkin berisi pernyataan deklarasi (§13,6). Cakupan variabel lokal atau konstanta yang dideklarasikan dalam blok sakelar adalah blok sakelar.
Label sakelar dapat dijangkau jika setidaknya salah satu hal berikut ini benar:
-
selector_expression sakelar adalah nilai konstanta dan
- label adalah
casepola yang akan cocok (§11.2.1) nilai tersebut, dan penjaga label tidak ada atau bukan ekspresi konstan dengan nilai false; atau - ini adalah
defaultlabel, dan tidak ada bagian pengalihan yang berisi label kasus yang polanya akan cocok dengan nilai tersebut, dan yang penjaganya tidak ada atau ekspresi konstanta dengan nilai benar.
- label adalah
-
selector_expression sakelar bukan nilai konstanta dan
- label adalah
casetanpa penjaga atau dengan penjaga yang nilainya bukan false konstanta; atau - ini adalah
defaultlabel dan- kumpulan pola yang muncul di antara kasus pernyataan pengalihan yang tidak memiliki penjaga atau memiliki penjaga yang nilainya adalah true konstanta, tidak lengkap (§11,4) untuk jenis tata kelola switch; atau
- jenis tata kelola sakelar adalah jenis nullable dan kumpulan pola yang muncul di antara kasus pernyataan switch yang tidak memiliki penjaga atau memiliki penjaga yang nilainya adalah true konstanta tidak berisi pola yang akan cocok dengan nilai
null.
- label adalah
- Label sakelar dirujuk oleh pernyataan atau
goto caseyang dapat dijangkaugoto default.
Daftar pernyataan dari bagian sakelar tertentu dapat dijangkau jika switch pernyataan dapat dijangkau dan bagian sakelar berisi label sakelar yang dapat dijangkau.
Titik switch akhir pernyataan dapat dijangkau jika pernyataan pengalihan dapat dijangkau dan setidaknya salah satu hal berikut ini benar:
- Pernyataan berisi
switchpernyataan yang dapat dijangkaubreakyang keluar dariswitchpernyataan. - Tidak ada
defaultlabel yang ada dan baik- selector_expression sakelar adalah nilai non-konstanta, dan kumpulan pola yang muncul di antara kasus pernyataan pengalihan yang tidak memiliki penjaga atau memiliki penjaga yang nilainya adalah true konstanta, tidak lengkap (§11,4) untuk jenis tata kelola pengalihan.
-
selector_expression sakelar adalah nilai non-konstanta dari jenis nullable, dan tidak ada pola yang muncul di antara kasus pernyataan pengalihan yang tidak memiliki penjaga atau memiliki penjaga yang nilainya adalah true konstanta akan cocok dengan nilai
null. -
selector_expression sakelar adalah nilai konstanta dan tanpa
caselabel tanpa penjaga atau yang penjaganya adalah true konstanta akan cocok dengan nilai tersebut.
Contoh: Kode berikut menunjukkan penggunaan klausa yang
whensingkat:static object CreateShape(string shapeDescription) { switch (shapeDescription) { case "circle": return new Circle(2); … case var o when string.IsNullOrWhiteSpace(o): return null; default: return "invalid shape description"; } }Kasus var cocok
null, string kosong, atau string apa pun yang hanya berisi spasi kosong. contoh akhir
13.9 Pernyataan perulangan
13.9.1 Umum
Pernyataan iterasi berulang kali menjalankan pernyataan yang disematkan.
iteration_statement
: while_statement
| do_statement
| for_statement
| foreach_statement
;
13.9.2 Pernyataan sementara
Pernyataan secara while kondisional menjalankan pernyataan yang disematkan nol atau lebih kali.
while_statement
: 'while' '(' boolean_expression ')' embedded_statement
;
Pernyataan while dijalankan sebagai berikut:
- boolean_expression (§12.26) dievaluasi.
- Jika ekspresi Boolean menghasilkan
true, kontrol ditransfer ke pernyataan yang disematkan. Kapan dan jika kontrol mencapai titik akhir pernyataan yang disematkan (mungkin dari eksekusicontinuepernyataan), kontrol ditransfer ke awalwhilepernyataan. - Jika ekspresi Boolean menghasilkan
false, kontrol ditransfer ke titikwhileakhir pernyataan.
Dalam pernyataan pernyataan yang while disematkan, pernyataan break (§13.10.2) dapat digunakan untuk mentransfer kontrol ke titik while akhir pernyataan (sehingga mengakhiri iterasi pernyataan yang disematkan), dan continue pernyataan (§13.10.3) dapat digunakan untuk mentransfer kontrol ke titik akhir pernyataan yang disematkan (sehingga melakukan iterasi lain dari while pernyataan).
Pernyataan pernyataan yang while disematkan dapat dijangkau jika while pernyataan dapat dijangkau dan ekspresi Boolean tidak memiliki nilai falsekonstanta .
Titik while akhir pernyataan dapat dijangkau jika setidaknya salah satu hal berikut ini benar:
- Pernyataan berisi
whilepernyataan yang dapat dijangkaubreakyang keluar dariwhilepernyataan. - Pernyataan
whiledapat dijangkau dan ekspresi Boolean tidak memiliki nilaitruekonstanta .
13.9.3 Pernyataan do
Pernyataan secara do kondisional menjalankan pernyataan yang disematkan satu atau beberapa kali.
do_statement
: 'do' embedded_statement 'while' '(' boolean_expression ')' ';'
;
Pernyataan do dijalankan sebagai berikut:
- Kontrol ditransfer ke pernyataan yang disematkan.
- Kapan dan jika kontrol mencapai titik akhir pernyataan yang disematkan (mungkin dari eksekusi
continuepernyataan), boolean_expression (§12,26) dievaluasi. Jika ekspresi Boolean menghasilkantrue, kontrol ditransfer ke awaldopernyataan. Jika tidak, kontrol ditransfer ke titikdoakhir pernyataan.
Dalam pernyataan pernyataan yang do disematkan, pernyataan break (§13.10.2) dapat digunakan untuk mentransfer kontrol ke titik do akhir pernyataan (sehingga mengakhiri iterasi pernyataan yang disematkan), dan continue pernyataan (§13.10.3) dapat digunakan untuk mentransfer kontrol ke titik akhir pernyataan yang disematkan (sehingga melakukan iterasi lain dari do pernyataan).
Pernyataan pernyataan yang do disematkan dapat dijangkau jika do pernyataan dapat dijangkau.
Titik do akhir pernyataan dapat dijangkau jika setidaknya salah satu hal berikut ini benar:
- Pernyataan berisi
dopernyataan yang dapat dijangkaubreakyang keluar daridopernyataan. - Titik akhir pernyataan yang disematkan dapat dijangkau dan ekspresi Boolean tidak memiliki nilai
truekonstanta .
13.9.4 Untuk pernyataan
Pernyataan mengevaluasi for urutan ekspresi inisialisasi dan kemudian, sementara kondisinya benar, berulang kali menjalankan pernyataan yang disematkan dan mengevaluasi urutan ekspresi perulangan.
for_statement
: 'for' '(' for_initializer? ';' for_condition? ';' for_iterator? ')'
embedded_statement
;
for_initializer
: local_variable_declaration
| statement_expression_list
;
for_condition
: boolean_expression
;
for_iterator
: statement_expression_list
;
statement_expression_list
: statement_expression (',' statement_expression)*
;
for_initializer, jika ada, terdiri dari local_variable_declaration (§13.6.2) atau daftar statement_expression(§13,7) yang dipisahkan oleh koma. Cakupan variabel lokal yang dideklarasikan oleh for_initializer adalah for_initializer, for_condition, for_iterator, dan embedded_statement.
for_condition, jika ada, akan menjadi boolean_expression (§12,26).
for_iterator, jika ada, terdiri dari daftar statement_expression(§13,7) yang dipisahkan oleh koma.
Pernyataan for dijalankan sebagai berikut:
- Jika for_initializer ada, penginisialisasi variabel atau ekspresi pernyataan dijalankan dalam urutan penulisannya. Langkah ini hanya dilakukan sekali.
- Jika ada for_condition , for_condition dievaluasi.
-
Jika for_condition tidak ada atau jika evaluasi menghasilkan
true, kontrol ditransfer ke pernyataan yang disematkan. Kapan dan jika kontrol mencapai titik akhir pernyataan yang disematkan (mungkin dari eksekusicontinuepernyataan), ekspresi for_iterator, jika ada, dievaluasi secara berurutan, dan kemudian iterasi lain dilakukan, dimulai dengan evaluasi for_condition pada langkah di atas. -
Jika for_condition ada dan evaluasi menghasilkan
false, kontrol ditransfer ke titikforakhir pernyataan.
Dalam pernyataan pernyataan yang for disematkan, break pernyataan (§13.10.2) dapat digunakan untuk mentransfer kontrol ke titik for akhir pernyataan (dengan demikian mengakhiri iterasi pernyataan yang disematkan), dan pernyataan continue (§13.10.3) dapat digunakan untuk mentransfer kontrol ke titik akhir pernyataan yang disematkan (dengan demikian menjalankan for_iterator dan melakukan iterasi lain dari pernyataan, for dimulai dengan for_condition).
Pernyataan pernyataan yang for disematkan dapat dijangkau jika salah satu hal berikut ini benar:
- Pernyataan
fordapat dijangkau dan tidak ada for_condition yang ada. - Pernyataan
fordapat dijangkau dan for_condition ada dan tidak memiliki nilaifalsekonstanta .
Titik for akhir pernyataan dapat dijangkau jika setidaknya salah satu hal berikut ini benar:
- Pernyataan berisi
forpernyataan yang dapat dijangkaubreakyang keluar dariforpernyataan. - Pernyataan
fordapat dijangkau dan for_condition ada dan tidak memiliki nilaitruekonstanta .
13.9.5 Pernyataan foreach
13.9.5.1 Umum
Pernyataan ini foreach menghitung elemen koleksi, menjalankan pernyataan yang disematkan untuk setiap elemen koleksi.
foreach_statement
: 'await'? 'foreach' '(' ref_kind? local_variable_type identifier
'in' expression ')' embedded_statement
;
Local_variable_type dan pengidentifikasi pernyataan foreach menyatakan variabel iterasi pernyataan.
var Jika pengidentifikasi diberikan sebagai local_variable_type, dan tidak ada jenis bernama var dalam cakupan, variabel iterasi dikatakan sebagai variabel iterasi yang diketik secara implisit, dan jenisnya diambil untuk menjadi jenis foreach elemen pernyataan, seperti yang ditentukan di bawah ini.
Ini adalah kesalahan waktu kompilasi jika baik await maupun ref_kind ada dalam foreach statement.
Jika foreach_statement berisi atau tidak dan refreadonly, variabel iterasi menunjukkan variabel yang diperlakukan sebagai baca-saja. Jika tidak, jika foreach_statement berisi ref tanpa readonly, variabel iterasi menunjukkan variabel yang akan dapat ditulis.
Variabel iterasi sesuai dengan variabel lokal dengan cakupan yang meluas di atas pernyataan yang disematkan. Selama eksekusi foreach pernyataan, variabel iterasi mewakili elemen koleksi tempat iterasi saat ini sedang dilakukan. Jika variabel iterasi menunjukkan variabel baca-saja, kesalahan waktu kompilasi terjadi jika pernyataan yang disematkan mencoba memodifikasinya (melalui penugasan atau ++ operator dan -- ) atau meneruskannya sebagai parameter referensi atau output.
Pemrosesan waktu foreach kompilasi pernyataan terlebih dahulu menentukan jenis koleksi (C), jenis enumerator (E) dan jenis perulangan (T, ref T atau ref readonly T) ekspresi.
Penentuannya mirip untuk versi sinkron dan asinkron. Antarmuka yang berbeda dengan metode yang berbeda dan jenis pengembalian membedakan versi sinkron dan asinkron. Proses umum berlanjut sebagai berikut. Nama dalam '«' dan '»' adalah tempat penampung untuk nama aktual untuk iterator sinkron dan asinkron. Jenis yang diizinkan untuk «GetEnumerator», «MoveNext», «IEnumerable»T, «IEnumerator»<T>, dan perbedaan lainnya dirinci dalam < untuk pernyataan sinkron>, dan dalam §13.9.5.3 untuk pernyataan asinkronforeach.foreach
- Tentukan apakah jenis
Xekspresi memiliki metode «GetEnumerator» yang sesuai:- Lakukan pencarian anggota pada jenis
Xdengan pengidentifikasi «GetEnumerator» dan tidak ada argumen jenis. Jika pencarian anggota tidak menghasilkan kecocokan, atau menghasilkan ambiguitas, atau menghasilkan kecocokan yang bukan grup metode, periksa antarmuka yang dapat dihitung seperti yang dijelaskan di langkah 2. Disarankan agar peringatan dikeluarkan jika pencarian anggota menghasilkan apa pun kecuali grup metode atau tidak ada kecocokan. - Lakukan resolusi kelebihan beban menggunakan grup metode yang dihasilkan dan daftar argumen kosong. Jika resolusi kelebihan beban tidak menghasilkan metode yang berlaku, menghasilkan ambiguitas, atau menghasilkan satu metode terbaik tetapi metode itu statis atau bukan publik, periksa antarmuka yang dapat dihitung seperti yang dijelaskan di bawah ini. Disarankan agar peringatan dikeluarkan jika resolusi kelebihan beban menghasilkan apa pun kecuali metode instans publik yang tidak ambigu atau tidak ada metode yang berlaku.
- Jika jenis
Epengembalian metode «GetEnumerator» bukan kelas, struct, atau jenis antarmuka, menghasilkan kesalahan dan tidak mengambil langkah lebih lanjut. - Lakukan pencarian anggota dengan
EpengidentifikasiCurrentdan tidak ada argumen jenis. Jika pencarian anggota tidak menghasilkan kecocokan, hasilnya adalah kesalahan, atau hasilnya adalah apa pun kecuali properti instans publik yang mengizinkan pembacaan, menghasilkan kesalahan dan tidak mengambil langkah lebih lanjut. - Lakukan pencarian anggota dengan
Epengidentifikasi «MoveNext» dan tidak ada argumen jenis. Jika pencarian anggota tidak menghasilkan kecocokan, hasilnya adalah kesalahan, atau hasilnya adalah apa pun kecuali grup metode, menghasilkan kesalahan dan tidak mengambil langkah lebih lanjut. - Lakukan resolusi kelebihan beban pada grup metode dengan daftar argumen kosong. Jika resolusi kelebihan beban menghasilkan: tidak ada metode yang berlaku; ambiguitas; atau satu metode terbaik tetapi metode itu statis, atau tidak publik, atau jenis pengembaliannya bukan jenis pengembalian yang diizinkan; kemudian menghasilkan kesalahan dan tidak mengambil langkah-langkah lebih lanjut.
- Jenis koleksi adalah
X, jenis enumerator adalahE, dan jenis iterasi adalah jenisCurrentproperti .
- Lakukan pencarian anggota pada jenis
- Jika tidak, periksa antarmuka yang dapat dijumlahkan:
- Jika di antara semua jenis
Tᵢyang ada konversi implisit dariXke «IEnumerable»<Ti>, ada jenisTunik seperti tidakTdynamicdan untuk yang lainTᵢada konversi implisit dari «IEnumerable»<T> ke «IEnumerable»<Ti>, maka jenis koleksi adalah antarmuka «IEnumerable»<T>, jenis enumerator adalah antarmuka «IEnumerator»<T>, dan jenis iterasinya adalahT. - Jika tidak, jika ada lebih dari satu jenis
Tseperti itu , maka menghasilkan kesalahan dan tidak mengambil langkah-langkah lebih lanjut.
- Jika di antara semua jenis
Catatan: Jika ekspresi memiliki nilai
null, makaSystem.NullReferenceExceptionakan terjadi saat run-time. catatan akhir
Implementasi diizinkan untuk menerapkan foreach_statement tertentu secara berbeda; misalnya, untuk alasan performa, selama perilaku konsisten dengan ekspansi yang dijelaskan dalam §13.9.5.2 dan §13.9.5.3.
13.9.5.2 Foreach sinkron
Sinkron foreach tidak menyertakan await kata kunci sebelum foreach kata kunci. Penentuan jenis koleksi, jenis enumerasi , dan jenis iterasi berlangsung seperti yang dijelaskan dalam §13.9.5.1, di mana:
- «GetEnumerator» adalah
GetEnumeratormetode . - «MoveNext» adalah
MoveNextmetode dengan jenis pengembalianbool. - «IEnumerable»<T> adalah antarmukanya
System.Collections.Generic.IEnumerable<T>. - «IEnumerator»<T> adalah antarmukanya
System.Collections.Generic.IEnumerator<T>.
Selain itu, modifikasi berikut dilakukan pada langkah-langkah dalam §13.9.5.1:
Sebelum proses yang dijelaskan dalam §13.9.5.1, langkah-langkah berikut diambil:
- Jika jenis
Xekspresi adalah jenis array, maka ada konversi referensi implisit dariXkeIEnumerable<T>antarmuka di manaTadalah jenis elemen arrayX(§17.2.3). - Jika jenis
Xekspresi maka ada konversi implisit dari ekspresi kedynamicantarmuka (§10.2.10).IEnumerableJenis koleksi adalahIEnumerableantarmuka dan jenis enumerator adalahIEnumeratorantarmuka.varJika pengidentifikasi diberikan sebagai local_variable_type maka jenis iterasi adalahdynamic, jika tidak, itu adalahobject.
Jika proses dalam §13.9.5.1 selesai tanpa menghasilkan satu jenis koleksi, jenis enumerator, dan jenis iterasi, langkah-langkah berikut diambil:
- Jika ada konversi implisit dari
XkeSystem.Collections.IEnumerableantarmuka, maka jenis koleksi adalah antarmuka ini, jenis enumerator adalah antarmukaSystem.Collections.IEnumerator, dan jenis iterasinya adalahobject. - Jika tidak, kesalahan dihasilkan, dan tidak ada langkah lebih lanjut yang diambil.
Pernyataan foreach formulir
foreach (V v in x) «embedded_statement»
kemudian setara dengan:
{
E e = ((C)(x)).GetEnumerator();
try
{
while (e.MoveNext())
{
V v = (V)(T)e.Current;
«embedded_statement»
}
}
finally
{
... // Dispose e
}
}
Variabel e tidak terlihat atau dapat diakses oleh ekspresi x atau pernyataan yang disematkan atau kode sumber program lainnya. Variabel v bersifat baca-saja dalam pernyataan yang disematkan. Jika tidak ada konversi eksplisit (§10,3) dari T (jenis iterasi) ke V ( local_variable_type dalam foreach pernyataan), kesalahan dihasilkan dan tidak ada langkah lebih lanjut yang diambil.
Ketika variabel iterasi adalah variabel referensi (§9,7), foreach pernyataan formulir
foreach (ref V v in x) «embedded_statement»
kemudian setara dengan:
{
E e = ((C)(x)).GetEnumerator();
try
{
while (e.MoveNext())
{
ref V v = ref e.Current;
«embedded_statement»
}
}
finally
{
... // Dispose e
}
}
Variabel e tidak terlihat atau dapat diakses oleh ekspresi x atau pernyataan yang disematkan atau kode sumber program lainnya. Variabel v referensi adalah baca-tulis dalam pernyataan yang disematkan, tetapi v tidak boleh ditetapkan ulang (§12.23.3). Jika tidak ada konversi identitas (§10.2.2) dari T (jenis iterasi) ke V ( local_variable_type dalam foreach pernyataan), kesalahan dihasilkan dan tidak ada langkah lebih lanjut yang diambil.
Pernyataan foreach formulir foreach (ref readonly V v in x) «embedded_statement» memiliki bentuk yang setara serupa, tetapi variabel v referensi berada ref readonly dalam pernyataan yang disematkan, dan karenanya tidak dapat ditetapkan ulang atau ditetapkan ulang.
Penempatan v di dalam while perulangan penting untuk bagaimana ia ditangkap (§12.21.6.2) oleh fungsi anonim apa pun yang terjadi di embedded_statement.
Contoh:
int[] values = { 7, 9, 13 }; Action f = null; foreach (var value in values) { if (f == null) { f = () => Console.WriteLine("First value: " + value); } } f();Jika
vdalam bentuk yang diperluas dideklarasikan di luarwhileperulangan, itu akan dibagikan di antara semua iterasi, dan nilainya setelahforperulangan akan menjadi nilai akhir,13, yang merupakan pemanggilanfakan dicetak. Sebaliknya, karena setiap iterasi memiliki variabelnyavsendiri , yang ditangkap olehfdalam iterasi pertama akan terus menyimpan nilai7, yaitu apa yang akan dicetak. (Perhatikan bahwa versi C# sebelumnya yang dinyatakanvdi luar perulanganwhile.)contoh akhir
finally Isi blok dibangun sesuai dengan langkah-langkah berikut:
Jika ada konversi implisit dari
EkeSystem.IDisposableantarmuka, makaJika
Eadalah jenis nilai yang tidak dapat diubah ke null, makafinallyklausa diperluas ke semantik yang setara dengan:finally { ((System.IDisposable)e).Dispose(); }Jika tidak,
finallyklausul diperluas ke semantik yang setara dengan:finally { System.IDisposable d = e as System.IDisposable; if (d != null) { d.Dispose(); } }kecuali bahwa jika
Eadalah jenis nilai, atau parameter jenis yang dibuat ke jenis nilai, maka konversi keeSystem.IDisposabletidak akan menyebabkan tinju terjadi.
Jika tidak, jika
Eadalah jenis tertutup,finallyklausul diperluas ke blok kosong:finally {}Jika tidak,
finallyklausa diperluas ke:finally { System.IDisposable d = e as System.IDisposable; if (d != null) { d.Dispose(); } }
Variabel d lokal tidak terlihat atau dapat diakses oleh kode pengguna apa pun. Secara khusus, itu tidak bertentang dengan variabel lain yang cakupannya mencakup finally blok.
Urutan di mana foreach melintasi elemen array, adalah sebagai berikut: Untuk elemen array dimensi tunggal dilalui dalam meningkatkan urutan indeks, dimulai dengan indeks 0 dan berakhir dengan indeks Length – 1. Untuk array multidimensi, elemen dilalui sedih sehingga indeks dimensi paling kanan ditingkatkan terlebih dahulu, lalu dimensi kiri berikutnya, dan seterusnya ke kiri.
Contoh: Contoh berikut mencetak setiap nilai dalam array dua dimensi, dalam urutan elemen:
class Test { static void Main() { double[,] values = { {1.2, 2.3, 3.4, 4.5}, {5.6, 6.7, 7.8, 8.9} }; foreach (double elementValue in values) { Console.Write($"{elementValue} "); } Console.WriteLine(); } }Output yang dihasilkan adalah sebagai berikut:
1.2 2.3 3.4 4.5 5.6 6.7 7.8 8.9contoh akhir
Contoh: Dalam contoh berikut
int[] numbers = { 1, 3, 5, 7, 9 }; foreach (var n in numbers) { Console.WriteLine(n); }jenis
ndisimpulkan menjadiint, jenis iterasi darinumbers.contoh akhir
13.9.5.3 menunggu foreach
Foreach asinkron menggunakan await foreach sintaks. Penentuan jenis koleksi, jenis enumerasi , dan jenis iterasi berlangsung seperti yang dijelaskan dalam §13.9.5.1, di mana:
- «GetEnumerator» adalah
GetEnumeratorAsyncmetode yang memiliki jenis pengembalian yang dapat ditunggu (§12.9.9.2). - «MoveNext» adalah
MoveNextAsyncmetode yang memiliki jenis pengembalian yang dapat ditunggu (§12.9.9.2) di mana await_expression diklasifikasikan sebagaibool(§12.9.9.3). - «IEnumerable»<T> adalah antarmukanya
System.Collections.Generic.IAsyncEnumerable<T>. - «IEnumerator»<T> adalah antarmukanya
System.Collections.Generic.IAsyncEnumerator<T>.
Ini adalah kesalahan untuk jenis pernyataan menjadi variabel referensi (await foreach).
Pernyataan await foreach dalam bentuk
await foreach (T item in enumerable) «embedded_statement»
secara semantik setara dengan:
var enumerator = enumerable.GetAsyncEnumerator();
try
{
while (await enumerator.MoveNextAsync())
{
T item = enumerator.Current;
«embedded_statement»
}
}
finally
{
// dispose of enumerator as described later in this clause.
}
Dalam kasus di mana ekspresi enumerable mewakili ekspresi panggilan metode dan salah satu parameter ditandai dengan EnumeratorCancellationAttribute (§23.5.8) diteruskan CancellationToken ke GetAsyncEnumerator metode . Metode pustaka lain mungkin memerlukan CancellationToken diteruskan ke GetAsyncEnumerator. Ketika metode tersebut adalah bagian dari ekspresi enumerable, token harus digabungkan ke dalam satu token seolah-olah oleh CreateLinkedTokenSource dan propertinya Token .
finally Isi blok dibangun sesuai dengan langkah-langkah berikut:
Jika
Ememiliki metode yang dapat diaksesDisposeAsync()di mana jenis pengembalian dapat ditunggu (§12.9.9.2),finallyklausa diperluas ke semantik yang setara dengan:finally { await e.DisposeAsync(); }Jika tidak, jika ada konversi implisit dari
EkeSystem.IAsyncDisposableantarmuka danEmerupakan jenis nilai yang tidak dapat diubah ke null, makafinallyklausul diperluas ke semantik yang setara dengan:finally { await ((System.IAsyncDisposable)e).DisposeAsync(); }kecuali bahwa jika
Eadalah jenis nilai, atau parameter jenis yang dibuat ke jenis nilai, maka konversi keeSystem.IAsyncDisposabletidak akan menyebabkan tinju terjadi.Jika tidak, jika
Eadalahref structjenis dan memiliki metode yang dapat diaksesDispose(),finallyklausul diperluas ke setara semantik:finally { e.Dispose(); }Jika tidak, jika
Eadalah jenis tertutup,finallyklausul diperluas ke blok kosong:finally {}Jika tidak,
finallyklausa diperluas ke:finally { System.IAsyncDisposable d = e as System.IAsyncDisposable; if (d != null) { await d.DisposeAsync(); } }
Variabel d lokal tidak terlihat atau dapat diakses oleh kode pengguna apa pun. Secara khusus, itu tidak bertentang dengan variabel lain yang cakupannya mencakup finally blok.
Catatan: Tidak
await foreachdiperlukan untuk membuangesecara sinkron jika mekanisme pembuangan asinkron tidak tersedia. catatan akhir
13.10 Pernyataan lompat
13.10.1 Umum
Pernyataan lompat kontrol transfer tanpa syarat.
jump_statement
: break_statement
| continue_statement
| goto_statement
| return_statement
| throw_statement
;
Lokasi di mana pernyataan lompat mentransfer kontrol disebut target pernyataan lompat.
Ketika pernyataan lompat terjadi dalam blok, dan target pernyataan lompat itu berada di luar blok itu, pernyataan lompat dikatakan keluar dari blok. Meskipun pernyataan lompat dapat mentransfer kontrol keluar dari blok, pernyataan lompat tidak dapat mentransfer kontrol ke blok.
Eksekusi pernyataan lompat dipersulit dengan adanya pernyataan intervensi try . Dengan tidak adanya try pernyataan seperti itu, pernyataan lompat secara tidak bersyarat mentransfer kontrol dari pernyataan lompat ke targetnya. Di hadapan pernyataan intervensi try seperti itu, eksekusi lebih kompleks. Jika pernyataan lompat keluar dari satu atau beberapa try blok dengan blok terkait finally , kontrol awalnya ditransfer ke finally blok pernyataan terdahulu try . Kapan dan jika kontrol mencapai titik finally akhir blok, kontrol ditransfer ke finally blok pernyataan penutup try berikutnya. Proses ini diulang sampai finally blok semua pernyataan intervensi try telah dijalankan.
Contoh: Dalam kode berikut
class Test { static void Main() { while (true) { try { try { Console.WriteLine("Before break"); break; } finally { Console.WriteLine("Innermost finally block"); } } finally { Console.WriteLine("Outermost finally block"); } } Console.WriteLine("After break"); } }blok yang
finallyterkait dengan duatrypernyataan dijalankan sebelum kontrol ditransfer ke target pernyataan lompat. Output yang dihasilkan adalah sebagai berikut:Before break Innermost finally block Outermost finally block After breakcontoh akhir
13.10.2 Pernyataan pembobolan
Pernyataan break keluar dari pernyataan penutup terdekat switch, , while, dofor, atau foreach .
break_statement
: 'break' ';'
;
Target break pernyataan adalah titik akhir dari switchpernyataan penutup terdekat , , while, dofor, atau foreach .
break Jika pernyataan tidak diapit oleh switch, , while, do, foratau foreach pernyataan, kesalahan waktu kompilasi terjadi.
Ketika beberapa switchpernyataan , while, do, for, atau foreach disarangkan satu sama lain, break pernyataan hanya berlaku untuk pernyataan terdalu. Untuk mentransfer kontrol di beberapa tingkat bersarang, goto pernyataan (§13.10.4) harus digunakan.
Pernyataan break tidak dapat keluar dari finally blok (§13.11).
break Ketika pernyataan terjadi dalam finally blok, target break pernyataan harus berada dalam blok yang samafinally; jika tidak, kesalahan waktu kompilasi terjadi.
Pernyataan break dijalankan sebagai berikut:
-
breakJika pernyataan keluar dari satu atau beberapatryblok dengan blok terkaitfinally, kontrol awalnya ditransfer kefinallyblok pernyataan terdahulutry. Kapan dan jika kontrol mencapai titikfinallyakhir blok, kontrol ditransfer kefinallyblok pernyataan penutuptryberikutnya. Proses ini diulang sampaifinallyblok semua pernyataan intervensitrytelah dijalankan. - Kontrol ditransfer ke target
breakpernyataan.
break Karena pernyataan secara tanpa syarat mentransfer kontrol di tempat lain, titik break akhir pernyataan tidak pernah dapat dijangkau.
13.10.3 Pernyataan lanjutan
Pernyataan memulai continue iterasi baru dari pernyataan penutup , , while, doatau for terdekatforeach.
continue_statement
: 'continue' ';'
;
Target continue pernyataan adalah titik akhir dari pernyataan yang disematkan dari pernyataan penutup terdekat while, , do, foratau foreach .
continue Jika pernyataan tidak diapit oleh whilepernyataan , , do, foratau foreach , terjadi kesalahan waktu kompilasi.
Ketika beberapa whilepernyataan , do, for, atau foreach disarangkan satu sama lain, continue pernyataan hanya berlaku untuk pernyataan terdalu. Untuk mentransfer kontrol di beberapa tingkat bersarang, goto pernyataan (§13.10.4) harus digunakan.
Pernyataan continue tidak dapat keluar dari finally blok (§13.11).
continue Ketika pernyataan terjadi dalam finally blok, target continue pernyataan harus berada dalam blok yang samafinally; jika tidak, kesalahan waktu kompilasi terjadi.
Pernyataan continue dijalankan sebagai berikut:
-
continueJika pernyataan keluar dari satu atau beberapatryblok dengan blok terkaitfinally, kontrol awalnya ditransfer kefinallyblok pernyataan terdahulutry. Kapan dan jika kontrol mencapai titikfinallyakhir blok, kontrol ditransfer kefinallyblok pernyataan penutuptryberikutnya. Proses ini diulang sampaifinallyblok semua pernyataan intervensitrytelah dijalankan. - Kontrol ditransfer ke target
continuepernyataan.
continue Karena pernyataan secara tanpa syarat mentransfer kontrol di tempat lain, titik continue akhir pernyataan tidak pernah dapat dijangkau.
13.10.4 Pernyataan goto
Pernyataan mentransfer goto kontrol ke pernyataan yang ditandai oleh label.
goto_statement
: 'goto' identifier ';'
| 'goto' 'case' constant_expression ';'
| 'goto' 'default' ';'
;
Target gotopernyataan pengidentifikasi adalah pernyataan berlabel dengan label yang diberikan. Jika label dengan nama yang diberikan tidak ada di anggota fungsi saat ini, atau jika goto pernyataan tidak berada dalam cakupan label, kesalahan waktu kompilasi terjadi.
Catatan: Aturan ini mengizinkan penggunaan
gotopernyataan untuk mentransfer kontrol keluar dari cakupan berlapis, tetapi tidak ke dalam cakupan berlapis. Dalam contohclass Test { static void Main(string[] args) { string[,] table = { {"Red", "Blue", "Green"}, {"Monday", "Wednesday", "Friday"} }; foreach (string str in args) { int row, colm; for (row = 0; row <= 1; ++row) { for (colm = 0; colm <= 2; ++colm) { if (str == table[row,colm]) { goto done; } } } Console.WriteLine($"{str} not found"); continue; done: Console.WriteLine($"Found {str} at [{row}][{colm}]"); } } }
gotopernyataan digunakan untuk mentransfer kontrol keluar dari cakupan berlapis.catatan akhir
Target pernyataan goto case adalah daftar pernyataan dalam pernyataan penutup switch segera (§13.8.3) yang berisi case label dengan pola konstanta dari nilai konstanta yang diberikan dan tanpa penjaga.
goto case Jika pernyataan tidak diapit oleh switch pernyataan, jika pernyataan penutup switch terdekat tidak berisi case, atau jika constant_expression tidak secara implisit dapat dikonversi (§10,2) ke jenis yang mengatur dari pernyataan penutup switch terdekat, kesalahan waktu kompilasi terjadi.
Target pernyataan goto default adalah daftar pernyataan dalam pernyataan yang switch segera diapit (§13.8.3), yang berisi default label.
goto default Jika pernyataan tidak diapit oleh switch pernyataan, atau jika pernyataan penutup switch terdekat tidak berisi default label, kesalahan waktu kompilasi terjadi.
Pernyataan goto tidak dapat keluar dari finally blok (§13.11).
goto Ketika pernyataan terjadi dalam finally blok, target goto pernyataan harus berada dalam blok yang samafinally, atau jika tidak, terjadi kesalahan waktu kompilasi.
Pernyataan goto dijalankan sebagai berikut:
-
gotoJika pernyataan keluar dari satu atau beberapatryblok dengan blok terkaitfinally, kontrol awalnya ditransfer kefinallyblok pernyataan terdahulutry. Kapan dan jika kontrol mencapai titikfinallyakhir blok, kontrol ditransfer kefinallyblok pernyataan penutuptryberikutnya. Proses ini diulang sampaifinallyblok semua pernyataan intervensitrytelah dijalankan. - Kontrol ditransfer ke target
gotopernyataan.
goto Karena pernyataan secara tanpa syarat mentransfer kontrol di tempat lain, titik goto akhir pernyataan tidak pernah dapat dijangkau.
13.10.5 Pernyataan pengembalian
Pernyataan return mengembalikan kontrol ke pemanggil anggota fungsi saat ini di mana pernyataan pengembalian muncul, secara opsional mengembalikan nilai atau variable_reference (§9,5).
return_statement
: 'return' ';'
| 'return' expression ';'
| 'return' 'ref' variable_reference ';'
;
return_statement tanpa ekspresi disebut return-no-value; satu yang berisi refekspresi disebut return-by-ref; dan satu yang hanya berisi ekspresi disebut return-by-value.
Ini adalah kesalahan waktu kompilasi untuk menggunakan return-no-value dari metode yang dinyatakan sebagai returns-by-value atau returns-by-ref (§15.6.1).
Ini adalah kesalahan waktu kompilasi untuk menggunakan return-by-ref dari metode yang dinyatakan sebagai returns-no-value atau returns-by-value.
Ini adalah kesalahan kompilasi-waktu untuk menggunakan return-by-value dari metode yang dinyatakan sebagai returns-no-value atau returns-by-ref.
Ini adalah kesalahan waktu kompilasi untuk menggunakan return-by-ref jika ekspresi bukan variable_reference atau merupakan referensi ke variabel yang konteks ref-safe-nya bukan caller-context (§9.7.2).
Ini adalah kesalahan waktu kompilasi untuk menggunakan return-by-ref dari metode yang dideklarasikan dengan method_modifierasync.
Anggota fungsi dikatakan menghitung nilai jika merupakan metode dengan metode returns-by-value (§15.6.11), returns-by-value get accessor dari properti atau pengindeks, atau operator yang ditentukan pengguna. Anggota fungsi yang merupakan returns-no-value tidak menghitung nilai dan merupakan metode dengan jenis voidpengembalian yang efektif, mengatur pengakses properti dan pengindeks, menambahkan dan menghapus pengakses peristiwa, konstruktor instans, konstruktor statis, dan finalizer. Anggota fungsi yang dikembalikan-demi-ref tidak menghitung nilai.
Untuk return-by-value, konversi implisit (§10,2) harus ada dari jenis ekspresi ke jenis pengembalian efektif (§15.6.11) dari anggota fungsi yang berisi. Untuk return-by-ref, konversi identitas (§10.2.2) harus ada antara jenis ekspresi dan jenis pengembalian efektif dari anggota fungsi yang berisi.
return pernyataan juga dapat digunakan dalam isi ekspresi fungsi anonim (§12,21), dan berpartisipasi dalam menentukan konversi mana yang ada untuk fungsi tersebut (§10.7.1).
Ini adalah kesalahan waktu kompilasi agar return pernyataan muncul di finally blok (§13.11).
Pernyataan return dijalankan sebagai berikut:
- Untuk return-by-value, ekspresi dievaluasi dan nilainya dikonversi ke jenis pengembalian efektif dari fungsi yang berisi oleh konversi implisit. Hasil konversi menjadi nilai hasil yang dihasilkan oleh fungsi . Untuk return-by-ref, ekspresi dievaluasi, dan hasilnya akan diklasifikasikan sebagai variabel. Jika return-by-ref metode penutup menyertakan
readonly, variabel yang dihasilkan bersifat baca-saja. -
returnJika pernyataan diapit oleh satu atau beberapatryblokcatchdengan blok terkaitfinally, kontrol awalnya ditransfer kefinallyblok pernyataan terdahulutry. Kapan dan jika kontrol mencapai titikfinallyakhir blok, kontrol ditransfer kefinallyblok pernyataan penutuptryberikutnya. Proses ini diulang hinggafinallyblok semua pernyataan penutuptrytelah dijalankan. - Jika fungsi yang berisi bukan fungsi asinkron, kontrol dikembalikan ke pemanggil fungsi yang berisi bersama dengan nilai hasil, jika ada.
- Jika fungsi yang berisi adalah fungsi asinkron, kontrol dikembalikan ke pemanggil saat ini, dan nilai hasil, jika ada, dicatat dalam tugas pengembalian seperti yang dijelaskan dalam (§15.14.3).
return Karena pernyataan secara tanpa syarat mentransfer kontrol di tempat lain, titik return akhir pernyataan tidak pernah dapat dijangkau.
13.10.6 Pernyataan pelemparan
Pernyataan tersebut throw melemparkan pengecualian.
throw_statement
: 'throw' expression? ';'
;
throw Pernyataan dengan ekspresi melemparkan pengecualian yang dihasilkan dengan mengevaluasi ekspresi. Ekspresi harus secara implisit dapat dikonversi ke System.Exception, dan hasil mengevaluasi ekspresi dikonversi ke System.Exception sebelum dilemparkan. Jika hasil konversi adalah null, akan System.NullReferenceException dilemparkan sebagai gantinya.
Pernyataan throw tanpa ekspresi hanya dapat digunakan dalam catch blok, dalam hal ini, pernyataan tersebut melemparkan kembali pengecualian yang saat ini sedang ditangani oleh blok tersebut catch .
throw Karena pernyataan secara tanpa syarat mentransfer kontrol di tempat lain, titik throw akhir pernyataan tidak pernah dapat dijangkau.
Ketika pengecualian dilemparkan, kontrol ditransfer ke klausul pertama catch dalam pernyataan penutup try yang dapat menangani pengecualian. Proses yang berlangsung dari titik pengecualian dilemparkan ke titik transfer kontrol ke handler pengecualian yang sesuai dikenal sebagai penyebaran pengecualian. Penyebaran pengecualian terdiri dari berulang kali mengevaluasi langkah-langkah berikut sampai catch klausul yang cocok dengan pengecualian ditemukan. Dalam deskripsi ini, titik pelemparan awalnya adalah lokasi di mana pengecualian dilemparkan. Perilaku ini ditentukan dalam (§22.4).
Dalam anggota fungsi saat ini, setiap
trypernyataan yang mencakup titik lemparan diperiksa. Untuk setiap pernyataanS, dimulai dengan pernyataan terdahulutrydan diakhiri dengan pernyataan terluartry, langkah-langkah berikut dievaluasi:-
tryJika blokSmencakup titik lemparan dan jikaSmemiliki satu atau beberapacatchklausul,catchklausa diperiksa dalam urutan penampilan untuk menemukan handler yang cocok untuk pengecualian. Klausa pertamacatchyang menentukan jenisTpengecualian (atau parameter jenis yang pada run-time menunjukkan jenisTpengecualian ) sehingga jenisErun-time yang berasal dianggapTcocok. Jika klausa berisi filter pengecualian, objek pengecualian ditetapkan ke variabel pengecualian, dan filter pengecualian dievaluasi.catchSaat klausa berisi filter pengecualian,catchklausa tersebut dianggap cocok jika filter pengecualian dievaluasi ketrue. Klausa umumcatch(§13.11) dianggap cocok untuk jenis pengecualian apa pun. Jika klausul yangcatchcocok ditemukan, penyebaran pengecualian diselesaikan dengan mentransfer kontrol ke blokcatchklausa tersebut. - Jika tidak, jika
tryblok ataucatchblokSmenutupi titik lemparan dan jikaSmemilikifinallyblok, kontrol ditransfer kefinallyblok.finallyJika blok melemparkan pengecualian lain, pemrosesan pengecualian saat ini dihentikan. Jika tidak, ketika kontrol mencapai titikfinallyakhir blok, pemrosesan pengecualian saat ini dilanjutkan.
-
Jika handler pengecualian tidak terletak di pemanggilan fungsi saat ini, pemanggilan fungsi dihentikan, dan salah satu hal berikut terjadi:
Jika fungsi saat ini tidak asinkron, langkah-langkah di atas diulang untuk pemanggil fungsi dengan titik lemparan yang sesuai dengan pernyataan tempat anggota fungsi dipanggil.
Jika fungsi saat ini adalah asinkron dan mengembalikan tugas, pengecualian dicatat dalam tugas yang dikembalikan, yang dimasukkan ke dalam status gagal atau dibatalkan seperti yang dijelaskan dalam §15.14.3.
Jika fungsi saat ini adalah asinkron dan
void-returning, konteks sinkronisasi utas saat ini akan diberi tahu seperti yang dijelaskan dalam §15.14.4.
Jika pemrosesan pengecualian mengakhiri semua pemanggilan anggota fungsi di utas saat ini, menunjukkan bahwa utas tidak memiliki handler untuk pengecualian, maka utas itu sendiri dihentikan. Dampak penghentian tersebut ditentukan implementasi.
13.11 Pernyataan coba
Pernyataan ini try menyediakan mekanisme untuk menangkap pengecualian yang terjadi selama eksekusi blok. Selain itu, pernyataan memberikan try kemampuan untuk menentukan blok kode yang selalu dijalankan ketika kontrol meninggalkan try pernyataan.
try_statement
: 'try' block catch_clauses
| 'try' block catch_clauses? finally_clause
;
catch_clauses
: specific_catch_clause+
| specific_catch_clause* general_catch_clause
;
specific_catch_clause
: 'catch' exception_specifier exception_filter? block
| 'catch' exception_filter block
;
exception_specifier
: '(' type identifier? ')'
;
exception_filter
: 'when' '(' boolean_expression ')'
;
general_catch_clause
: 'catch' block
;
finally_clause
: 'finally' block
;
try_statement terdiri dari kata kunci try diikuti oleh blok, lalu nol atau lebih catch_clauses, lalu finally_clause opsional. Setidaknya akan ada satu catch_clause atau finally_clause.
Dalam exception_specifierjenis, atau kelas dasar yang efektif jika itu adalah type_parameter, adalah System.Exception atau jenis yang berasal darinya.
catch Ketika klausul menentukan class_type dan pengidentifikasi, variabel pengecualian dari nama dan jenis yang diberikan dideklarasikan. Variabel pengecualian dimasukkan ke dalam ruang deklarasi specific_catch_clause (§7,3). Selama eksekusi exception_filter dan catch blok, variabel pengecualian mewakili pengecualian yang saat ini sedang ditangani. Untuk tujuan pemeriksaan penugasan pasti, variabel pengecualian dianggap pasti ditetapkan dalam seluruh cakupannya.
Kecuali klausul catch menyertakan nama variabel pengecualian, tidak mungkin untuk mengakses objek pengecualian di filter dan catch blok.
catch Klausa yang menentukan jenis pengecualian atau nama variabel pengecualian tidak disebut klausul umumcatch. Pernyataan try hanya dapat memiliki satu klausa umum catch , dan, jika ada, itu akan menjadi klausul terakhir catch .
Catatan: Beberapa bahasa pemrograman mungkin mendukung pengecualian yang tidak dapat diwakili sebagai objek yang berasal dari
System.Exception, meskipun pengecualian tersebut tidak pernah dapat dihasilkan oleh kode C#. Klausul umumcatchmungkin digunakan untuk menangkap pengecualian tersebut. Dengan demikian, klausul umumcatchsecara semantik berbeda dari yang menentukan jenisSystem.Exception, di mana yang pertama mungkin juga menangkap pengecualian dari bahasa lain. catatan akhir
Untuk menemukan handler untuk pengecualian, catch klausul diperiksa dalam urutan leksikal.
catch Jika klausa menentukan jenis tetapi tidak ada filter pengecualian, itu adalah kesalahan waktu kompilasi untuk klausa yang lebih baru catch dari pernyataan yang sama try untuk menentukan jenis yang sama dengan, atau berasal dari, jenis tersebut.
Catatan: Tanpa pembatasan ini, akan mungkin untuk menulis klausul yang tidak dapat dijangkau
catch. catatan akhir
catch Dalam blok, throw pernyataan (§13.10.6) tanpa ekspresi tidak dapat digunakan untuk melemparkan kembali pengecualian yang ditangkap oleh catch blok. Penugasan ke variabel pengecualian tidak mengubah pengecualian yang dilemparkan kembali.
Contoh: Dalam kode berikut
class Test { static void F() { try { G(); } catch (Exception e) { Console.WriteLine("Exception in F: " + e.Message); e = new Exception("F"); throw; // re-throw } } static void G() => throw new Exception("G"); static void Main() { try { F(); } catch (Exception e) { Console.WriteLine("Exception in Main: " + e.Message); } } }metode
Fini menangkap pengecualian, menulis beberapa informasi diagnostik ke konsol, mengubah variabel pengecualian, dan melemparkan kembali pengecualian. Pengecualian yang dilemparkan kembali adalah pengecualian asli, sehingga output yang dihasilkan adalah:Exception in F: G Exception in Main: GJika blok pertama
catchtelah dilemparkanealih-alih menumbuhkan kembali pengecualian saat ini, output yang dihasilkan adalah sebagai berikut:Exception in F: G Exception in Main: Fcontoh akhir
Ini adalah kesalahan waktu kompilasi untuk breakpernyataan , , continueatau goto untuk mentransfer kontrol keluar dari finally blok.
breakKetika pernyataan , , continueatau goto terjadi dalam finally blok, target pernyataan harus berada dalam blok yang samafinally, atau jika tidak, kesalahan waktu kompilasi terjadi.
Ini adalah kesalahan waktu kompilasi agar return pernyataan terjadi dalam finally blok.
Ketika eksekusi mencapai try pernyataan, kontrol ditransfer ke try blok. Jika kontrol mencapai titik try akhir blok tanpa pengecualian disebarluaskan, kontrol akan ditransfer ke finally blok jika ada. Jika tidak ada finally blok, kontrol ditransfer ke titik try akhir pernyataan.
Jika pengecualian telah disebarluaskan, catch klausul, jika ada, diperiksa dalam urutan leksikal yang mencari kecocokan pertama untuk pengecualian. Pencarian klausul yang cocok catch berlanjut dengan semua blok penutup seperti yang dijelaskan dalam §13.10.6.
catch Klausa cocok jika jenis pengecualian cocok dengan exception_specifier dan exception_filter apa pun benar.
catch Klausa tanpa exception_specifier cocok dengan jenis pengecualian apa pun. Jenis pengecualian cocok dengan exception_specifier saat exception_specifier menentukan jenis pengecualian atau jenis dasar dari jenis pengecualian. Jika klausa berisi filter pengecualian, objek pengecualian ditetapkan ke variabel pengecualian, dan filter pengecualian dievaluasi. Jika evaluasi boolean_expression untuk exception_filter melempar pengecualian, pengecualian tersebut tertangkap, dan filter pengecualian mengevaluasi ke false.
Jika pengecualian telah disebarluaskan dan klausul yang cocok catch ditemukan, kontrol ditransfer ke blok pencocokan catch pertama. Jika kontrol mencapai titik catch akhir blok tanpa pengecualian disebarluaskan, kontrol akan ditransfer ke finally blok jika ada. Jika tidak ada finally blok, kontrol ditransfer ke titik try akhir pernyataan. Jika pengecualian telah disebarluaskan dari catch blok, kontrol akan ditransfer ke finally blok jika ada. Pengecualian disebarkan ke pernyataan penutup berikutnya try .
Jika pengecualian telah disebarluaskan, dan tidak ada klausa yang catch cocok yang ditemukan, kontrol akan ditransfer ke finally blok, jika ada. Pengecualian disebarkan ke pernyataan penutup berikutnya try .
Pernyataan finally blok selalu dijalankan ketika kontrol meninggalkan try pernyataan. Ini benar apakah transfer kontrol terjadi sebagai akibat dari eksekusi normal, sebagai akibat dari menjalankan breakpernyataan , , continue, gotoatau return , atau sebagai akibat dari menyebarkan pengecualian dari try pernyataan. Jika kontrol mencapai titik finally akhir blok tanpa pengecualian disebarluaskan, kontrol ditransfer ke titik try akhir pernyataan.
Jika pengecualian dilemparkan selama eksekusi finally blok, dan tidak tertangkap dalam blok yang sama finally , pengecualian disebarkan ke pernyataan penutup try berikutnya. Jika pengecualian lain sedang dalam proses disebarluaskan, pengecualian tersebut akan hilang. Proses penyebaran pengecualian dibahas lebih lanjut dalam deskripsi throw pernyataan (§13.10.6).
Contoh: Dalam kode berikut
public class Test { static void Main() { try { Method(); } catch (Exception ex) when (ExceptionFilter(ex)) { Console.WriteLine("Catch"); } bool ExceptionFilter(Exception ex) { Console.WriteLine("Filter"); return true; } } static void Method() { try { throw new ArgumentException(); } finally { Console.WriteLine("Finally"); } } }metode
Methodmelemparkan pengecualian. Tindakan pertama adalah memeriksa klausa penutupcatch, menjalankan filter pengecualian apa pun. Kemudian,finallyklausul dalamMethoddijalankan sebelum kontrol ditransfer ke klausul pencocokancatchpenutup. Output yang dihasilkan adalah:Filter Finally Catchcontoh akhir
try Blok try pernyataan dapat dijangkau jika try pernyataan dapat dijangkau.
catch Blok try pernyataan dapat dijangkau jika try pernyataan dapat dijangkau.
finally Blok try pernyataan dapat dijangkau jika try pernyataan dapat dijangkau.
Titik try akhir pernyataan dapat dijangkau jika kedua hal berikut ini benar:
- Titik
tryakhir blok dapat dijangkau atau titik akhir setidaknya satucatchblok dapat dijangkau. - Jika ada
finallyblok, titikfinallyakhir blok dapat dijangkau.
13.12 Pernyataan yang dicentang dan tidak dicentang
Pernyataan checked dan unchecked digunakan untuk mengontrol konteks pemeriksaan luapan untuk operasi dan konversi aritmatika jenis integral.
checked_statement
: 'checked' block
;
unchecked_statement
: 'unchecked' block
;
Pernyataan menyebabkan checked semua ekspresi dalam blok dievaluasi dalam konteks yang diperiksa, dan unchecked pernyataan menyebabkan semua ekspresi dalam blok dievaluasi dalam konteks yang tidak dicentang.
Pernyataan checked dan unchecked tepatnya setara dengan checked operator dan unchecked (§12.8.20), kecuali bahwa mereka beroperasi pada blok alih-alih ekspresi.
13.13 Pernyataan kunci
Pernyataan ini lock memperoleh kunci pengecualian bersama untuk objek tertentu, menjalankan pernyataan, dan kemudian melepaskan kunci.
lock_statement
: 'lock' '(' expression ')' embedded_statement
;
Ekspresi lock pernyataan harus menunjukkan nilai jenis yang diketahui sebagai referensi. Tidak ada konversi tinju implisit (§10.2.9) yang pernah dilakukan untuk pernyataan, dan dengan demikian itu adalah kesalahan waktu kompilasi bagi ekspresi untuk menunjukkan nilai lock.
Pernyataan lock formulir
lock (x) ...
di mana x adalah ekspresi reference_type, tepatnya setara dengan:
bool __lockWasTaken = false;
try
{
System.Threading.Monitor.Enter(x, ref __lockWasTaken);
...
}
finally
{
if (__lockWasTaken)
{
System.Threading.Monitor.Exit(x);
}
}
kecuali x hanya dievaluasi sekali.
Saat kunci pengecualian bersama ditahan, kode yang dijalankan dalam utas eksekusi yang sama juga dapat memperoleh dan melepaskan kunci. Namun, kode yang dijalankan di utas lain diblokir agar tidak mendapatkan kunci hingga kunci dilepaskan.
13.14 Pernyataan penggunaan
13.14.1 Umum
Pernyataan ini using memperoleh satu atau beberapa sumber daya, menjalankan pernyataan, lalu membuang sumber daya.
using_statement
: 'await'? 'using' '(' resource_acquisition ')' embedded_statement
;
resource_acquisition
: non_ref_local_variable_declaration
| expression
;
non_ref_local_variable_declaration
: implicitly_typed_local_variable_declaration
| explicitly_typed_local_variable_declaration
;
Jenis sumber daya adalah struct kelas atau non-ref yang mengimplementasikan salah satu atau kedua System.IDisposable antarmuka atau System.IAsyncDisposable , yang mencakup metode tanpa parameter tunggal bernama Dispose dan/atau DisposeAsync; atau struktur ref yang menyertakan metode bernama Dispose memiliki tanda tangan yang sama seperti yang dideklarasikan oleh System.IDisposable. Kode yang menggunakan sumber daya dapat memanggil Dispose atau DisposeAsync untuk menunjukkan bahwa sumber daya tidak lagi diperlukan.
Jika bentuk resource_acquisitionlocal_variable_declaration maka jenis local_variable_declaration harus berupa dynamic atau jenis sumber daya. Jika bentuk resource_acquisition adalah ekspresi , ekspresi ini akan memiliki jenis sumber daya. Jika await ada, jenis sumber daya akan mengimplementasikan System.IAsyncDisposable. Jenis ref struct tidak boleh berupa jenis sumber daya untuk using pernyataan dengan pengubah await .
Variabel lokal yang dinyatakan dalam resource_acquisition bersifat baca-saja, dan harus menyertakan penginisialisasi. Kesalahan waktu kompilasi terjadi jika pernyataan yang disematkan mencoba memodifikasi variabel lokal ini (melalui penugasan atau ++ operator dan -- ), mengambil alamatnya, atau meneruskannya sebagai parameter referensi atau output.
Pernyataan using diterjemahkan ke dalam tiga bagian: akuisisi, penggunaan, dan pembuangan. Penggunaan sumber daya secara implisit diapit dalam try pernyataan yang menyertakan finally klausul. Klausa ini finally membuang sumber daya. Jika ekspresi akuisisi mengevaluasi ke null, maka tidak ada panggilan ke Dispose (atau DisposeAsync) yang dilakukan, dan tidak ada pengecualian yang dilemparkan. Jika jenis sumber daya dynamic dikonversi secara dinamis melalui konversi dinamis implisit (§10.2.10) ke IDisposable (atau IAsyncDisposable) selama akuisisi untuk memastikan bahwa konversi berhasil sebelum penggunaan dan pembuangan.
Pernyataan using formulir
using (ResourceType resource = «expression» ) «statement»
sesuai dengan salah satu dari tiga kemungkinan rumusan. Untuk sumber daya struct kelas dan non-ref, ketika ResourceType adalah jenis nilai yang tidak dapat diubah ke null atau parameter jenis dengan batasan jenis nilai (§15.2.5), rumusan secara semantik setara dengan
{
ResourceType resource = «expression»;
try
{
«statement»;
}
finally
{
((IDisposable)resource).Dispose();
}
}
Kecuali bahwa para pemeran resourceSystem.IDisposable untuk tidak menyebabkan tinju terjadi.
Jika tidak, kapan ResourceType adalah dynamic, rumusnya adalah
{
ResourceType resource = «expression»;
IDisposable d = resource;
try
{
«statement»;
}
finally
{
if (d != null)
{
d.Dispose();
}
}
}
Jika tidak, rumusannya adalah
{
ResourceType resource = «expression»;
try
{
«statement»;
}
finally
{
IDisposable d = (IDisposable)resource;
if (d != null)
{
d.Dispose();
}
}
}
Untuk sumber daya struct ref, satu-satunya rumusan yang setara secara semantik adalah
{
«ResourceType» resource = «expression»;
try
{
«statement»;
}
finally
{
resource.Dispose();
}
}
Dalam rumusan apa pun, resource variabel bersifat baca-saja dalam pernyataan yang disematkan, dan d variabel tidak dapat diakses, dan tidak terlihat, pernyataan yang disematkan.
Pernyataan using formulir:
using («expression») «statement»
memiliki kemungkinan rumusan yang sama.
Ketika resource_acquisition mengambil bentuk local_variable_declaration, dimungkinkan untuk memperoleh beberapa sumber daya dari jenis tertentu. Pernyataan using formulir
using (ResourceType r1 = e1, r2 = e2, ..., rN = eN) «statement»
tepatnya setara dengan urutan pernyataan berlapis using :
using (ResourceType r1 = e1)
using (ResourceType r2 = e2)
...
using (ResourceType rN = eN)
«statement»
Contoh: Contoh di bawah ini membuat file bernama log.txt dan menulis dua baris teks ke file. Contoh kemudian membuka file yang sama untuk membaca dan menyalin baris teks yang terkandung ke konsol.
class Test { static void Main() { using (TextWriter w = File.CreateText("log.txt")) { w.WriteLine("This is line one"); w.WriteLine("This is line two"); } using (TextReader r = File.OpenText("log.txt")) { string s; while ((s = r.ReadLine()) != null) { Console.WriteLine(s); } } } }
TextWriterKarena kelas danTextReadermengimplementasikanIDisposableantarmuka, contoh dapat menggunakanusingpernyataan untuk memastikan bahwa file yang mendasar ditutup dengan benar setelah operasi tulis atau baca.contoh akhir
Kapan ResourceType adalah jenis referensi yang mengimplementasikan IAsyncDisposable. Rumusan lain untuk await using melakukan substitusi serupa dari metode sinkron Dispose ke metode asinkron DisposeAsync . Pernyataan await using dalam bentuk
await using (ResourceType resource = «expression» ) «statement»
secara semantik setara dengan rumusan yang ditunjukkan di bawah ini dengan IAsyncDisposable alih-alih IDisposable, DisposeAsync alih-alih Dispose, dan yang Task dikembalikan dari DisposeAsync adalah awaited:
await using (ResourceType resource = «expression» ) «statement»
secara semantik setara dengan
{
ResourceType resource = «expression»;
try
{
«statement»;
}
finally
{
IAsyncDisposable d = (IAsyncDisposable)resource;
if (d != null)
{
await d.DisposeAsync();
}
}
}
Catatan: Setiap pernyataan lompat (§13.10) dalam embedded_statement harus sesuai dengan bentuk pernyataan yang
usingdiperluas. catatan akhir
13.14.2 Menggunakan deklarasi
Varian syntactic dari pernyataan penggunaan adalah menggunakan deklarasi.
using_declaration
: 'await'? 'using' non_ref_local_variable_declaration ';' statement_list?
;
Deklarasi penggunaan memiliki semantik yang sama dengan, dan dapat ditulis ulang sebagai, bentuk akuisisi sumber daya yang sesuai dari pernyataan penggunaan (§13.14.1), sebagai berikut:
using «local_variable_type» «local_variable_declarators»
// statements
secara semantik setara dengan
using («local_variable_type» «local_variable_declarators»)
{
// statements
}
dan
await using «local_variable_type» «local_variable_declarators»
// statements
secara semantik setara dengan
await using («local_variable_type» «local_variable_declarators»)
{
// statements
}
Masa pakai variabel yang dideklarasikan dalam non_ref_local_variable_declaration meluas ke akhir cakupan di mana variabel dideklarasikan. Variabel-variabel tersebut kemudian dibuang dalam urutan terbalik di mana variabel tersebut dideklarasikan.
static void M()
{
using FileStream f1 = new FileStream(...);
using FileStream f2 = new FileStream(...), f3 = new FileStream(...);
...
// Dispose f3
// Dispose f2
// Dispose f1
}
Deklarasi menggunakan tidak akan muncul langsung di dalam switch_label, tetapi, sebaliknya, mungkin berada dalam blok di dalam switch_label.
13.15 Pernyataan hasil
Pernyataan yield digunakan dalam blok iterator (§13,3) untuk menghasilkan nilai ke objek enumerator (§15.15.5) atau objek enumerasi (§15.15.6) dari iterator atau untuk menandakan akhir perulangan.
yield_statement
: 'yield' 'return' expression ';'
| 'yield' 'break' ';'
;
yield adalah kata kunci kontekstual (§6.4.4) dan memiliki arti khusus hanya ketika digunakan segera sebelum kata return kunci atau break .
Ada beberapa batasan di mana pernyataan dapat muncul, seperti yang yield dijelaskan dalam hal berikut.
- Ini adalah kesalahan waktu kompilasi agar
yieldpernyataan (dari salah satu formulir) muncul di luar method_body, operator_body, atau accessor_body. - Ini adalah kesalahan waktu kompilasi agar
yieldpernyataan (dari salah satu bentuk) muncul di dalam fungsi anonim. - Ini adalah kesalahan waktu kompilasi agar
yieldpernyataan (dari salah satu formulir) muncul dalamfinallyklausultrypernyataan. - Ini adalah kesalahan waktu kompilasi agar
yield returnpernyataan muncul di mana saja dalamtrypernyataan yang berisi catch_clauses apa pun.
Contoh: Contoh berikut menunjukkan beberapa penggunaan pernyataan yang
yieldvalid dan tidak valid.delegate IEnumerable<int> D(); IEnumerator<int> GetEnumerator() { try { yield return 1; // Ok yield break; // Ok } finally { yield return 2; // Error, yield in finally yield break; // Error, yield in finally } try { yield return 3; // Error, yield return in try/catch yield break; // Ok } catch { yield return 4; // Error, yield return in try/catch yield break; // Ok } D d = delegate { yield return 5; // Error, yield in an anonymous function }; } int MyMethod() { yield return 1; // Error, wrong return type for an iterator block }contoh akhir
Konversi implisit (§10,2) harus ada dari jenis ekspresi dalam yield return pernyataan ke jenis hasil (§15.15.4) dari iterator.
Pernyataan yield return dijalankan sebagai berikut:
- Ekspresi yang diberikan dalam pernyataan dievaluasi, dikonversi secara implisit ke jenis hasil, dan ditetapkan ke
Currentproperti objek enumerator. - Eksekusi blok iterator ditangguhkan.
yield returnJika pernyataan berada dalam satu atau beberapatryblok, blok terkaitfinallytidak dijalankan saat ini. - Metode
MoveNextobjek enumerator kembalitrueke pemanggilnya, menunjukkan bahwa objek enumerator berhasil dimajukan ke item berikutnya.
Panggilan berikutnya ke metode objek MoveNext enumerator melanjutkan eksekusi blok iterator dari tempat terakhir ditangguhkan.
Pernyataan yield break dijalankan sebagai berikut:
-
yield breakJika pernyataan diapit oleh satu atau beberapatryblok dengan blok terkaitfinally, kontrol awalnya ditransfer kefinallyblok pernyataan terdahulutry. Kapan dan jika kontrol mencapai titikfinallyakhir blok, kontrol ditransfer kefinallyblok pernyataan penutuptryberikutnya. Proses ini diulang hinggafinallyblok semua pernyataan penutuptrytelah dijalankan. - Kontrol dikembalikan ke pemanggil blok iterator. Ini adalah
MoveNextmetode atauDisposemetode objek enumerator.
yield break Karena pernyataan secara tanpa syarat mentransfer kontrol di tempat lain, titik yield break akhir pernyataan tidak pernah dapat dijangkau.
ECMA C# draft specification