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 (§23.2) dan fixed_statement (§23.7) hanya tersedia dalam kode yang tidak aman (§23).
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
if
pernyataan memerlukan embedded_statement daripada pernyataan untuk cabangnyaif
. Jika kode ini diizinkan, maka variabeli
akan dideklarasikan, tetapi tidak pernah dapat digunakan. Namun, perhatikan bahwa dengan menempatkani
deklarasi 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,23) 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
if
pernyataan adalah ekspresi konstan==
karena kedua operan operator adalah konstanta. Karena ekspresi konstan dievaluasi pada waktu kompilasi, menghasilkan nilaifalse
,Console.WriteLine
pemanggilan dianggap tidak dapat dijangkau. Namun, jikai
diubah menjadi variabel lokalvoid F() { int i = 1; if (i == 2) Console.WriteLine("reachable"); }
pemanggilan
Console.WriteLine
dianggap 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.WriteLine
ditentukan sebagai berikut:
- Pernyataan ekspresi pertama
Console.WriteLine
dapat dijangkau karena blokF
metode dapat dijangkau (§13.3).- Titik akhir pernyataan ekspresi pertama
Console.WriteLine
dapat dijangkau karena pernyataan tersebut dapat dijangkau (§13,7 dan §13,3).- Pernyataan
if
dapat dijangkau karena titik akhir pernyataan ekspresi pertamaConsole.WriteLine
dapat dijangkau (§13,7 dan §13,3).- Pernyataan ekspresi kedua
Console.WriteLine
dapat dijangkau karena ekspresi Boolean dariif
pernyataan tidak memiliki nilaifalse
konstanta .contoh akhir
Ada dua situasi di mana itu adalah kesalahan waktu kompilasi agar titik akhir pernyataan dapat dijangkau:
switch
Karena 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 bahwabreak
pernyataan 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
return
pernyataan 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
return
pernyataan muncul di blok iterator (tetapiyield return
pernyataan diizinkan). - Ini adalah kesalahan waktu kompilasi untuk blok iterator untuk berisi konteks yang tidak aman (§23.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
while
pernyataan 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
goto
pernyataan 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
var
dalam cakupan dan input cocok dengan implicitly_typed_local_variable_declaration maka dipilih; - Jika tidak, jika jenis bernama
var
berada 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 ref
awal 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 itself
contoh 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
;
Explicity_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.21.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
;
variable_reference inisialisasi harus memiliki jenis jenis dan memenuhi persyaratan yang sama seperti untuk penugasan ref (§12.21.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,23) 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 (§23,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 (§23.2), fungsi lokal dapat 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
this
dangoto
mencerminkan aturan untuk fungsi anonim dalam §12.19.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
L
dapat dijangkau meskipun titikL
awal tidak dapat dijangkau. Karena titikL
awal tidak dapat dijangkau, pernyataan setelah titikL
akhir 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
this
ataubase
atau 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 + y
danx == 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
if
formulirif (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.24) 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 titikif
akhir pernyataan. - Jika ekspresi Boolean menghasilkan
false
dan jika adaelse
bagian, kontrol ditransfer ke pernyataan tersemat kedua. Kapan dan jika kontrol mencapai titik akhir pernyataan tersebut, kontrol ditransfer ke titikif
akhir pernyataan. - Jika ekspresi Boolean menghasilkan
false
dan jika bagianelse
tidak ada, kontrol ditransfer ke titikif
akhir pernyataan.
Pernyataan pertama yang disematkan dari pernyataan if
dapat dijangkau jika if
pernyataan dapat dijangkau dan ekspresi Boolean tidak memiliki nilai false
konstanta .
Pernyataan pernyataan kedua yang if
disematkan, jika ada, dapat dijangkau jika if
pernyataan dapat dijangkau dan ekspresi Boolean tidak memiliki nilai true
konstanta .
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 true
konstanta .
13.8.3 Pernyataan pengalihan
Pernyataan switch
memilih untuk eksekusi daftar pernyataan yang memiliki label sakelar terkait yang sesuai dengan nilai ekspresi pengalihan.
switch_statement
: 'switch' '(' expression ')' switch_block
;
switch_block
: '{' switch_section* '}'
;
switch_section
: switch_label+ statement_list
;
switch_label
: 'case' pattern case_guard? ':'
| 'default' ':'
;
case_guard
: 'when' expression
;
switch_statement terdiri dari kata kunci switch
, diikuti oleh ekspresi yang dikurung (disebut ekspresi pengalihan), 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 ekspresi pengalihan 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.
Jenis pernyataan yang switch
mengatur ditetapkan oleh ekspresi pengalihan.
- Jika jenis ekspresi pengalihan adalah
sbyte
, ,byte
,short
,ushort
int
uint
long
ulong
,char
,bool
,string
, , atau enum_type, atau jika itu adalah jenis nilai nullable yang sesuai dengan salah satu jenis ini, maka itu adalah jenisswitch
pernyataan yang mengatur. - Jika tidak, jika persis satu konversi implisit yang ditentukan pengguna ada dari jenis ekspresi pengalihan ke salah satu kemungkinan jenis tata kelola berikut:
sbyte
, ,byte
,short
ushort
int
uint
long
ulong
char
,string
atau, jenis nilai nullable yang sesuai dengan salah satu jenis tersebut, maka jenis yang dikonversi adalah jenisswitch
pernyataan yang mengatur. - Jika tidak, jenis pernyataan yang
switch
mengatur adalah jenis ekspresi pengalihan. 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:
- Ekspresi pengalihan dievaluasi dan dikonversi ke jenis yang mengatur.
- Kontrol ditransfer sesuai dengan nilai ekspresi sakelar yang dikonversi:
- Pola pertama leksikal dalam kumpulan
case
label dalam pernyataan yang samaswitch
yang cocok dengan nilai ekspresi pengalihan, dan di mana ekspresi penjaga tidak ada atau dievaluasi ke true, menyebabkan kontrol ditransfer ke daftar pernyataan mengikuti label yang cocokcase
. - Jika tidak, jika
default
label ada, kontrol akan ditransfer ke daftar pernyataan setelahdefault
label. - Jika tidak, kontrol ditransfer ke titik
switch
akhir 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 case
ataugoto default
pernyataan 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
break
pernyataan dihilangkan secara tidak sengaja. Misalnya, bagian pernyataan diswitch
atas 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
break
pernyataan , ,goto case
ataugoto default
, tetapi konstruksi apa pun yang merender titik akhir daftar pernyataan yang tidak dapat dijangkau diizinkan. Misalnya, pernyataan yangwhile
dikendalikan oleh ekspresitrue
Boolean diketahui tidak pernah mencapai titik akhirnya. Demikian juga, pernyataanthrow
ataureturn
selalu 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
switch
mengatur 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.12.8),
switch
pernyataan peka huruf besar/kecil dan akan menjalankan bagian sakelar tertentu hanya jika string ekspresi pengalihan sama persis dengancase
konstanta label. catatan akhir Saat jenis pernyataan yangswitch
mengatur adalahstring
atau jenis nilai nullable, nilainull
diizinkan sebagaicase
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:
- Ekspresi pengalihan adalah nilai konstanta dan
- label adalah
case
pola yang akan cocok (§11.2.1) nilai tersebut, dan penjaga label tidak ada atau bukan ekspresi konstan dengan nilai false; atau - ini adalah
default
label, 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
- Ekspresi pengalihan bukan nilai konstanta dan baik
- label adalah
case
tanpa penjaga atau dengan penjaga yang nilainya bukan false konstanta; atau - ini adalah
default
label 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 case
yang 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
switch
pernyataan yang dapat dijangkaubreak
yang keluar dariswitch
pernyataan. - Tidak ada
default
label yang ada dan baik- Ekspresi pengalihan 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 switch.
- Ekspresi pengalih adalah nilai non-konstanta dari jenis yang dapat diubah ke null, 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
. - Ekspresi pengalihan adalah nilai konstanta dan tanpa
case
label tanpa penjaga atau yang penjaganya adalah true konstanta akan cocok dengan nilai tersebut.
Contoh: Kode berikut menunjukkan penggunaan klausa yang
when
singkat: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.24) dievaluasi.
- Jika ekspresi Boolean menghasilkan
true
, kontrol ditransfer ke pernyataan yang disematkan. Kapan dan jika kontrol mencapai titik akhir pernyataan yang disematkan (mungkin dari eksekusicontinue
pernyataan), kontrol ditransfer ke awalwhile
pernyataan. - Jika ekspresi Boolean menghasilkan
false
, kontrol ditransfer ke titikwhile
akhir 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 false
konstanta .
Titik while
akhir pernyataan dapat dijangkau jika setidaknya salah satu hal berikut ini benar:
- Pernyataan berisi
while
pernyataan yang dapat dijangkaubreak
yang keluar dariwhile
pernyataan. - Pernyataan
while
dapat dijangkau dan ekspresi Boolean tidak memiliki nilaitrue
konstanta .
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
continue
pernyataan), boolean_expression (§12,24) dievaluasi. Jika ekspresi Boolean menghasilkantrue
, kontrol ditransfer ke awaldo
pernyataan. Jika tidak, kontrol ditransfer ke titikdo
akhir 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
do
pernyataan yang dapat dijangkaubreak
yang keluar darido
pernyataan. - Titik akhir pernyataan yang disematkan dapat dijangkau dan ekspresi Boolean tidak memiliki nilai
true
konstanta .
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.24).
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 eksekusicontinue
pernyataan), 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 titikfor
akhir 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
for
dapat dijangkau dan tidak ada for_condition yang ada. - Pernyataan
for
dapat dijangkau dan for_condition ada dan tidak memiliki nilaifalse
konstanta .
Titik for
akhir pernyataan dapat dijangkau jika setidaknya salah satu hal berikut ini benar:
- Pernyataan berisi
for
pernyataan yang dapat dijangkaubreak
yang keluar darifor
pernyataan. - Pernyataan
for
dapat dijangkau dan for_condition ada dan tidak memiliki nilaitrue
konstanta .
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 ref
readonly
, 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, jenis enumerator, dan jenis iterasi ekspresi. Pemrosesan untuk foreach
pernyataan dirinci dalam §13.9.5.2 dan proses untuk await foreach
dirinci dalam §13.9.5.3.
Catatan: Jika ekspresi memiliki nilai
null
, makaSystem.NullReferenceException
akan terjadi saat run-time. catatan akhir
Implementasi diizinkan untuk menerapkan foreach_statement tertentu secara berbeda; misalnya, karena alasan performa, selama perilaku konsisten dengan ekspansi di atas.
13.9.5.2 Foreach sinkron
Pemrosesan waktu foreach
kompilasi pernyataan terlebih dahulu menentukan jenis koleksi, jenis enumerator, dan jenis iterasi ekspresi. Penentuan ini berlanjut sebagai berikut:
- Jika jenis
X
ekspresi adalah jenis array, maka ada konversi referensi implisit dari X keIEnumerable
antarmuka (karenaSystem.Array
mengimplementasikan antarmuka ini). Jenis koleksi adalahIEnumerable
antarmuka, jenis enumerator adalahIEnumerator
antarmuka dan jenis iterasi adalah jenis elemen dari jenisX
array . - Jika jenis
X
ekspresi maka ada konversi implisit dari ekspresi kedynamic
antarmuka (§10.2.10).IEnumerable
Jenis koleksi adalahIEnumerable
antarmuka dan jenis enumerator adalahIEnumerator
antarmuka.var
Jika pengidentifikasi diberikan sebagai local_variable_type maka jenis iterasi adalahdynamic
, jika tidak, itu adalahobject
. - Jika tidak, tentukan apakah jenis
X
memiliki metode yang sesuaiGetEnumerator
:- Lakukan pencarian anggota pada jenis
X
dengan pengidentifikasiGetEnumerator
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 bawah ini. 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
E
GetEnumerator
pengembalian metode bukan kelas, struct atau jenis antarmuka, kesalahan dihasilkan dan tidak ada langkah lebih lanjut yang diambil. - Pencarian anggota dilakukan pada
E
dengan pengidentifikasiCurrent
dan 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, kesalahan dihasilkan dan tidak ada langkah lebih lanjut yang diambil. - Pencarian anggota dilakukan pada
E
dengan pengidentifikasiMoveNext
dan tidak ada argumen jenis. Jika pencarian anggota tidak menghasilkan kecocokan, hasilnya adalah kesalahan, atau hasilnya adalah apa pun kecuali grup metode, kesalahan dihasilkan dan tidak ada langkah lebih lanjut yang diambil. - Resolusi kelebihan beban dilakukan pada grup metode dengan daftar argumen kosong. Jika resolusi kelebihan beban tidak menghasilkan metode yang berlaku, menghasilkan ambiguitas, atau menghasilkan satu metode terbaik tetapi metode tersebut statis atau tidak publik, atau jenis pengembaliannya bukan
bool
, kesalahan dihasilkan, dan tidak ada langkah lebih lanjut yang diambil. - Jenis koleksi adalah
X
, jenis enumerator adalahE
, dan jenis iterasi adalah jenisCurrent
properti . PropertiCurrent
dapat mencakup pengubahref
, dalam hal ini, ekspresi yang dikembalikan adalah variable_reference (§9,5) yang secara opsional baca-saja.
- Lakukan pencarian anggota pada jenis
- Jika tidak, periksa antarmuka yang dapat dijumlahkan:
- Jika di antara semua jenis
Tᵢ
yang ada konversi implisit dariX
keIEnumerable<Tᵢ>
, ada jenisT
unik seperti itu bukanT
dan untuk semua yangdynamic
lainTᵢ
ada konversi implisit dariIEnumerable<T>
keIEnumerable<Tᵢ>
, maka jenis koleksi adalah antarmukaIEnumerable<T>
, jenis enumerator adalah antarmukaIEnumerator<T>
, dan jenis iterasi adalahT
. - Jika tidak, jika ada lebih dari satu jenis
T
tersebut , maka kesalahan dihasilkan dan tidak ada langkah lebih lanjut yang diambil. - Jika tidak, jika ada konversi implisit dari
X
keSystem.Collections.IEnumerable
antarmuka, maka jenis koleksi adalah antarmuka ini, jenis enumerator adalah antarmukaSystem.Collections.IEnumerator
, dan jenis iterasi adalahobject
. - Jika tidak, kesalahan dihasilkan, dan tidak ada langkah lebih lanjut yang diambil.
- Jika di antara semua jenis
Langkah-langkah di atas, jika berhasil, secara tidak ambigu menghasilkan jenis koleksi, jenis C
E
enumerator dan jenis T
iterasi , , ref T
atau ref readonly T
. 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.21.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.19.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
v
dalam bentuk yang diperluas dideklarasikan di luarwhile
perulangan, itu akan dibagikan di antara semua iterasi, dan nilainya setelahfor
perulangan akan menjadi nilai akhir,13
, yang merupakan pemanggilanf
akan dicetak. Sebaliknya, karena setiap iterasi memiliki variabelnyav
sendiri , yang ditangkap olehf
dalam iterasi pertama akan terus menyimpan nilai7
, yaitu apa yang akan dicetak. (Perhatikan bahwa versi C# sebelumnya yang dinyatakanv
di luar perulanganwhile
.)contoh akhir
finally
Isi blok dibangun sesuai dengan langkah-langkah berikut:
Jika ada konversi implisit dari
E
keSystem.IDisposable
antarmuka, makaJika
E
adalah jenis nilai yang tidak dapat diubah ke null, makafinally
klausa diperluas ke semantik yang setara dengan:finally { ((System.IDisposable)e).Dispose(); }
Jika tidak,
finally
klausul diperluas ke semantik yang setara dengan:finally { System.IDisposable d = e as System.IDisposable; if (d != null) { d.Dispose(); } }
kecuali bahwa jika
E
adalah jenis nilai, atau parameter jenis yang dibuat ke jenis nilai, maka konversi kee
System.IDisposable
tidak akan menyebabkan tinju terjadi.
Jika tidak, jika
E
adalah jenis tertutup,finally
klausul diperluas ke blok kosong:finally {}
Jika tidak,
finally
klausa 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.9
contoh akhir
Contoh: Dalam contoh berikut
int[] numbers = { 1, 3, 5, 7, 9 }; foreach (var n in numbers) { Console.WriteLine(n); }
jenis
n
disimpulkan menjadiint
, jenis iterasi darinumbers
.contoh akhir
13.9.5.3 menunggu foreach
Pemrosesan waktu foreach
kompilasi pernyataan terlebih dahulu menentukan jenis koleksi, jenis enumerator, dan jenis iterasi ekspresi. Pemrosesan untuk foreach
pernyataan dirinci dalam §13.9.5.2 dan proses untuk await foreach
dirinci dalam §13.9.5.3.
Penentuan ini berlanjut sebagai berikut:
- Tentukan apakah jenis
X
memiliki metode yang sesuaiGetAsyncEnumerator
:- Lakukan pencarian anggota pada jenis
X
dengan pengidentifikasiGetAsyncEnumerator
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 bawah ini. 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
E
GetAsyncEnumerator
pengembalian metode bukan kelas, struct atau jenis antarmuka, kesalahan dihasilkan dan tidak ada langkah lebih lanjut yang diambil. - Pencarian anggota dilakukan pada
E
dengan pengidentifikasiCurrent
dan 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, kesalahan dihasilkan dan tidak ada langkah lebih lanjut yang diambil. - Pencarian anggota dilakukan pada
E
dengan pengidentifikasiMoveNextAsync
dan tidak ada argumen jenis. Jika pencarian anggota tidak menghasilkan kecocokan, hasilnya adalah kesalahan, atau hasilnya adalah apa pun kecuali grup metode, kesalahan dihasilkan dan tidak ada langkah lebih lanjut yang diambil. - Resolusi kelebihan beban dilakukan pada grup metode dengan daftar argumen kosong. Jika resolusi kelebihan beban tidak menghasilkan metode yang berlaku, menghasilkan ambiguitas, atau menghasilkan satu metode terbaik tetapi metode tersebut statis atau bukan publik, atau jenis pengembaliannya tidak dapat ditunggu (§12.9.8.2) di mana await_expression diklasifikasikan sebagai
bool
(§12.9.8.3), kesalahan dihasilkan, dan tidak ada langkah lebih lanjut yang diambil. - Jenis koleksi adalah
X
, jenis enumerator adalahE
, dan jenis iterasi adalah jenisCurrent
properti .
- Lakukan pencarian anggota pada jenis
- Jika tidak, periksa antarmuka asinkron yang dapat dijumlahkan:
- Jika di antara semua jenis
Tᵢ
yang ada konversi implisit dariX
keIAsyncEnumerable<Tᵢ>
, ada jenisT
unik seperti itu bukanT
dan untuk semua yangdynamic
lainTᵢ
ada konversi implisit dariIAsyncEnumerable<T>
keIAsyncEnumerable<Tᵢ>
, maka jenis koleksi adalah antarmukaIAsyncEnumerable<T>
, jenis enumerator adalah antarmukaIAsyncEnumerator<T>
, dan jenis iterasi adalahT
. - Jika tidak, jika ada lebih dari satu jenis
T
tersebut , maka kesalahan dihasilkan dan tidak ada langkah lebih lanjut yang diambil. - Jika tidak, kesalahan dihasilkan, dan tidak ada langkah lebih lanjut yang diambil.
- Jika di antara semua jenis
Langkah-langkah di atas, jika berhasil, secara tidak ambigu menghasilkan jenis koleksi C
, jenis enumerator E
dan jenis iterasi T
. Pernyataan await foreach
dalam bentuk
await foreach (V v in x) «embedded_statement»
kemudian setara dengan:
{
E e = ((C)(x)).GetAsyncEnumerator();
try
{
while (await e.MoveNextAsync())
{
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 await foreach
pernyataan), kesalahan dihasilkan dan tidak ada langkah lebih lanjut yang diambil.
Enumerator asinkron dapat secara opsional mengekspos sebuah metode DisposeAsync
yang dapat dipanggil tanpa argumen dan mengembalikan sesuatu yang dapat diawait
dan yang GetResult()
mengembalikan void
.
Pernyataan foreach
formulir
await foreach (T item in enumerable) «embedded_statement»
diperluas ke:
var enumerator = enumerable.GetAsyncEnumerator();
try
{
while (await enumerator.MoveNextAsync())
{
T item = enumerator.Current;
«embedded_statement»
}
}
finally
{
await enumerator.DisposeAsync(); // omitted, along with the try/finally,
// if the enumerator doesn't expose DisposeAsync
}
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
finally
terkait dengan duatry
pernyataan dijalankan sebelum kontrol ditransfer ke target pernyataan lompat. Output yang dihasilkan adalah sebagai berikut:Before break Innermost finally block Outermost finally block After break
contoh akhir
13.10.2 Pernyataan pembobolan
Pernyataan break
keluar dari pernyataan penutup terdekat switch
, , while
, do
for
, atau foreach
.
break_statement
: 'break' ';'
;
Target break
pernyataan adalah titik akhir dari switch
pernyataan penutup terdekat , , while
, do
for
, atau foreach
.
break
Jika pernyataan tidak diapit oleh switch
, , while
, do
, for
atau foreach
pernyataan, kesalahan waktu kompilasi terjadi.
Ketika beberapa switch
pernyataan , 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:
-
break
Jika pernyataan keluar dari satu atau beberapatry
blok dengan blok terkaitfinally
, kontrol awalnya ditransfer kefinally
blok pernyataan terdahulutry
. Kapan dan jika kontrol mencapai titikfinally
akhir blok, kontrol ditransfer kefinally
blok pernyataan penutuptry
berikutnya. Proses ini diulang sampaifinally
blok semua pernyataan intervensitry
telah dijalankan. - Kontrol ditransfer ke target
break
pernyataan.
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
, do
atau for
terdekatforeach
.
continue_statement
: 'continue' ';'
;
Target continue
pernyataan adalah titik akhir dari pernyataan yang disematkan dari pernyataan penutup terdekat while
, , do
, for
atau foreach
.
continue
Jika pernyataan tidak diapit oleh while
pernyataan , , do
, for
atau foreach
, terjadi kesalahan waktu kompilasi.
Ketika beberapa while
pernyataan , 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:
-
continue
Jika pernyataan keluar dari satu atau beberapatry
blok dengan blok terkaitfinally
, kontrol awalnya ditransfer kefinally
blok pernyataan terdahulutry
. Kapan dan jika kontrol mencapai titikfinally
akhir blok, kontrol ditransfer kefinally
blok pernyataan penutuptry
berikutnya. Proses ini diulang sampaifinally
blok semua pernyataan intervensitry
telah dijalankan. - Kontrol ditransfer ke target
continue
pernyataan.
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 goto
pernyataan 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
goto
pernyataan 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}]"); } } }
goto
pernyataan 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:
-
goto
Jika pernyataan keluar dari satu atau beberapatry
blok dengan blok terkaitfinally
, kontrol awalnya ditransfer kefinally
blok pernyataan terdahulutry
. Kapan dan jika kontrol mencapai titikfinally
akhir blok, kontrol ditransfer kefinally
blok pernyataan penutuptry
berikutnya. Proses ini diulang sampaifinally
blok semua pernyataan intervensitry
telah dijalankan. - Kontrol ditransfer ke target
goto
pernyataan.
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 ref
ekspresi 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 void
pengembalian 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,19), 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. -
return
Jika pernyataan diapit oleh satu atau beberapatry
blokcatch
dengan blok terkaitfinally
, kontrol awalnya ditransfer kefinally
blok pernyataan terdahulutry
. Kapan dan jika kontrol mencapai titikfinally
akhir blok, kontrol ditransfer kefinally
blok pernyataan penutuptry
berikutnya. Proses ini diulang hinggafinally
blok semua pernyataan penutuptry
telah 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 (§21.4).
Dalam anggota fungsi saat ini, setiap
try
pernyataan yang mencakup titik lemparan diperiksa. Untuk setiap pernyataanS
, dimulai dengan pernyataan terdahulutry
dan diakhiri dengan pernyataan terluartry
, langkah-langkah berikut dievaluasi:-
try
Jika blokS
mencakup titik lemparan dan jikaS
memiliki satu atau beberapacatch
klausul,catch
klausa diperiksa dalam urutan penampilan untuk menemukan handler yang cocok untuk pengecualian. Klausa pertamacatch
yang menentukan jenisT
pengecualian (atau parameter jenis yang pada run-time menunjukkan jenisT
pengecualian ) sehingga jenisE
run-time yang berasal dianggapT
cocok. Jika klausa berisi filter pengecualian, objek pengecualian ditetapkan ke variabel pengecualian, dan filter pengecualian dievaluasi.catch
Saat klausa berisi filter pengecualian,catch
klausa tersebut dianggap cocok jika filter pengecualian dievaluasi ketrue
. Klausa umumcatch
(§13.11) dianggap cocok untuk jenis pengecualian apa pun. Jika klausul yangcatch
cocok ditemukan, penyebaran pengecualian diselesaikan dengan mentransfer kontrol ke blokcatch
klausa tersebut. - Jika tidak, jika
try
blok ataucatch
blokS
menutupi titik lemparan dan jikaS
memilikifinally
blok, kontrol ditransfer kefinally
blok.finally
Jika blok melemparkan pengecualian lain, pemrosesan pengecualian saat ini dihentikan. Jika tidak, ketika kontrol mencapai titikfinally
akhir 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 umumcatch
mungkin digunakan untuk menangkap pengecualian tersebut. Dengan demikian, klausul umumcatch
secara 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
F
ini 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: G
Jika blok pertama
catch
telah dilemparkane
alih-alih menumbuhkan kembali pengecualian saat ini, output yang dihasilkan adalah sebagai berikut:Exception in F: G Exception in Main: F
contoh akhir
Ini adalah kesalahan waktu kompilasi untuk break
pernyataan , , continue
atau goto
untuk mentransfer kontrol keluar dari finally
blok.
break
Ketika pernyataan , , continue
atau 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 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 break
pernyataan , , continue
, goto
atau 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
Method
melemparkan pengecualian. Tindakan pertama adalah memeriksa klausa penutupcatch
, menjalankan filter pengecualian apa pun. Kemudian,finally
klausul dalamMethod
dijalankan sebelum kontrol ditransfer ke klausul pencocokancatch
penutup. Output yang dihasilkan adalah:Filter Finally Catch
contoh 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
try
akhir blok dapat dijangkau atau titik akhir setidaknya satucatch
blok dapat dijangkau. - Jika ada
finally
blok, titikfinally
akhir 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
Pernyataan ini using
memperoleh satu atau beberapa sumber daya, menjalankan pernyataan, lalu membuang sumber daya.
using_statement
: 'using' '(' resource_acquisition ')' embedded_statement
;
resource_acquisition
: local_variable_declaration
| expression
;
Sumber daya adalah kelas atau struct yang mengimplementasikan System.IDisposable
antarmuka (IAsyncDisposable
untuk aliran asinkron), yang mencakup satu metode tanpa parameter bernama Dispose
(DisposeAsync
untuk aliran asinkron). Kode yang menggunakan sumber daya dapat memanggil Dispose
untuk menunjukkan bahwa sumber daya tidak lagi diperlukan.
Jika bentuk resource_acquisition adalah local_variable_declaration, maka jenis local_variable_declaration haruslah salah satu dari dynamic
atau jenis yang dapat dikonversi secara implisit menjadi System.IDisposable
(IAsyncDisposable
untuk aliran asinkron). Jika bentuk resource_acquisition adalah ekspresi maka ekspresi ini akan secara implisit dapat dikonversi ke System.IDisposable
(IAsyncDisposable
untuk aliran asinkron).
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.
null
Jika sumber daya diperoleh, maka tidak ada panggilan ke Dispose
(DisposeAsync
untuk aliran asinkron) 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
(IAsyncDisposable
untuk aliran asinkron) 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 ekspansi. Ketika ResourceType
adalah jenis nilai yang tidak dapat diubah ke null atau parameter jenis dengan batasan jenis nilai (§15.2.5), ekspansi secara semantik setara dengan
{
ResourceType resource = «expression»;
try
{
«statement»;
}
finally
{
((IDisposable)resource).Dispose();
}
}
Kecuali bahwa para pemeran resource
System.IDisposable
untuk tidak menyebabkan tinju terjadi.
Jika tidak, kapan ResourceType
adalah dynamic
, ekspansinya adalah
{
ResourceType resource = «expression»;
IDisposable d = resource;
try
{
«statement»;
}
finally
{
if (d != null)
{
d.Dispose();
}
}
}
Jika tidak, ekspansinya adalah
{
ResourceType resource = «expression»;
try
{
«statement»;
}
finally
{
IDisposable d = (IDisposable)resource;
if (d != null)
{
d.Dispose();
}
}
}
Dalam ekspansi apa pun, resource
variabel bersifat baca-saja dalam pernyataan yang disematkan, dan d
variabel tidak dapat diakses, dan tidak terlihat, pernyataan yang disematkan.
Implementasi diizinkan untuk menerapkan using_statement tertentu secara berbeda, misalnya, untuk alasan performa, selama perilaku konsisten dengan ekspansi di atas.
Pernyataan using
formulir:
using («expression») «statement»
memiliki tiga kemungkinan ekspansi yang sama. Dalam hal ResourceType
ini secara implisit adalah jenis ekspresi waktu kompilasi, jika memilikinya. Jika tidak, antarmuka IDisposable
(IAsyncDisposable
untuk aliran asinkron) itu sendiri digunakan sebagai ResourceType
. Variabel resource
tidak dapat diakses, dan tidak terlihat, pernyataan yang disematkan.
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); } } } }
TextWriter
Karena kelas danTextReader
mengimplementasikanIDisposable
antarmuka, contoh dapat menggunakanusing
pernyataan untuk memastikan bahwa file yang mendasar ditutup dengan benar setelah operasi tulis atau baca.contoh akhir
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
yield
pernyataan (dari salah satu formulir) muncul di luar method_body, operator_body, atau accessor_body. - Ini adalah kesalahan waktu kompilasi agar
yield
pernyataan (dari salah satu bentuk) muncul di dalam fungsi anonim. - Ini adalah kesalahan waktu kompilasi agar
yield
pernyataan (dari salah satu formulir) muncul dalamfinally
klausultry
pernyataan. - Ini adalah kesalahan waktu kompilasi agar
yield return
pernyataan muncul di mana saja dalamtry
pernyataan yang berisi catch_clauses apa pun.
Contoh: Contoh berikut menunjukkan beberapa penggunaan pernyataan yang
yield
valid 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
Current
properti objek enumerator. - Eksekusi blok iterator ditangguhkan.
yield return
Jika pernyataan berada dalam satu atau beberapatry
blok, blok terkaitfinally
tidak dijalankan saat ini. - Metode
MoveNext
objek enumerator kembalitrue
ke 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 break
Jika pernyataan diapit oleh satu atau beberapatry
blok dengan blok terkaitfinally
, kontrol awalnya ditransfer kefinally
blok pernyataan terdahulutry
. Kapan dan jika kontrol mencapai titikfinally
akhir blok, kontrol ditransfer kefinally
blok pernyataan penutuptry
berikutnya. Proses ini diulang hinggafinally
blok semua pernyataan penutuptry
telah dijalankan. - Kontrol dikembalikan ke pemanggil blok iterator. Ini adalah
MoveNext
metode atauDispose
metode 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