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.
23.1 Umum
Sebagian besar bahasa C# memungkinkan programmer menentukan informasi deklaratif tentang entitas yang ditentukan dalam program. Misalnya, aksesibilitas metode di kelas ditentukan dengan mendekorasinya dengan method_modifier, public, protectedinternal, dan private.
C# memungkinkan programmer untuk menciptakan jenis informasi deklaratif baru, yang disebut atributs. Programmer kemudian dapat melampirkan atribut ke berbagai entitas program, dan mengambil informasi atribut di lingkungan run-time.
Catatan: Misalnya, kerangka kerja mungkin menentukan
HelpAttributeatribut yang dapat ditempatkan pada elemen program tertentu (seperti kelas dan metode) untuk menyediakan pemetaan dari elemen program tersebut ke dokumentasi mereka. catatan akhir
Atribut didefinisikan melalui deklarasi kelas atribut (§23.2), yang dapat memiliki parameter posisi dan bernama (§23.2.3). Atribut dilampirkan ke entitas dalam program C# menggunakan spesifikasi atribut (§23.3), dan dapat diambil pada run-time sebagai instans atribut (§23.4).
23.2 Kelas atribut
23.2.1 Umum
Kelas yang berasal dari kelas System.Attributeabstrak , baik secara langsung maupun tidak langsung, adalah kelas atribut. Deklarasi kelas atribut mendefinisikan jenis atribut baru yang dapat ditempatkan pada entitas program. Menurut konvensi, kelas atribut dinamai dengan akhiran Attribute. Penggunaan atribut dapat mencakup atau menghilangkan akhiran ini.
Deklarasi kelas generik tidak boleh digunakan System.Attribute sebagai kelas dasar langsung atau tidak langsung.
Contoh:
public class B : Attribute {} public class C<T> : B {} // Error – generic cannot be an attributecontoh akhir
23.2.2 Penggunaan atribut
Atribut AttributeUsage (§23.5.2) digunakan untuk menjelaskan bagaimana kelas atribut dapat digunakan.
AttributeUsage memiliki parameter posisi (§23.2.3) yang memungkinkan kelas atribut untuk menentukan jenis entitas program tempatnya dapat digunakan.
Contoh: Contoh berikut mendefinisikan kelas atribut bernama
SimpleAttributeyang dapat ditempatkan pada class_declarationdan interface_declarations saja, dan menunjukkan beberapa penggunaanSimpleatribut.[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface)] public class SimpleAttribute : Attribute { ... } [Simple] class Class1 {...} [Simple] interface Interface1 {...}Meskipun atribut ini didefinisikan dengan nama
SimpleAttribute, ketika atribut ini digunakan,Attributeakhiran dapat dihilangkan, menghasilkan namaSimplependek . Dengan demikian, contoh di atas secara semantik setara dengan yang berikut ini[SimpleAttribute] class Class1 {...} [SimpleAttribute] interface Interface1 {...}contoh akhir
AttributeUsage memiliki parameter bernama (§23.2.3), yang disebut AllowMultiple, yang menunjukkan apakah atribut dapat ditentukan lebih dari sekali untuk entitas tertentu. Jika AllowMultiple untuk kelas atribut benar, kelas atribut tersebut adalah kelas atribut multi-penggunaan, dan dapat ditentukan lebih dari sekali pada entitas. Jika AllowMultiple untuk kelas atribut salah atau tidak ditentukan, kelas atribut tersebut adalah kelas atribut sekali pakai, dan dapat ditentukan paling banyak sekali pada entitas.
Contoh: Contoh berikut mendefinisikan kelas atribut multi-penggunaan bernama
AuthorAttributedan menunjukkan deklarasi kelas dengan dua penggunaanAuthoratribut:[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class AuthorAttribute : Attribute { public string Name { get; } public AuthorAttribute(string name) => Name = name; } [Author("Brian Kernighan"), Author("Dennis Ritchie")] class Class1 { ... }contoh akhir
AttributeUsage memiliki parameter bernama lain (§23.2.3), yang disebut Inherited, yang menunjukkan apakah atribut, ketika ditentukan pada kelas dasar, juga diwarisi oleh kelas yang berasal dari kelas dasar tersebut. Jika Inherited untuk kelas atribut benar, maka atribut tersebut diwariskan. Jika Inherited untuk kelas atribut salah, atribut tersebut tidak diwariskan. Jika tidak ditentukan, nilai defaultnya adalah true.
Kelas X atribut yang tidak memiliki atribut yang AttributeUsage melekat padanya, seperti dalam
class X : Attribute { ... }
setara dengan yang berikut ini:
[AttributeUsage(
AttributeTargets.All,
AllowMultiple = false,
Inherited = true)
]
class X : Attribute { ... }
23.2.3 Parameter posisi dan bernama
Kelas atribut dapat memiliki parameterposisi dan parameterbernama s. Setiap konstruktor instans publik untuk kelas atribut menentukan urutan parameter posisi yang valid untuk kelas atribut tersebut. Setiap bidang baca-tulis publik non-statis dan properti untuk kelas atribut menentukan parameter bernama untuk kelas atribut. Agar properti menentukan parameter bernama, properti tersebut harus memiliki aksesor get publik dan aksesor set publik.
Contoh: Contoh berikut mendefinisikan kelas atribut bernama
HelpAttributeyang memiliki satu parameter posisi,url, dan satu parameter bernama,Topic. Meskipun tidak statis dan publik, propertiUrltidak menentukan parameter bernama, karena tidak baca-tulis. Dua penggunaan atribut ini juga ditampilkan:[AttributeUsage(AttributeTargets.Class)] public class HelpAttribute : Attribute { public HelpAttribute(string url) // url is a positional parameter { ... } // Topic is a named parameter public string Topic { get; set; } public string Url { get; } } [Help("http://www.mycompany.com/xxx/Class1.htm")] class Class1 { } [Help("http://www.mycompany.com/xxx/Misc.htm", Topic ="Class2")] class Class2 { }contoh akhir
23.2.4 Jenis parameter atribut
Jenis parameter posisi dan bernama untuk kelas atribut terbatas pada jenis parameter atributs, yaitu:
- Salah satu jenis berikut:
bool, ,byte,char,double,float,intlong,sbyte, ,short,string,uint,ulong,ushort. - Jenis
object. - Jenis
System.Type. - Jenis enum.
- Array dimensi tunggal dari jenis di atas.
- Argumen konstruktor atau bidang publik yang tidak memiliki salah satu jenis ini, tidak boleh digunakan sebagai parameter posisi atau bernama dalam spesifikasi atribut.
23.3 Spesifikasi atribut
Aplikasi atribut yang ditentukan sebelumnya ke entitas program disebut spesifikasi atribut. Atribut adalah bagian dari informasi deklaratif tambahan yang ditentukan untuk entitas program. Atribut dapat ditentukan pada cakupan global (untuk menentukan atribut pada rakitan atau modul yang berisi) dan untuk type_declaration(§14,7), class_member_declarations (§15,3), interface_member_declarations (§19 4), struct_member_declaration(§16,3), enum_member_declarations (§20,2), accessor_declarations (§15,7,3), event_accessor_declarations (§15,8), elemen parameter_list(§15,6,2), dan elemen type_parameter_lists (§15.2.3).
Atribut ditentukan dalam bagian atributs. Bagian atribut terdiri dari sepasang kurung siku, yang mengelilingi daftar yang dipisahkan koma dari satu atau beberapa atribut. Urutan di mana atribut ditentukan dalam daftar seperti itu, dan urutan di mana bagian yang dilampirkan ke entitas program yang sama diatur, tidak signifikan. Misalnya, spesifikasi [A][B]atribut , , [B][A][A, B], dan [B, A] setara.
global_attributes
: global_attribute_section+
;
global_attribute_section
: '[' global_attribute_target_specifier attribute_list ']'
;
global_attribute_target_specifier
: global_attribute_target ':'
;
global_attribute_target
: identifier
;
attributes
: attribute_section+
;
attribute_section
: '[' attribute_target_specifier? attribute_list ']'
;
attribute_target_specifier
: attribute_target ':'
;
attribute_target
: identifier
| keyword
;
attribute_list
: attribute (',' attribute)* ','?
;
attribute
: attribute_name attribute_arguments?
;
attribute_name
: type_name
;
attribute_arguments
: '(' ')'
| '(' positional_argument_list (',' named_argument_list)? ')'
| '(' named_argument_list ')'
;
positional_argument_list
: positional_argument (',' positional_argument)*
;
positional_argument
: argument_name? attribute_argument_expression
;
named_argument_list
: named_argument (',' named_argument)*
;
named_argument
: identifier '=' attribute_argument_expression
;
attribute_argument_expression
: non_assignment_expression
;
Untuk global_attribute_target produksi, dan dalam teks di bawah ini, pengidentifikasi harus memiliki ejaan yang sama dengan atau , di mana kesetaraan assembly yang ditentukan dalam module. Untuk attribute_target produksi, dan dalam teks di bawah ini, pengidentifikasi harus memiliki ejaan yang tidak sama dengan assembly atau module, menggunakan definisi kesetaraan yang sama seperti di atas.
Atribut terdiri dari attribute_name dan daftar opsional argumen posisi dan bernama. Argumen posisi (jika ada) mendahului argumen bernama. Argumen posisi terdiri dari attribute_argument_expression; argumen bernama terdiri dari nama, diikuti dengan tanda sama dengan, diikuti oleh attribute_argument_expression, yang, bersama-sama, dibatasi oleh aturan yang sama dengan penugasan sederhana. Urutan argumen bernama tidak signifikan.
Catatan: Untuk kenyamanan, koma berikutnya diizinkan dalam global_attribute_section dan attribute_section, sama seperti yang diizinkan dalam array_initializer (§17,7). catatan akhir
attribute_name mengidentifikasi kelas atribut.
Saat atribut ditempatkan di tingkat global, global_attribute_target_specifier diperlukan. Saat global_attribute_target sama dengan:
-
assembly— targetnya adalah rakitan yang berisi -
module— targetnya adalah modul yang berisi
Tidak ada nilai lain untuk global_attribute_target yang diizinkan.
Nama attribute_target yang distandarkan adalah , , , event, fieldmethod, param, property, dan return.typetypevar Nama target ini hanya akan digunakan dalam konteks berikut:
-
event— sebuah peristiwa. -
field— bidang. Peristiwa seperti bidang (yaitu, satu tanpa pengakses) (§15.8.2) dan properti yang diimplementasikan secara otomatis (§15.7.4) juga dapat memiliki atribut dengan target ini. -
method— konstruktor, finalizer, metode, operator, properti mendapatkan dan mengatur aksesor, pengindeks mendapatkan dan mengatur aksesor, dan peristiwa menambahkan dan menghapus aksesor. Peristiwa seperti bidang (yaitu, satu tanpa aksesor) juga dapat memiliki atribut dengan target ini. -
param— pengakses set properti, pengakses set pengindeks, pengakses penambahan dan penghapusan peristiwa, dan parameter dalam konstruktor, metode, dan operator. -
property— properti dan pengindeks. -
return— delegasi, metode, operator, properti dapatkan aksesor, dan pengindeks mendapatkan aksesor. -
type— delegasi, kelas, struktur, enum, dan antarmuka. -
typevar— parameter jenis.
Konteks tertentu mengizinkan spesifikasi atribut pada lebih dari satu target. Program dapat secara eksplisit menentukan target dengan menyertakan attribute_target_specifier. Tanpa attribute_target_specifier default diterapkan, tetapi attribute_target_specifier dapat digunakan untuk mengafirmasi atau mengambil alih default. Konteks diselesaikan sebagai berikut:
- Untuk atribut pada deklarasi delegasi, target default adalah delegasi. Jika tidak, jika attribute_target sama dengan:
-
type— target adalah delegasi -
return— target adalah nilai pengembalian
-
- Untuk atribut pada deklarasi metode, target default adalah metode . Jika tidak, jika attribute_target sama dengan:
-
method— targetnya adalah metode -
return— target adalah nilai pengembalian
-
- Untuk atribut pada deklarasi operator, target default adalah operator. Jika tidak, jika attribute_target sama dengan:
-
method— targetnya adalah operator -
return— target adalah nilai pengembalian
-
- Untuk atribut pada deklarasi dapatkan aksesor untuk deklarasi properti atau pengindeks, target default adalah metode terkait. Jika tidak, jika attribute_target sama dengan:
-
method— target adalah metode terkait -
return— target adalah nilai pengembalian
-
- Untuk atribut yang ditentukan pada aksesor yang ditetapkan untuk deklarasi properti atau pengindeks, target default adalah metode terkait. Jika tidak, jika attribute_target sama dengan:
-
method— target adalah metode terkait -
param— target adalah parameter implisit kesepian
-
- Untuk atribut pada deklarasi properti yang diimplementasikan secara otomatis, target default adalah properti . Jika tidak, jika attribute_target sama dengan:
-
field— target adalah bidang backing yang dihasilkan kompilator untuk properti
-
- Untuk atribut yang ditentukan pada deklarasi peristiwa yang menghilangkan event_accessor_declarations target default adalah deklarasi peristiwa. Jika tidak, jika attribute_target sama dengan:
-
event— targetnya adalah deklarasi peristiwa -
field— target adalah bidang -
method— targetnya adalah metode
-
- Dalam kasus deklarasi peristiwa yang tidak menghilangkan event_accessor_declarations target default adalah metode .
-
method— target adalah metode terkait -
param— targetnya adalah parameter lone
-
Dalam semua konteks lainnya, penyertaan attribute_target_specifier diizinkan tetapi tidak perlu.
Contoh: deklarasi kelas dapat mencakup atau menghilangkan penentu
type:[type: Author("Brian Kernighan")] class Class1 {} [Author("Dennis Ritchie")] class Class2 {}contoh akhir.
Implementasi dapat menerima attribute_targetlain, tujuan implementasi yang ditentukan. Implementasi yang tidak mengenali attribute_target tersebut akan mengeluarkan peringatan dan mengabaikan attribute_section yang berisi.
Menurut konvensi, kelas atribut dinamai dengan akhiran Attribute. Attribute_name dapat menyertakan atau menghilangkan akhiran ini. Secara khusus, attribute_name diselesaikan sebagai berikut:
- Jika pengidentifikasi paling kanan dari attribute_name adalah pengidentifikasi verbatim (§6.4.3), maka attribute_name diselesaikan sebagai type_name (§7,8). Jika hasilnya bukan jenis yang berasal dari
System.Attribute, kesalahan waktu kompilasi terjadi. - Sebaliknya
-
attribute_name diselesaikan sebagai type_name (§7,8) kecuali kesalahan apa pun ditekan. Jika resolusi ini berhasil dan menghasilkan jenis yang berasal dari
System.Attributemaka jenisnya adalah hasil dari langkah ini. - Karakter
Attributeditambahkan ke pengidentifikasi paling kanan dalam attribute_name dan string token yang dihasilkan diselesaikan sebagai type_name (§7,8) kecuali kesalahan apa pun ditekan. Jika resolusi ini berhasil dan menghasilkan jenis yang berasal dariSystem.Attributemaka jenisnya adalah hasil dari langkah ini.
-
attribute_name diselesaikan sebagai type_name (§7,8) kecuali kesalahan apa pun ditekan. Jika resolusi ini berhasil dan menghasilkan jenis yang berasal dari
Jika tepat salah satu dari dua langkah di atas menghasilkan jenis yang berasal dari System.Attribute, maka jenis tersebut adalah hasil dari attribute_name. Jika tidak, kesalahan waktu kompilasi terjadi.
Contoh: Jika kelas atribut ditemukan dengan dan tanpa akhiran ini, ambiguitas ada, dan hasil kesalahan waktu kompilasi. Jika attribute_name dieja sedih sehingga pengidentifikasi paling kanan adalah pengidentifikasi verbatim (§6.4.3), maka hanya atribut tanpa akhiran yang cocok, sehingga memungkinkan ambiguitas seperti itu diselesaikan. Contoh
[AttributeUsage(AttributeTargets.All)] public class Example : Attribute {} [AttributeUsage(AttributeTargets.All)] public class ExampleAttribute : Attribute {} [Example] // Error: ambiguity class Class1 {} [ExampleAttribute] // Refers to ExampleAttribute class Class2 {} [@Example] // Refers to Example class Class3 {} [@ExampleAttribute] // Refers to ExampleAttribute class Class4 {}menunjukkan dua kelas atribut bernama
ExampledanExampleAttribute. Atributnya[Example]ambigu, karena dapat merujuk keExampleatauExampleAttribute. Menggunakan pengidentifikasi verbatim memungkinkan niat yang tepat untuk ditentukan dalam kasus langka seperti itu. Atribut[ExampleAttribute]tidak ambigu (meskipun akan jika ada kelas atribut bernamaExampleAttributeAttribute!). Jika deklarasi untuk kelasExampledihapus, kedua atribut merujuk ke kelas atribut bernamaExampleAttribute, sebagai berikut:[AttributeUsage(AttributeTargets.All)] public class ExampleAttribute : Attribute {} [Example] // Refers to ExampleAttribute class Class1 {} [ExampleAttribute] // Refers to ExampleAttribute class Class2 {} [@Example] // Error: no attribute named “Example” class Class3 {}contoh akhir
Ini adalah kesalahan waktu kompilasi untuk menggunakan kelas atribut sekali pakai lebih dari sekali pada entitas yang sama.
Contoh: Contoh
[AttributeUsage(AttributeTargets.Class)] public class HelpStringAttribute : Attribute { public HelpStringAttribute(string value) { Value = value; } public string Value { get; } } [HelpString("Description of Class1")] [HelpString("Another description of Class1")] // multiple uses not allowed public class Class1 {}menghasilkan kesalahan waktu kompilasi
HelpStringkarena mencoba menggunakanClass1, yang merupakan kelas atribut sekali pakai, lebih dari sekali pada deklarasi .contoh akhir
Ekspresi E adalah attribute_argument_expression jika semua pernyataan berikut ini benar:
- Jenisnya
Eadalah jenis parameter atribut (§23.2.4). - Pada waktu kompilasi
E, nilai dapat diatasi ke salah satu hal berikut:
Contoh:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Field)] public class TestAttribute : Attribute { public int P1 { get; set; } public Type P2 { get; set; } public object P3 { get; set; } } [Test(P1 = 1234, P3 = new int[]{1, 3, 5}, P2 = typeof(float))] class MyClass {} class C<T> { [Test(P2 = typeof(T))] // Error – T not a closed type. int x1; [Test(P2 = typeof(C<T>))] // Error – C<;T>; not a closed type. int x2; [Test(P2 = typeof(C<int>))] // Ok int x3; [Test(P2 = typeof(C<>))] // Ok int x4; }contoh akhir
Atribut jenis yang dideklarasikan dalam beberapa bagian ditentukan dengan menggabungkan, dalam urutan yang tidak ditentukan, atribut masing-masing bagiannya. Jika atribut yang sama ditempatkan pada beberapa bagian, atribut tersebut setara dengan menentukan atribut tersebut beberapa kali pada jenisnya.
Contoh: Dua bagian:
[Attr1, Attr2("hello")] partial class A {} [Attr3, Attr2("goodbye")] partial class A {}setara dengan deklarasi tunggal berikut:
[Attr1, Attr2("hello"), Attr3, Attr2("goodbye")] class A {}contoh akhir
Atribut pada parameter jenis digabungkan dengan cara yang sama.
23.4 Instans atribut
23.4.1 Umum
Instans atribut adalah instans yang mewakili atribut pada run-time. Atribut didefinisikan dengan kelas atribut, argumen posisi, dan argumen bernama. Instans atribut adalah instans kelas atribut yang diinisialisasi dengan argumen posisi dan bernama.
Pengambilan instans atribut melibatkan pemrosesan waktu kompilasi dan run-time, seperti yang dijelaskan dalam subklasul berikut.
23.4.2 Kompilasi atribut
Kompilasi atribut dengan kelas Tatribut , positional_argument_listP, , dan ditentukan pada entitas N program dikompilasi ke dalam rakitan E melalui langkah-langkah berikut:
- Ikuti langkah-langkah pemrosesan waktu kompilasi untuk mengkompilasi object_creation_expression formulir baru
T(P). Langkah-langkah ini mengakibatkan kesalahan waktu kompilasi, atau menentukan konstruktorCinstans padaTyang dapat dipanggil pada run-time. - Jika
Ctidak memiliki aksesibilitas publik, maka terjadi kesalahan waktu kompilasi. - Untuk setiap named_argument
ArgdiN:- Biarkan
Namemenjadi pengidentifikasi -
Nameharus mengidentifikasi bidang publik baca-tulis non-statis atau properti padaT. JikaTtidak memiliki bidang atau properti seperti itu, maka terjadi kesalahan waktu kompilasi.
- Biarkan
- Jika salah satu nilai dalam positional_argument_list
Patau salah satu nilai dalam named_argument_listNberjenisSystem.Stringdan nilainya tidak terbentuk dengan baik seperti yang didefinisikan oleh Standar Unicode, nilai yang didefinisikan implementasinya sama dengan nilai run-time yang diambil (§23.4.3).Catatan: Sebagai contoh, string yang berisi unit kode UTF-16 pengganti tinggi yang tidak segera diikuti oleh unit kode pengganti rendah tidak terbentuk dengan baik. catatan akhir
- Simpan informasi berikut (untuk instansiasi run-time atribut) dalam output perakitan oleh pengkompilasi sebagai hasil dari mengkompilasi program yang berisi atribut: kelas
Tatribut , konstruktorCinstans padaT, ,P, dan entitasNprogram terkait , dengan nilai diselesaikan sepenuhnya pada waktu kompilasi.
23.4.3 Pengambilan run-time instans atribut
Menggunakan istilah yang ditentukan dalam §23.4.2, instans atribut yang diwakili oleh T, , CP, dan N, dan yang terkait dengan E dapat diambil pada run-time dari perakitan A menggunakan langkah-langkah berikut:
- Ikuti langkah-langkah pemrosesan run-time untuk menjalankan object_creation_expression formulir
new T(P), menggunakan konstruktorCinstans dan nilai seperti yang ditentukan pada waktu kompilasi. Langkah-langkah ini menghasilkan pengecualian, atau menghasilkan instansOT. - Untuk setiap named_argument
ArgdalamN, secara berurutan:- Biarkan
Namemenjadi pengidentifikasi JikaNametidak mengidentifikasi bidang baca-tulis publik atau properti non-statis padaO, maka pengecualian akan dilemparkan. - Mari kita
Valuejadikan hasil mengevaluasi attribute_argument_expression .Arg - Jika
Namemengidentifikasi bidang padaO, maka atur bidang ini keValue. - Jika tidak, Nama mengidentifikasi properti pada
O. Atur properti ini ke Nilai. - Hasilnya adalah
O, instans kelasTatribut yang telah diinisialisasi dengan positional_argument_listPdan named_argument_listN.
- Biarkan
Catatan: Format untuk menyimpan
T, ,C,PN(dan mengaitkannya denganE) diAdan mekanisme untuk menentukanEdan mengambilT, ,CP,NdariA(dan karenanya bagaimana instans atribut diperoleh pada runtime) berada di luar cakupan spesifikasi ini. catatan akhir
23.5 Atribut cadangan
23.5.1 Umum
Sejumlah atribut memengaruhi bahasa dalam beberapa cara. Atribut ini meliputi:
-
System.AttributeUsageAttribute(§23.5.2), yang digunakan untuk menggambarkan cara kelas atribut dapat digunakan. -
System.Diagnostics.ConditionalAttribute(§23.5.3), adalah kelas atribut multi-penggunaan yang digunakan untuk menentukan metode kondisional dan kelas atribut kondisional. Atribut ini menunjukkan kondisi dengan menguji simbol kompilasi bersyarah. -
System.ObsoleteAttribute(§23.5.4), yang digunakan untuk menandai anggota sebagai usang. -
System.Runtime.CompilerServices.AsyncMethodBuilderAttribute(§23.5.5), yang digunakan untuk membuat pembangun tugas untuk metode asinkron. -
System.Runtime.CompilerServices.CallerLineNumberAttribute(§23.5.6.2),System.Runtime.CompilerServices.CallerFilePathAttribute(§23.5.6.3), danSystem.Runtime.CompilerServices.CallerMemberNameAttribute(§23.5.6.4), yang digunakan untuk memberikan informasi tentang konteks panggilan ke parameter opsional. -
System.Runtime.CompilerServices.EnumeratorCancellationAttribute(§23.5.8), yang digunakan untuk menentukan parameter untuk token pembatalan dalam iterator asinkron.
Atribut analisis statis nullable (§23.5.7) dapat meningkatkan kebenaran peringatan yang dihasilkan untuk nullabilities dan status null (§8.9.5).
Lingkungan eksekusi dapat menyediakan atribut tambahan yang ditentukan implementasi yang memengaruhi eksekusi program C#.
23.5.2 AtributUsage atribut
Atribut AttributeUsage digunakan untuk menjelaskan cara kelas atribut dapat digunakan.
Kelas yang didekorasi dengan AttributeUsage atribut harus berasal dari System.Attribute, baik secara langsung maupun tidak langsung. Jika tidak, terjadi kesalahan waktu kompilasi.
Catatan: Untuk contoh penggunaan atribut ini, lihat §23.2.2. catatan akhir
23.5.3 Atribut Bersyarah
23.5.3.1 Umum
Atribut Conditional memungkinkan definisi metode kondisionaldan kelas atribut kondisionales.
23.5.3.2 Metode bersyarah
Metode yang didekorasi dengan Conditional atribut adalah metode bersyarkat. Setiap metode bersyarat dengan demikian dikaitkan dengan simbol kompilasi bersyarat yang dideklarasikan dalam atributnya Conditional .
Contoh:
class Eg { [Conditional("ALPHA")] [Conditional("BETA")] public static void M() { // ... } }menyatakan
Eg.Msebagai metode bersyarat yang terkait dengan dua simbol kompilasi bersyaratALPHAdanBETA.contoh akhir
Panggilan ke metode bersyarkat disertakan jika satu atau beberapa simbol kompilasi bersyar terkait didefinisikan pada titik panggilan, jika tidak, panggilan dihilangkan.
Metode bersyukur tunduk pada pembatasan berikut:
- Metode bersyarah harus menjadi metode dalam class_declaration atau struct_declaration. Kesalahan waktu kompilasi terjadi jika
Conditionalatribut ditentukan pada metode dalam deklarasi antarmuka. - Metode bersyarah tidak boleh menjadi pengakses properti, pengindeks, atau peristiwa.
- Metode bersyarah harus memiliki jenis pengembalian .
void - Metode kondisional tidak boleh ditandai dengan pengubah
override. Namun, metode kondisional dapat ditandai dengan pengubahvirtual. Penimpaan metode tersebut secara implisit kondisional, dan tidak boleh ditandai secara eksplisit denganConditionalatribut . - Metode kondisional tidak boleh menjadi implementasi metode antarmuka. Jika tidak, terjadi kesalahan waktu kompilasi.
- Parameter metode bersyarah tidak boleh berupa parameter output.
Catatan: Atribut dengan
AttributeUsage(§23.2.2) termasukAttributeTargets.Methodbiasanya dapat diterapkan ke pengakses properti, pengindeks, dan peristiwa. Pembatasan di atas melarang penggunaanConditionalatribut ini. catatan akhir
Selain itu, kesalahan waktu kompilasi terjadi jika delegasi dibuat dari metode bersyarah.
Contoh: Contoh
#define DEBUG using System; using System.Diagnostics; class Class1 { [Conditional("DEBUG")] public static void M() { Console.WriteLine("Executed Class1.M"); } } class Class2 { public static void Test() { Class1.M(); } }menyatakan sebagai metode bersyarat
Class1.M.Class2Metode memanggilTestmetode ini. Karena simbolDEBUGkompilasi bersyarat didefinisikan, jikaClass2.Testdipanggil, simbol tersebut akan memanggilM. Jika simbolDEBUGbelum ditentukan, makaClass2.Testtidak akan memanggilClass1.M.contoh akhir
Penting untuk dipahami bahwa penyertaan atau pengecualian panggilan ke metode kondisional dikendalikan oleh simbol kompilasi kondisional pada saat panggilan.
Contoh: Dalam kode berikut
// File Class1.cs: using System; using System.Diagnostics; class Class1 { [Conditional("DEBUG")] public static void F() { Console.WriteLine("Executed Class1.F"); } } // File Class2.cs: #define DEBUG class Class2 { public static void G() { Class1.F(); // F is called } } // File Class3.cs: #undef DEBUG class Class3 { public static void H() { Class1.F(); // F is not called } }kelas
Class2danClass3masing-masing berisi panggilan ke metodeClass1.Fkondisional , yang bersyukur berdasarkan apakah didefinisikan atau tidakDEBUG. Karena simbol ini didefinisikan dalam konteksClass2tetapi tidakClass3, panggilan keFdalamClass2disertakan, sementara panggilan keFdihilangkanClass3.contoh akhir
Penggunaan metode kondisional dalam rantai warisan dapat membingungkan. Panggilan yang dilakukan ke metode bersyarah melalui base, dari formulir base.M, tunduk pada aturan panggilan metode kondisi normal.
Contoh: Dalam kode berikut
// File Class1.cs using System; using System.Diagnostics; class Class1 { [Conditional("DEBUG")] public virtual void M() => Console.WriteLine("Class1.M executed"); } // File Class2.cs class Class2 : Class1 { public override void M() { Console.WriteLine("Class2.M executed"); base.M(); // base.M is not called! } } // File Class3.cs #define DEBUG class Class3 { public static void Main() { Class2 c = new Class2(); c.M(); // M is called } }
Class2termasuk panggilan ke yangMditentukan di kelas dasarnya. Panggilan ini dihilangkan karena metode dasar bersyukur berdasarkan keberadaan simbolDEBUG, yang tidak terdefinisi. Dengan demikian, metode menulis ke konsol "Class2.M executed" saja. Penggunaan pp_declarationyang berdasar dapat menghilangkan masalah tersebut.contoh akhir
23.5.3.3 Kelas atribut kondisional
Kelas atribut (§23.2) yang didekorasi dengan satu atau beberapa Conditional atribut adalah kelas atribut kondisional. Kelas atribut bersyarat dengan demikian dikaitkan dengan simbol kompilasi bersyarat yang dideklarasikan dalam atributnya Conditional .
Contoh:
[Conditional("ALPHA")] [Conditional("BETA")] public class TestAttribute : Attribute {}menyatakan
TestAttributesebagai kelas atribut bersyarat yang terkait dengan simbol kompilasi bersyaratALPHAdanBETA.contoh akhir
Spesifikasi atribut (§23,3) dari atribut bersyarkat disertakan jika satu atau beberapa simbol kompilasi bersyarkat terkait didefinisikan pada titik spesifikasi, jika tidak, spesifikasi atribut dihilangkan.
Penting untuk dicatat bahwa penyertaan atau pengecualian spesifikasi atribut dari kelas atribut bersyarkat dikontrol oleh simbol kompilasi bersyarkat pada titik spesifikasi.
Contoh: Dalam contoh
// File Test.cs: using System; using System.Diagnostics; [Conditional("DEBUG")] public class TestAttribute : Attribute {} // File Class1.cs: #define DEBUG [Test] // TestAttribute is specified class Class1 {} // File Class2.cs: #undef DEBUG [Test] // TestAttribute is not specified class Class2 {}kelas
Class1danClass2masing-masing didekorasi dengan atributTest, yang bersyukur berdasarkan apakah ditentukan atau tidakDEBUG. Karena simbol ini didefinisikan dalam konteksClass1tetapi tidakClass2, spesifikasi atribut Uji padaClass1disertakan, sementara spesifikasiTestatribut pada dihilangkanClass2.contoh akhir
23.5.4 Atribut Usang
Atribut Obsolete digunakan untuk menandai jenis dan anggota jenis yang seharusnya tidak lagi digunakan.
Jika program menggunakan jenis atau anggota yang dihiasi dengan atribut Obsolete, pengkompilasi akan mengeluarkan peringatan atau kesalahan. Secara khusus, kompilator harus mengeluarkan peringatan jika tidak ada parameter kesalahan yang disediakan, atau jika parameter kesalahan disediakan dan memiliki nilai false. Kompilator akan mengeluarkan kesalahan jika parameter kesalahan ditentukan dan memiliki nilai true.
Contoh: Dalam kode berikut
[Obsolete("This class is obsolete; use class B instead")] class A { public void F() {} } class B { public void F() {} } class Test { static void Main() { A a = new A(); // Warning a.F(); } }kelas
Adihiasi denganObsoleteatribut . Setiap penggunaanAdalamMainmenghasilkan peringatan yang mencakup pesan yang ditentukan, "Kelas ini usang; gunakan kelasBsebagai gantinya".contoh akhir
23.5.5 Atribut AsyncMethodBuilder
Atribut ini dijelaskan dalam §15.14.1.
23.5.6 Atribut caller-info
23.5.6.1 Umum
Untuk tujuan seperti pengelogan dan pelaporan, terkadang berguna bagi anggota fungsi untuk mendapatkan informasi waktu kompilasi tertentu tentang kode panggilan. Atribut caller-info menyediakan cara untuk meneruskan informasi tersebut secara transparan.
Ketika parameter opsional diannotasi dengan salah satu atribut caller-info, menghilangkan argumen yang sesuai dalam panggilan tidak selalu menyebabkan nilai parameter default diganti. Sebaliknya, jika informasi yang ditentukan tentang konteks panggilan tersedia, informasi tersebut akan diteruskan sebagai nilai argumen.
Contoh:
public void Log( [CallerLineNumber] int line = -1, [CallerFilePath] string path = null, [CallerMemberName] string name = null ) { Console.WriteLine((line < 0) ? "No line" : "Line "+ line); Console.WriteLine((path == null) ? "No file path" : path); Console.WriteLine((name == null) ? "No member name" : name); }Panggilan ke
Log()tanpa argumen akan mencetak nomor baris dan jalur file panggilan, serta nama anggota tempat panggilan terjadi.contoh akhir
Atribut caller-info dapat terjadi pada parameter opsional di mana saja, termasuk dalam deklarasi delegasi. Namun, atribut caller-info tertentu memiliki batasan pada jenis parameter yang dapat mereka atribut, sehingga akan selalu ada konversi implisit dari nilai yang diganti ke jenis parameter.
Ini adalah kesalahan untuk memiliki atribut caller-info yang sama pada parameter dari deklarasi mendefinisikan dan menerapkan bagian dari deklarasi metode parsial. Hanya atribut caller-info di bagian yang menentukan yang diterapkan, sedangkan atribut caller-info yang hanya terjadi di bagian penerapan diabaikan.
Informasi penelepon tidak memengaruhi resolusi kelebihan beban. Karena parameter opsional yang dikaitkan masih dihilangkan dari kode sumber pemanggil, resolusi kelebihan beban mengabaikan parameter tersebut dengan cara yang sama mengabaikan parameter opsional lain yang dihilangkan (§12.6.4).
Informasi penelepon hanya diganti ketika fungsi secara eksplisit dipanggil dalam kode sumber. Pemanggilan implisit seperti panggilan konstruktor induk implisit tidak memiliki lokasi sumber dan tidak akan menggantikan informasi pemanggil. Selain itu, panggilan yang terikat secara dinamis tidak akan menggantikan informasi pemanggil. Ketika parameter atribut caller-info dihilangkan dalam kasus seperti itu, nilai default parameter yang ditentukan digunakan sebagai gantinya.
Satu pengecualian adalah ekspresi kueri. Ini dianggap sebagai ekspansi syntactic, dan jika panggilan yang mereka perluas untuk menghilangkan parameter opsional dengan atribut caller-info, informasi penelepon akan diganti. Lokasi yang digunakan adalah lokasi klausa kueri tempat panggilan dihasilkan.
Jika lebih dari satu atribut caller-info ditentukan pada parameter tertentu, atribut tersebut dikenali dalam urutan berikut: CallerLineNumber, , CallerFilePathCallerMemberName. Pertimbangkan deklarasi parameter berikut:
[CallerMemberName, CallerFilePath, CallerLineNumber] object p = ...
CallerLineNumber lebih diutamakan, dan dua atribut lainnya diabaikan. Jika CallerLineNumber dihilangkan, CallerFilePath akan diutamakan, dan CallerMemberName akan diabaikan. Urutan leksikal atribut ini tidak relevan.
23.5.6.2 Atribut CallerLineNumber
Atribut System.Runtime.CompilerServices.CallerLineNumberAttribute diizinkan pada parameter opsional ketika ada konversi implisit standar (§10.4.2) dari nilai int.MaxValue konstanta ke jenis parameter. Ini memastikan bahwa nomor baris non-negatif hingga nilai tersebut dapat diteruskan tanpa kesalahan.
Jika pemanggilan fungsi dari lokasi dalam kode sumber menghilangkan parameter opsional dengan CallerLineNumberAttribute, maka literal numerik yang mewakili nomor baris lokasi tersebut digunakan sebagai argumen untuk pemanggilan alih-alih nilai parameter default.
Jika pemanggilan mencakup beberapa baris, baris yang dipilih bergantung pada implementasi.
Nomor baris dapat dipengaruhi oleh #line arahan (§6.5.8).
23.5.6.3 Atribut CallerFilePath
Atribut System.Runtime.CompilerServices.CallerFilePathAttribute diizinkan pada parameter opsional ketika ada konversi implisit standar (§10.4.2) dari string ke jenis parameter.
Jika pemanggilan fungsi dari lokasi dalam kode sumber menghilangkan parameter opsional dengan CallerFilePathAttribute, maka string literal yang mewakili jalur file lokasi tersebut digunakan sebagai argumen untuk pemanggilan alih-alih nilai parameter default.
Format jalur file bergantung pada implementasi.
Jalur file dapat dipengaruhi oleh #line arahan (§6.5.8).
23.5.6.4 Atribut CallerMemberName
Atribut System.Runtime.CompilerServices.CallerMemberNameAttribute diizinkan pada parameter opsional ketika ada konversi implisit standar (§10.4.2) dari string ke jenis parameter.
Jika pemanggilan fungsi dari lokasi dalam isi anggota fungsi atau dalam atribut yang diterapkan ke anggota fungsi itu sendiri atau jenis pengembaliannya, parameter atau parameter jenis dalam kode sumber menghilangkan parameter opsional dengan CallerMemberNameAttribute, maka string harfiah yang mewakili nama anggota tersebut digunakan sebagai argumen untuk pemanggilan alih-alih nilai parameter default.
Untuk pemanggilan yang terjadi dalam metode generik, hanya nama metode itu sendiri yang digunakan, tanpa daftar parameter jenis.
Untuk pemanggilan yang terjadi dalam implementasi anggota antarmuka eksplisit, hanya nama metode itu sendiri yang digunakan, tanpa kualifikasi antarmuka sebelumnya.
Untuk pemanggilan yang terjadi dalam properti atau aksesor peristiwa, nama anggota yang digunakan adalah properti atau peristiwa itu sendiri.
Untuk pemanggilan yang terjadi dalam pengakses pengindeks, nama anggota yang digunakan adalah yang disediakan oleh IndexerNameAttribute (§23,6) pada anggota pengindeks, jika ada, atau nama Item default sebaliknya.
Untuk pemanggilan yang terjadi dalam penginisialisasi bidang atau peristiwa, nama anggota yang digunakan adalah nama bidang atau peristiwa yang sedang diinisialisasi.
Untuk pemanggilan yang terjadi dalam deklarasi konstruktor instans, konstruktor statis, finalizer, dan operator nama anggota yang digunakan bergantung pada implementasi.
23.5.7 Atribut analisis kode
23.5.7.1 Umum
Atribut dalam subklaus ini digunakan untuk memberikan informasi tambahan guna mendukung kompilator yang menyediakan diagnostik untuk ketidaknullan dan keadaan null (§8.9.5). Pengkompilasi tidak diperlukan untuk melakukan diagnostik status null. Kehadiran atau tidak adanya atribut ini tidak memengaruhi bahasa atau perilaku program. Pengkompilasi yang tidak menyediakan diagnostik status null harus membaca dan mengabaikan keberadaan atribut ini. Kompilator yang menyediakan diagnosis status null harus menggunakan arti yang ditentukan dalam subklausa ini untuk atribut mana pun yang digunakannya guna menginformasikan diagnosisnya.
Atribut analisis kode dideklarasikan dalam namespace System.Diagnostics.CodeAnalysis.
| Atribut | Arti |
|---|---|
AllowNull (§23.5.7.2) |
Argumen yang tidak dapat diubah ke null mungkin null. |
DisallowNull (§23.5.7.3) |
Argumen nullable tidak boleh null. |
MaybeNull (§23.5.7.6) |
Nilai pengembalian yang tidak dapat diubah ke null mungkin null. |
NotNull (§23.5.7.8) |
Nilai pengembalian null tidak akan pernah null. |
MaybeNullWhen (§23.5.7.7) |
Argumen yang tidak dapat diubah ke null mungkin null saat metode mengembalikan nilai bool yang ditentukan. |
NotNullWhen (§23.5.7.10) |
Argumen nullable tidak akan null ketika metode mengembalikan nilai yang ditentukan bool . |
NotNullIfNotNull (§23.5.7.9) |
Nilai yang dikembalikan tidak null jika argumen untuk parameter yang ditentukan tidak null. |
DoesNotReturn (§23.5.7.4) |
Metode ini tidak pernah kembali. |
DoesNotReturnIf (§23.5.7.5) |
Metode ini tidak pernah mengembalikan jika parameter terkait bool memiliki nilai yang ditentukan. |
Subklaus berikut dalam §23.5.7.1 bersifat normatif kondisional.
23.5.7.2 Atribut AllowNull
Menentukan bahwa nilai null diizinkan sebagai input meskipun jenis yang sesuai melarangnya.
Contoh: Pertimbangkan properti baca/tulis berikut yang tidak pernah ditampilkan
nullkarena memiliki nilai default yang wajar. Namun, pengguna dapat memberikan null kepada aksesor yang ditetapkan untuk mengatur properti ke nilai default tersebut.#nullable enable public class X { [AllowNull] public string ScreenName { get => _screenName; set => _screenName = value ?? GenerateRandomScreenName(); } private string _screenName = GenerateRandomScreenName(); private static string GenerateRandomScreenName() => ...; }Mengingat penggunaan aksesor set properti tersebut berikut
var v = new X(); v.ScreenName = null; // may warn without attribute AllowNulltanpa atribut, pengompilasi dapat menghasilkan peringatan karena properti bertipe non-nullable tampaknya diatur ke nilai null. Kehadiran atribut menekan peringatan tersebut. contoh akhir
23.5.7.3 Atribut DisallowNull
Menentukan bahwa nilai null tidak diizinkan sebagai input meskipun jenis yang sesuai mengizinkannya.
Contoh: Pertimbangkan properti berikut di mana null adalah nilai default, tetapi klien hanya dapat mengaturnya ke nilai non-null.
#nullable enable public class X { [DisallowNull] public string? ReviewComment { get => _comment; set => _comment = value ?? throw new ArgumentNullException(nameof(value), "Cannot set to null"); } private string? _comment = default; }Get accessor dapat mengembalikan nilai default
null, sehingga pengkompilasi dapat memperingatkan bahwa itu harus diperiksa sebelum akses. Selain itu, ini memperingatkan penelepon bahwa, meskipun bisa null, penelepon tidak boleh secara eksplisit mengaturnya ke null. contoh akhir
23.5.7.4 Atribut DoesNotReturn
Menentukan bahwa metode tertentu tidak pernah kembali.
Contoh: Pertimbangkan hal berikut:
public class X { [DoesNotReturn] private void FailFast() => throw new InvalidOperationException(); public void SetState(object? containedField) { if ((!isInitialized) || (containedField == null)) { FailFast(); } // null check not needed. _field = containedField; } private bool isInitialized = false; private object _field; }Kehadiran atribut membantu pengkompilasi dengan sejumlah cara. Pertama, kompilator dapat mengeluarkan peringatan jika ada jalur di mana metode dapat keluar tanpa melemparkan pengecualian. Kedua, kompilator dapat menekan peringatan nullable dalam kode apa pun setelah panggilan ke metode tersebut, sampai klausa tangkapan yang sesuai ditemukan. Ketiga, kode yang tidak dapat dijangkau tidak akan memengaruhi status null apa pun.
Atribut tidak mengubah keterjangkauan (§13.2) atau analisis penetapan pasti (§9,4) berdasarkan keberadaan atribut ini. Ini hanya digunakan untuk memengaruhi peringatan nullability. contoh akhir
23.5.7.5 Atribut DoesNotReturnIf
Menentukan bahwa metode tertentu tidak pernah mengembalikan jika parameter terkait bool memiliki nilai yang ditentukan.
Contoh: Pertimbangkan hal berikut:
#nullable enable public class X { private void ThrowIfNull([DoesNotReturnIf(true)] bool isNull, string argumentName) { if (!isNull) { throw new ArgumentException(argumentName, $"argument {argumentName} can't be null"); } } public void SetFieldState(object containedField) { ThrowIfNull(containedField == null, nameof(containedField)); // unreachable code when "isInitialized" is false: _field = containedField; } private bool isInitialized = false; private object _field = default!; }contoh akhir
23.5.7.6 Atribut MaybeNull
Menentukan bahwa nilai pengembalian yang tidak dapat diubah ke null mungkin null.
Contoh: Pertimbangkan metode generik berikut:
#nullable enable public T? Find<T>(IEnumerable<T> sequence, Func<T, bool> predicate) { ... }Ide dari kode ini adalah bahwa jika
Tdigantikan olehstring,T?menjadi anotasi nullable. Namun, kode ini tidak legal karenaTtidak dibatasi untuk menjadi jenis referensi. Namun, menambahkan atribut ini memecahkan masalah:#nullable enable [return: MaybeNull] public T Find<T>(IEnumerable<T> sequence, Func<T, bool> predicate) { ... }Atribut menginformasikan kepada penelepon bahwa kontrak menyiratkan jenis yang tidak dapat diubah ke null, tetapi nilai pengembalian sebenarnya mungkin
null. contoh akhir
23.5.7.7 Atribut MaybeNullWhen
Menentukan bahwa argumen yang tidak dapat diubah ke null mungkin null ketika metode mengembalikan nilai yang ditentukan bool . Ini mirip MaybeNull dengan atribut (§23.5.7.6), tetapi menyertakan parameter untuk nilai pengembalian yang ditentukan.
23.5.7.8 Atribut NotNull
Menentukan bahwa nilai nullable tidak akan null pernah jika metode mengembalikan (bukan melemparkan).
Contoh: Pertimbangkan hal berikut:
#nullable enable public static void ThrowWhenNull([NotNull] object? value, string valueExpression = "") => _ = value ?? throw new ArgumentNullException(valueExpression); public static void LogMessage(string? message) { ThrowWhenNull(message, nameof(message)); Console.WriteLine(message.Length); }Ketika jenis referensi nullable diaktifkan, metode
ThrowWhenNulldikompilasi tanpa peringatan. Ketika metode itu kembali, argumen dijaminvaluebukannull. Namun, dapat diterima untuk memanggilThrowWhenNulldengan referensi null. contoh akhir
23.5.7.9 Atribut NotNullIfNotNull
Menentukan bahwa nilai pengembalian bukan null jika argumen untuk parameter yang ditentukan bukan null.
Contoh: Status null dari nilai pengembalian dapat bergantung pada status null dari satu atau beberapa argumen. Untuk membantu analisis pengkompilasi ketika metode selalu mengembalikan nilai non-null ketika argumen tertentu tidak
nullatributNotNullIfNotNulldapat digunakan. Pertimbangkan kode berikut:#nullable enable string GetTopLevelDomainFromFullUrl(string url) { ... }
urlJika argumen tidaknull,nulltidak dikembalikan. Ketika referensi nullable diaktifkan, tanda tangan tersebut berfungsi dengan benar, asalkan API tidak pernah menerima argumen null. Namun, jika argumen bisa null, maka nilai yang dikembalikan juga bisa null. Untuk mengekspresikan kontrak tersebut dengan benar, anotasi metode ini sebagai berikut:#nullable enable [return: NotNullIfNotNull("url")] string? GetTopLevelDomainFromFullUrl(string? url) { ... }contoh akhir
23.5.7.10 Atribut NotNullWhen
Menentukan bahwa argumen nullable tidak akan ketika null metode mengembalikan nilai yang ditentukan bool .
Contoh: Metode
String.IsNullOrEmpty(String)pustaka mengembalikantruesaat argumen adalahnullatau string kosong. Ini adalah bentuk pemeriksaan null: Penelepon tidak perlu memeriksa argumen null jika metode mengembalikanfalse. Untuk membuat metode seperti ini sadar nullable, buat jenis parameter sebagai jenis referensi nullable, dan tambahkan atribut NotNullWhen:#nullable enable bool IsNullOrEmpty([NotNullWhen(false)] string? value) { ... }contoh akhir
23.5.8 Atribut EnumeratorCancellation
Menentukan parameter yang mewakili CancellationToken untuk iterator asinkron (§15.15). Argumen untuk parameter ini harus dikombinasikan dengan argumen yang diteruskan ke IAsyncEnumerable<T>.GetAsyncEnumerator(CancellationToken). Token gabungan ini harus dijajaki oleh IAsyncEnumerator<T>.MoveNextAsync() (§15.15.5.2). Token harus digabungkan ke dalam satu token seolah-olah oleh dan CancellationToken.CreateLinkedTokenSource propertinya Token . Token gabungan akan dibatalkan jika salah satu dari dua token sumber dibatalkan. Token gabungan dipandang sebagai argumen untuk metode iterator asinkron (§15,15) dalam isi metode tersebut.
Ini adalah kesalahan jika System.Runtime.CompilerServices.EnumeratorCancellation atribut diterapkan ke lebih dari satu parameter. Pengkompilasi dapat menghasilkan peringatan jika:
- Atribut
EnumeratorCancellationditerapkan ke parameter jenis selainCancellationToken, - atau jika
EnumeratorCancellationatribut diterapkan ke parameter pada metode yang bukan iterator asinkron (§15.15), - atau jika
EnumeratorCancellationatribut diterapkan ke parameter pada metode yang mengembalikan antarmuka enumerator asinkron (§15.15.3) daripada antarmuka enumerator asinkron (§15.15.2).
Iterator tidak akan memiliki akses ke CancellationToken argumen GetAsyncEnumerator ketika tidak ada atribut yang memiliki parameter ini.
Contoh: Metode
GetStringsAsync()ini adalah iterator asinkron. Sebelum melakukan pekerjaan apa pun untuk mengambil nilai berikutnya, ia memeriksa token pembatalan untuk menentukan apakah perulangan harus dibatalkan. Jika pembatalan diminta, tidak ada tindakan lebih lanjut yang diambil.public static async Task ExampleCombination() { var sourceOne = new CancellationTokenSource(); var sourceTwo = new CancellationTokenSource(); await using (IAsyncEnumerator<string> enumerator = GetStringsAsync(sourceOne.Token).GetAsyncEnumerator(sourceTwo.Token)) { while (await enumerator.MoveNextAsync()) { string number = enumerator.Current; if (number == "8") sourceOne.Cancel(); if (number == "5") sourceTwo.Cancel(); Console.WriteLine(number); } } } static async IAsyncEnumerable<string> GetStringsAsync( [EnumeratorCancellation] CancellationToken token) { for (int i = 0; i < 10; i++) { if (token.IsCancellationRequested) yield break; await Task.Delay(1000, token); yield return i.ToString(); } }contoh akhir
23.6 Atribut untuk interoperatur
Untuk interoperatasi dengan bahasa lain, pengindeks dapat diimplementasikan menggunakan properti terindeks. Jika tidak ada IndexerName atribut yang ada untuk pengindeks, maka nama Item tersebut digunakan secara default. Atribut ini IndexerName memungkinkan pengembang untuk mengambil alih default ini dan menentukan nama yang berbeda.
Contoh: Secara default, nama pengindeks adalah
Item. Ini dapat ditimpa, sebagai berikut:[System.Runtime.CompilerServices.IndexerName("TheItem")] public int this[int index] { get { ... } set { ... } }Sekarang, nama pengindeks adalah
TheItem.contoh akhir
ECMA C# draft specification