Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
23.1 Általános
A C#-nyelv nagy része lehetővé teszi, hogy a programozó deklaratív információkat adjon meg a programban meghatározott entitásokról. Egy osztályban például egy metódus akadálymentességét úgy adhatja meg, hogy az method_modifiers public, protected, internalés private.
A C# lehetővé teszi a programozók számára, hogy új deklaratív információkat, úgynevezett attribútumokattaláljanak ki. A programozók ezután attribútumokat csatolhatnak a különböző programentitásokhoz, és lekérhetik az attribútuminformációkat egy futásidejű környezetben.
Megjegyzés: Előfordulhat például, hogy egy keretrendszer meghatároz egy
HelpAttributeattribútumot, amely elhelyezhető bizonyos programelemeken (például osztályokon és metódusokon), hogy megfeleltetést biztosítson ezekből a programelemekből a dokumentációjukba. végjegyzet
Az attribútumokat az attribútumosztályok deklarációja (23.2. §) határozza meg, amelyek helymeghatározó és elnevezett paraméterekkel rendelkezhetnek (23.2.3. §). Az attribútumok attribútumspecifikációk (23.3.§) használatával kapcsolódnak egy C#-program entitásaihoz, és futtatáskor attribútumpéldányokként kérhetők le (23.4. §).
23.2 Attribútumosztályok
23.2.1 Általános
Az absztrakt osztályból System.Attributeszármazó osztály – akár közvetlenül, akár közvetve – attribútumosztály. Az attribútumosztály deklarálása egy új típusú attribútumot határoz meg, amely programentitásokon helyezhető el. Konvenció szerint az attribútumosztályok neve a következő utótaggal Attributevan elnevezve: . Az attribútumok használata magában foglalhatja vagy kihagyhatja ezt az utótagot.
Az általános osztály deklarációja nem használható System.Attribute közvetlen vagy közvetett alaposztályként.
Példa:
public class B : Attribute {} public class C<T> : B {} // Error – generic cannot be an attributezáró példa
23.2.2 Attribútumhasználat
Az attribútum AttributeUsage (23.5.2. §) az attribútumosztályok felhasználási módjának leírására szolgál.
AttributeUsage rendelkezik egy pozícióparaméterrel (23.2.3. §), amely lehetővé teszi, hogy az attribútumosztály meghatározza azokat a programentitások típusait, amelyeken használható.
Példa: Az alábbi példa egy attribútumosztályt
SimpleAttributehatároz meg, amely csak class_declaration s és interface_declarations-n helyezhető el, és azSimpleattribútum több használatát is megjeleníti.[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface)] public class SimpleAttribute : Attribute { ... } [Simple] class Class1 {...} [Simple] interface Interface1 {...}Bár ez az attribútum a névvel
SimpleAttributevan definiálva , az attribútum használatakor előfordulhat, hogy azAttributeutótag hiányzik, ami a rövid nevetSimpleeredményezi. Így a fenti példa szemantikailag egyenértékű a következő[SimpleAttribute] class Class1 {...} [SimpleAttribute] interface Interface1 {...}záró példa
AttributeUsage nevű paramétere (23.2.3. §), AllowMultipleamely azt jelzi, hogy az attribútum egy adott entitáshoz többször is megadható-e. Ha AllowMultiple egy attribútumosztály értéke igaz, akkor az attribútumosztály egy többfelhasználós attribútumosztály, amely egy entitáson többször is megadható. Ha AllowMultiple egy attribútumosztály értéke hamis vagy nincs meghatározva, akkor az attribútumosztály egy egyszer használatos attribútumosztály, és legfeljebb egyszer adható meg egy entitáson.
Példa: Az alábbi példa egy elnevezett
AuthorAttributetöbbfelhasználós attribútumosztályt határoz meg, és egy osztálydeklarációt jelenít meg azAuthorattribútum két használatával:[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 { ... }záró példa
AttributeUsage van egy másik elnevezett paramétere (23.2.3. §), Inheritedamely azt jelzi, hogy az attribútumot az alaposztályban megadottak is öröklik-e az adott alaposztályból származó osztályok. Ha Inherited egy attribútumosztály értéke igaz, akkor az attribútum öröklődik. Ha Inherited egy attribútumosztály hamis, akkor az attribútum nem öröklődik. Ha nincs meghatározva, az alapértelmezett értéke igaz.
Olyan attribútumosztály X , amelyhez AttributeUsage nincs attribútum csatolva, mint a
class X : Attribute { ... }
egyenértékű a következő értékével:
[AttributeUsage(
AttributeTargets.All,
AllowMultiple = false,
Inherited = true)
]
class X : Attribute { ... }
23.2.3 Pozíció- és elnevezett paraméterek
Az attribútumosztályok s pozícióparamétertés elnevezett paraméterttartalmazhatnak. Az attribútumosztály minden nyilvános példány-konstruktora az adott attribútumosztályhoz tartozó pozícióparaméterek érvényes sorozatát határozza meg. Az attribútumosztály minden nem statikus nyilvános olvasási-írási mezője és nem statikus nyilvános írási vagy olvasási init tulajdonsága egy elnevezett paramétert határoz meg az attribútumosztályhoz. Ahhoz, hogy egy tulajdonság megnevezett paramétert határozzon meg, az adott tulajdonságnak nyilvános lekéréses tartozékot és nyilvános készletet vagy init tartozékot is tartalmaznia kell.
Példa: Az alábbi példa egy egy pozícióparamétert
HelpAttributeés egy elnevezett paraméterturltartalmazó attribútumosztálytTopichatároz meg. Bár nem statikus és nyilvános, a tulajdonságUrlnem definiál elnevezett paramétert, mivel nem írási vagy olvasási init. Az attribútum két felhasználási módja is látható:[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 { }záró példa
23.2.4 Attribútumparaméter-típusok
Az attribútumosztály helymeghatározó és elnevezett paramétereinek típusai az s attribútumparaméter-típusrakorlátozódnak, amelyek a következők:
- Az alábbi típusok egyike: , , , , ,
bool,bytechar,double,floatint, ,long, .sbyteshortstringuintulongushort - A típus
object. - A típus
System.Type. - Enumerálási típusok.
- A fenti típusok egydimenziós tömbjei.
- Egy konstruktor argumentum vagy nyilvános mező, amely nem rendelkezik ilyen típussal, nem használható pozíció- vagy elnevezett paraméterként az attribútum specifikációjában.
23.3 Attribútum specifikációja
A korábban definiált attribútumokat attribútumspecifikációnak nevezzük. Az attribútum egy programentitáshoz megadott további deklaratív információ. Az attribútumok a globális hatókörben (a szerelvény vagy modul attribútumainak meghatározásához) és type_declarations (14.8.§), class_member_declarations (15.3. §), interface_member_declarations (19. §) esetében adhatók meg. 4), struct_member_declarations (16.3. §), enum_member_declarations (20.2. §), accessor_declarations (15.7.3. §), event_accessor_declarations (15.8. §)), local_function_declarations (13.6.4. §), parameter_lists elemei (15.6.2. §), type_parameter_listelemei (15.2.3.§), lambda_expressions (12.22.1. §), valamint explicit_anonymous_function_parameterés implicit_anonymous_function_parameterelemei (12.22.1. §).
Az attribútumok az s attribútumszakaszbanvannak megadva. Az attribútumszakaszok szögletes zárójelekből állnak, amelyek egy vagy több attribútum vesszővel tagolt listáját veszik körül. Az attribútumok ilyen listában való megadásának sorrendje, valamint az a sorrend, amelyben az adott programentitásához csatolt szakaszok rendezve vannak, nem jelentős. Az attribútum-specifikációk például egyenértékűek[A][B][B][A][A, B][B, A].
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
;
Az éles global_attribute_target és az alábbi szövegben az azonosítónak a assemblymodule6.4.3. Az éles attribute_target és az alábbi szövegben az azonosítónak olyan helyesírással kell rendelkeznie, amely nem egyenlő assembly vagy module– az egyenlőség fenti definícióját használva .
Az attribútumok attribute_name és a pozíció- és elnevezett argumentumok választható listájából állnak. A pozícióargumentumok (ha vannak ilyenek) megelőzik az elnevezett argumentumokat. A pozícióargumentumok egy attribute_argument_expression, egy elnevezett argumentum egy névből, majd egy egyenlőségjelből állnak, majd egy attribute_argument_expression, amelyet együtt ugyanazok a szabályok korlátoznak, mint az egyszerű hozzárendelés. Az elnevezett argumentumok sorrendje nem jelentős.
Megjegyzés: Az egyszerűség kedvéért a záró vesszők global_attribute_section és attribute_section is megengedettek, ahogyan az array_initializer megengedett (17.7. §). végjegyzet
A attribute_name egy attribútumosztályt azonosít.
Ha egy attribútum globális szinten van elhelyezve, global_attribute_target_specifier kell megadni. Ha a global_attribute_target egyenlő:
-
assembly— a cél a tárolószerelvény -
module— a cél az azt tartalmazó modul
A global_attribute_target más értékei nem engedélyezettek.
A szabványosított attribute_target nevek a következők event: , field, method, param, property, return, typeés typevar. Ezeket a célneveket csak a következő kontextusokban szabad használni:
-
event– esemény. -
field– mező. Egy mezőszerű eseménynek (azaz tartozék nélkülinek) (15.8.2. §) és egy automatikusan implementált tulajdonságnak (15.7.4. §) is lehet attribútuma ezzel a célval. -
method– konstruktor; finalizer; Módszer; Üzemeltető; helyi függvény, tulajdonság lekérése, beállítása és inicializálása; indexelő lekérése, beállítása és inicializálása; event add and remove accessors; és lambda kifejezések. Egy mezőszerű esemény (azaz tartozék nélküli) attribútummal is rendelkezhet ezzel a céllal. -
param— tulajdonságkészlet és init tartozék, indexelőkészlet és init tartozék, esemény hozzáadása és eltávolítása, valamint egy paraméter egy konstruktorban, metódusban, helyi füstölésben és operátorban. -
property— tulajdonság és indexelő. -
return— delegált, metódus, helyi függvény, operátor, tulajdonság get tartozék, indexelő kap tartozék, és lambda kifejezés. -
type— delegált, osztály, struct, enum és interfész. -
typevar— típusparaméter.
Bizonyos környezetek lehetővé teszik egy attribútum specifikációját egynél több célon. A program egy attribute_target_specifier beleszámítva explicit módon megadhatja a célt. Attribute_target_specifier nélkül az alapértelmezett érték van alkalmazva, de egy attribute_target_specifier is használható az alapértelmezett beállítás megerősítésére vagy felülbírálására. A környezetek a következőképpen lesznek feloldva:
- A delegált deklarációban szereplő attribútumok esetében az alapértelmezett cél a meghatalmazott. Ellenkező esetben, ha a attribute_target egyenlő:
-
type— a cél a meghatalmazott -
return— a cél a visszatérési érték
-
- Egy metódusdeklaráció egyik attribútuma esetében az alapértelmezett cél a metódus. Ellenkező esetben, ha a attribute_target egyenlő:
-
method— a cél a módszer -
return— a cél a visszatérési érték
-
- Egy helyi függvény deklarációján lévő attribútum esetében az alapértelmezett cél a helyi függvény. Ellenkező esetben, ha a attribute_target egyenlő:
-
method— a cél a helyi függvény -
return— a cél a visszatérési érték
-
- Egy operátor-deklaráció egyik attribútuma esetében az alapértelmezett cél az operátor. Ellenkező esetben, ha a attribute_target egyenlő:
-
method— a cél az operátor -
return— a cél a visszatérési érték
-
- Tulajdonság vagy indexelő deklarációhoz tartozó beolvasási kiegészítő deklaráción szereplő attribútum esetében az alapértelmezett cél a társított módszer. Ellenkező esetben, ha a attribute_target egyenlő:
-
method— a cél a társított módszer -
return— a cél a visszatérési érték
-
- Egy tulajdonság vagy indexelő deklaráció készletén vagy init tartozékán megadott attribútum esetében az alapértelmezett cél a társított módszer. Ellenkező esetben, ha a attribute_target egyenlő:
-
method— a cél a társított módszer -
param— a cél a magányos implicit paraméter
-
- Az automatikusan implementált tulajdonságdeklarációban szereplő attribútumok esetében az alapértelmezett cél a tulajdonság. Ellenkező esetben, ha a attribute_target egyenlő:
-
field— a cél a tulajdonság fordító által létrehozott háttérmezője
-
- Egy eseménydeklarációban megadott attribútum esetében, amely kihagyja event_accessor_declarations az alapértelmezett cél az eseménydeklaráció. Ellenkező esetben, ha a attribute_target egyenlő:
-
event– a cél az eseménydeklaráció -
field— a cél a mező -
method— a célok a módszerek
-
- Olyan eseménydeklaráció esetén, amely nem hagyja ki event_accessor_declarations az alapértelmezett cél a metódus.
-
method— a cél a társított módszer -
param— a cél a magányos paraméter
-
- Egy lambda_expression attribútum esetében az alapértelmezett cél a metódus. Ellenkező esetben, ha a attribute_target egyenlő:
-
method— a cél a módszer -
return— a cél a visszatérési érték
-
Minden más kontextusban a attribute_target_specifier felvétele engedélyezett, de szükségtelen.
Példa: az osztálydeklaráció tartalmazhat vagy kihagyhat egy kijelölőt
type:[type: Author("Brian Kernighan")] class Class1 {} [Author("Dennis Ritchie")] class Class2 {}záró példa.
A implementációk más attribute_targetis elfogadhatnak, amelyek céljait a megvalósítás határozza meg. Az ilyen attribute_target nem felismerő végrehajtás figyelmeztetést ad ki, és figyelmen kívül hagyja a attribute_section.
Konvenció szerint az attribútumosztályok neve a következő utótaggal Attributevan elnevezve: . Egy attribute_name belefoglalhatja vagy kihagyhatja ezt az utótagot.
A attribute_name az alábbiak szerint oldjuk fel:
- Ha a attribute_name jobb oldali azonosítója szó szerinti azonosító (6.4.3. §), akkor a attribute_name type_name (7.8. §) oldja fel. Ha az eredmény nem a következő típusból
System.Attributeszármazik, fordítási időhiba lép fel. - Egyébként
- A attribute_name type_name (7.8. §) oldja fel, kivéve a hibákat. Ha ez a megoldás sikeres, és egy származtatott
System.Attributetípust eredményez, akkor a típus ennek a lépésnek az eredménye. - A karakterek
Attributehozzá vannak fűzve a attribute_name jobb oldali azonosítóhoz, és az eredményül kapott jogkivonat-sztring type_name ként (7.8. §) lesz feloldva, kivéve a hibákat. Ha ez a megoldás sikeres, és egy származtatottSystem.Attributetípust eredményez, akkor a típus ennek a lépésnek az eredménye.
- A attribute_name type_name (7.8. §) oldja fel, kivéve a hibákat. Ha ez a megoldás sikeres, és egy származtatott
Ha a fenti két lépés közül pontosan az egyik származik System.Attribute, akkor ez a típus a attribute_name eredménye. Ellenkező esetben fordítási időhiba lép fel.
Példa: Ha egy attribútumosztály található az utótaggal együtt és nélkül is, akkor kétértelműség és fordítási idő hibát eredményez. Ha a attribute_name úgy van beírva, hogy a jobb szélső azonosító egy szó szerinti azonosító (6.4.3. §), akkor csak utótag nélküli attribútummal egyeznek meg, ami lehetővé teszi az ilyen kétértelműség feloldását. A példa
[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 {}két attribútumosztály neve
ExampleésExampleAttribute. Az attribútum[Example]nem egyértelmű, mivel hivatkozhat rá vagyExampleExampleAttribute. A szó szerinti azonosító használata lehetővé teszi a pontos szándék megadását ilyen ritka esetekben. Az attribútum[ExampleAttribute]nem egyértelmű (bár az lenne, ha lenne egy !nevűExampleAttributeAttributeattribútumosztály). Ha az osztályExampledeklarációja el lett távolítva, akkor mindkét attribútum a következő nevűExampleAttributeattribútumosztályra hivatkozik:[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 {}záró példa
Fordítási időhiba, ha egy egyszer használt attribútumosztályt többször is használ ugyanazon az entitáson.
Példa: A példa
[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 {}fordítási idő hibát eredményez, mert az egyszer használatos attribútumosztályt többször is megpróbálja használni
HelpStringa deklarációnClass1.záró példa
A kifejezés E egy attribute_argument_expression , ha az alábbi állítások mindegyike igaz:
- A típus
Eegy attribútumparaméter típusa (23.2.4. §). - Fordításkor az érték
Eaz alábbiak egyikével oldható fel:- Állandó érték.
- Olyan
System.Typeobjektum, amely typeof_expression (12.8.18. §) használatával kapott, amely nem általános típust, zárt építésű típust (8.4.3. §) vagy kötetlen általános típust (8.4.4. §) határoz meg, de nyílt típust nem (8.4.3. §). - Attribute_argument_expression egydimenziós tömbje.
Példa:
[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; }záró példa
A több részben deklarált típus attribútumait úgy határozzuk meg, hogy meghatározatlan sorrendben egyesítjük az egyes részek attribútumait. Ha ugyanazt az attribútumot több részre helyezi, az egyenértékű azzal, hogy az attribútumot többször is megadja a típuson.
Példa: A két rész:
[Attr1, Attr2("hello")] partial class A {} [Attr3, Attr2("goodbye")] partial class A {}egyenértékűek a következő egyetlen deklarációval:
[Attr1, Attr2("hello"), Attr3, Attr2("goodbye")] class A {}záró példa
A típusparaméterek attribútumai ugyanúgy egyesíthetők.
23.4 Attribútumpéldányok
23.4.1 Általános
Az attribútumpéldányok olyan példányok, amelyek futásidőben egy attribútumot jelölnek. Az attribútumokat attribútumosztály, pozícióargumentumok és elnevezett argumentumok határozzák meg. Az attribútumpéldány annak az attribútumosztálynak a példánya, amely a pozíció- és elnevezett argumentumokkal inicializálva van.
Az attribútumpéldányok lekérése a fordítási és a futásidejű feldolgozást is magában foglalja az alábbi alklámokban leírtak szerint.
23.4.2 Attribútum összeállítása
A programentitásokon megadott és positional_argument_list, T attribútumosztályt Ptartalmazó attribútumNa következő lépések végrehajtásával lesz összeállítva egy szerelvénybeE:A
- Kövesse a fordítási idő feldolgozási lépéseit összeállításához. Ezek a lépések fordítási időt eredményeznek, vagy meghatároznak egy példánykonstruktort
CT, amely futásidőben hívható meg. - Ha
Cnem rendelkezik nyilvános akadálymentességgel, fordítási időhiba lép fel. - Minden named_argument
Arga következőbenN:- Legyen
Namea . -
Nameazonosítja a nem statikus olvasási-írási nyilvános mezőt vagy a nyilvános, nem statikus írási vagy olvasási init tulajdonságot a következő helyenT: . HaTnincs ilyen mezője vagy tulajdonsága, akkor fordítási időhiba lép fel.
- Legyen
- Ha a positional_argument_list
Pvagy a named_argument_listNvalamelyik értéke típusúSystem.String, és az érték nem megfelelően van formázva a Unicode Szabványban meghatározottak szerint, akkor implementálási meghatározást kell alkalmazni, hogy a lefordított érték megegyezik-e a lekért futásidejű értékkel (23.4.3. §).Megjegyzés: Például egy sztring, amely egy magas helyettesítő UTF-16 kódegységet tartalmaz, amelyet nem követ azonnal egy alacsony helyettesítő kódegység, nem jól formázott. végjegyzet
- Tárolja a következő információkat (az attribútum futásidejű példányosításához) a fordító által a szerelvény kimenetében az attribútumot tartalmazó program összeállítása eredményeképpen: az attribútumosztály
T, a példánykonstruktorCT, , aPés a kapcsolódó programentitássalN, az értékek fordítási időpontban teljesen feloldva.
23.4.3 Attribútumpéldány futásidejű lekérése
A 23.4.2. §-ban meghatározott kifejezések használatával a , T, C, és , attribútumpéldány által Pképviselt és Ntársított E attribútumpéldány futásidőben lekérhető a szerelvényből A az alábbi lépések végrehajtásával:
- Kövesse az űrlap egy object_creation_expression végrehajtásának futásidejű feldolgozási lépéseit a példánykonstruktor
new T(P)és a fordítási időpontbanCmeghatározott értékek használatával. Ezek a lépések kivételt eredményeznek, vagy létrehoznak egy példánytO.T - Minden named_argument
ArgNsorrendben:- Legyen
Namea . HaNamenem azonosít nem statikus nyilvános olvasási-írási mezőt vagy nem statikus nyilvános olvasási-írási vagy olvasási init tulajdonságotO, akkor kivétel történik. - Nézzük
Valuemeg a attribute_argument_expression kiértékelésénekArgeredményét. - Ha
Nameazonosít egy mezőtO, akkor állítsa ezt a mezőt a következőreValue: . - Ellenkező esetben a Name (Név) tulajdonság azonosítja a (z) tulajdonságot
O. Állítsa ezt a tulajdonságot Érték értékre. - Az eredmény a
Opositional_argument_list és a named_argument_listTinicializált attribútumosztályPegy példánya.
- Legyen
Megjegyzés: A tárolás, ,
T,C,P(és társításNE) formátumaA, valamint a megadhatjaEés lekérniTkívánt mechanizmus, a ,C,PNA, a (és így az attribútumpéldány futásidőben történő lekérésének módja) túllépi a specifikáció hatókörét. végjegyzet
23.5 Fenntartott attribútumok
23.5.1 Általános
Számos attribútum valamilyen módon befolyásolja a nyelvet. Ezek az attribútumok a következők:
-
System.AttributeUsageAttribute(23.5.2. §), amely az attribútumosztályok felhasználási módjait ismerteti. -
System.Diagnostics.ConditionalAttribute(23.5.3. §) egy többfelhasználós attribútumosztály, amely feltételes metódusok és feltételes attribútumosztályok definiálására szolgál. Ez az attribútum egy feltételes fordítási szimbólum tesztelésével jelez egy feltételt. -
System.ObsoleteAttribute(23.5.4. §), amely egy tag elavultként való megjelölésére szolgál. -
System.Runtime.CompilerServices.AsyncMethodBuilderAttribute(23.5.5.5. §), amely egy aszinkron metódus feladatszerkesztőjének létrehozására szolgál. -
System.Runtime.CompilerServices.CallerLineNumberAttribute(23.5.6.2. §),System.Runtime.CompilerServices.CallerFilePathAttribute(23.5.6.3. §),System.Runtime.CompilerServices.CallerMemberNameAttribute(23.5.6.4. §) ésSystem.Runtime.CompilerServices.CallerArgumentExpressionAttribute(23.5.6.5.5. §), amelyek a hívó környezettel kapcsolatos információk opcionális paramétereknek való megadására szolgálnak. -
System.Runtime.CompilerServices.EnumeratorCancellationAttribute(23.5.8. §), amely a lemondási jogkivonat paraméterének megadására szolgál egy aszinkron iterátorban. -
System.Runtime.CompilerServices.ModuleInitializer(23.5.9. §), amely egy metódus modul inicializálójaként való megjelölésére szolgál. -
System.Runtime.CompilerServices.InterpolatedStringHandlerAttributeésSystem.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute, amelyek egy egyéni interpolált sztringkifejezés-kezelő deklarálásához (§23.5.9.1) és annak egyik konstruktorának meghívásához használatosak.
A null értékű statikus elemzési attribútumok (23.5.7.§) javíthatják a nulla képességekre és nullállapotokra generált figyelmeztetések helyességét (8.9.5. §).
A végrehajtási környezetek további implementáció által definiált attribútumokat biztosíthatnak, amelyek befolyásolják a C#-programok végrehajtását.
23.5.2 Az AttributeUsage attribútum
Az attribútum AttributeUsage az attribútumosztály használható módjának leírására szolgál.
Az attribútummal AttributeUsage ellátott osztálynak közvetlenül vagy közvetve kell származnie System.Attribute. Ellenkező esetben fordítási időhiba lép fel.
Megjegyzés: Az attribútum használatára példa: §23.2.2. végjegyzet
23.5.3 A feltételes attribútum
23.5.3.1 Általános
Az attribútum Conditional lehetővé teszi az s feltételes metódus, a feltételes helyi függvényés a feltételes attribútum osztályes definícióját.
23.5.3.2 Feltételes módszerek
Az attribútummal Conditional díszített metódus feltételes módszer. Így minden feltételes módszer társítva van az attribútumaiban Conditional deklarált feltételes fordítási szimbólumokkal.
Példa:
class Eg { [Conditional("ALPHA")] [Conditional("BETA")] public static void M() { // ... } }feltételes metódusként deklarál
Eg.Ma két feltételes fordításiALPHAszimbólumhoz ésBETA.záró példa
Egy feltételes metódus hívása akkor jelenik meg, ha egy vagy több társított feltételes fordítási szimbólum a hívás időpontjában van definiálva, ellenkező esetben a hívás nem lesz megadva.
A feltételes módszerekre a következő korlátozások vonatkoznak:
- A feltételes módszer egy class_declaration vagy struct_declaration metódusa. Fordítási időhiba akkor fordul elő, ha az
Conditionalattribútum egy felületi deklarációban megadott metóduson van megadva. - A feltételes módszer nem lehet tulajdonság, indexelő vagy esemény tartozéka.
- A feltételes módszer visszatérési
voidtípusa . - A feltételes módszert nem szabad megjelölni a
overridemódosítóval. A feltételes metódusok azonban megjelölhetők avirtualmódosítóval. Az ilyen módszer felülbírálása implicit módon feltételes, és nem jelölhető meg explicit módon attribútummalConditional. - A feltételes módszer nem lehet interfészmetódus alkalmazása. Ellenkező esetben fordítási időhiba lép fel.
- A feltételes módszer paraméterei nem lehetnek kimeneti paraméterek.
Megjegyzés: A (
AttributeUsage) attribútumok általábanAttributeTargets.Methodalkalmazhatók a tulajdonságok, indexelők és események tartozékaira. A fenti korlátozások tiltják azConditionalattribútum használatát. végjegyzet
Emellett fordítási idő hibát is tapasztal, ha egy meghatalmazott feltételes metódusból jön létre.
Példa: A példa
#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(); } }feltételes módszerként deklarál
Class1.M.Class2's metódus meghívjaTestezt a metódust. Mivel a feltételes fordítási szimbólumDEBUGdefiniálva van, haClass2.Testa rendszer meghívja, meghívjaM. Ha a szimbólumDEBUGnincs definiálva, akkorClass2.Testnem hívná megClass1.M.záró példa
Fontos tisztában lenni azzal, hogy a feltételes metódusra irányuló hívás felvételét vagy kizárását a hívás helyén lévő feltételes fordítási szimbólumok szabályozzák.
Példa: Az alábbi kódban
// 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 } }az osztályok
Class2ésClass3mindegyik a feltételes metódusClass1.Fhívásait tartalmazza, amely feltételes attól függően, hogy definiálva van-e.DEBUGMivel ez a szimbólum a környezetébenClass2van definiálva, de nemClass3, a rendszer a benne lévőFhívástClass2is tartalmazza, míg a betárcsázhatóFClass3hívás nincs megadva.záró példa
A feltételes módszerek használata az öröklési láncban zavaró lehet. A feltételes metódushoz az űrlapon basekeresztül base.Mindított hívásokra a normál feltételes metódushívási szabályok vonatkoznak.
Példa: Az alábbi kódban
// 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 } }
Class2AM /> az alaposztályban meghatározott hívásokat tartalmazza. Ez a hívás ki van hagyva, mert az alapmetódus feltételes, a szimbólum DEBUGjelenléte alapján, amely nincs meghatározva. Így a metódus csak "Class2.M executed" a konzolra ír. Az pp_declaration-kmegfontolt használata kiküszöbölheti az ilyen problémákat.záró példa
23.5.3.3 Feltételes helyi függvények
A statikus helyi függvények feltételessé tehetők a feltételes módszerrel azonos értelemben (23.5.3.2. §).
Fordítási időhiba akkor fordul elő, ha egy nem statikus helyi függvény feltételessé lett téve.
23.5.3.4 Feltételes attribútumosztályok
Egy vagy több attribútummal dekorált attribútumosztály (Conditional) feltételes attribútumosztály. A feltételes attribútumosztály így társítva van az attribútumaiban Conditional deklarált feltételes fordítási szimbólumokkal.
Példa:
[Conditional("ALPHA")] [Conditional("BETA")] public class TestAttribute : Attribute {}feltételes attribútumosztályként deklarálja
TestAttributea feltételes fordítási szimbólumokhozALPHAésBETAa .záró példa
A feltételes attribútum attribútumspecifikációi (23.3. §) akkor szerepelnek, ha egy vagy több társított feltételes fordítási szimbólum a specifikáció helyén van meghatározva, ellenkező esetben az attribútum specifikációja nem szerepel.
Fontos megjegyezni, hogy a feltételes attribútumosztály attribútumspecifikációjának felvételét vagy kizárását a specifikáció helyén található feltételes fordítási szimbólumok szabályozzák.
Példa: A példában
// 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 {}osztályokat
Class1, ésClass2mindegyik attribútummalTestvan dekorálva, amely feltételes attól függően, hogy definiálva van-e vagy semDEBUG. Mivel ez a szimbólum a kontextusbanClass1van definiálva, de nemClass2, a tesztattribútumClass1specifikációja is szerepel, míg aTestrajta lévőClass2attribútum specifikációja nem szerepel.záró példa
23.5.4 Az elavult attribútum
Az attribútum Obsolete olyan típusok és tagok megjelölésére szolgál, amelyeket már nem szabad használni.
Ha egy program olyan típust vagy tagot használ, amelyet a Obsolete attribútum díszít, a fordító figyelmeztetést vagy hibát ad ki. A fordítónak figyelmeztetést kell adnia, ha nem ad meg hibaparamétert, vagy ha a hibaparaméter meg van adva, és falseértékkel rendelkezik. A fordító hibát ad ki, ha a hibaparaméter meg van adva, és trueértékkel rendelkezik.
Példa: Az alábbi kódban
[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(); } }az osztályt
AazObsoleteattribútum díszíti. Minden egyes használatAegy figyelmeztetésbenMainjelenik meg, amely tartalmazza a megadott üzenetet: "Ez az osztály elavult; helyett használja az osztálytB".záró példa
23.5.5 Az AsyncMethodBuilder attribútum
Ezt az attribútumot a 15.14.1 szakaszban leírják.
23.5.6 Hívóinformációs attribútumok
23.5.6.1 Általános
A naplózáshoz és a jelentéskészítéshez néha hasznos, ha a függvénytagok bizonyos fordítási időre vonatkozó információkat szereznek be a hívó kódról. A hívóinformációs attribútumok lehetővé teszik az információk transzparens átadását.
Ha egy választható paramétert a hívó-info attribútumok egyikével jegyzetel, a hívás megfelelő argumentumának kihagyása nem feltétlenül eredményezi az alapértelmezett paraméterérték helyettesítését. Ehelyett, ha a hívási környezettel kapcsolatos megadott információk rendelkezésre állnak, a rendszer argumentumértékként adja át az adatokat.
Példa:
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); }Az argumentumok nélküli hívás
Log()kinyomtatja a hívás sorszámát és fájl elérési útját, valamint annak a tagnak a nevét, amelyen belül a hívás történt.záró példa
A hívóinformációs attribútumok bárhol előfordulhatnak választható paramétereken, beleértve a delegált deklarációkat is. Az adott hívóinformációs attribútumok azonban korlátozzák az attribútumok típusait, így mindig implicit átalakítás lesz a helyettesítő értékről a paramétertípusra.
Hiba, ha ugyanazzal a hívó-info attribútummal rendelkezik egy részleges metódusdeklaráció definiáló és implementáló részének paraméterén. A rendszer csak a definiáló rész hívóinformációs attribútumait alkalmazza, míg a csak a megvalósító részben előforduló hívó-info attribútumokat a rendszer figyelmen kívül hagyja.
A hívó adatai nem befolyásolják a túlterhelés feloldását. Mivel az attribútumként megadott opcionális paraméterek továbbra is kimaradnak a hívó forráskódjából, a túlterhelés feloldása ugyanúgy figyelmen kívül hagyja ezeket a paramétereket, mint a többi kihagyott opcionális paramétert (12.6.4. §).
A hívóadatok csak akkor lesznek helyettesítve, ha a forráskód kifejezetten meghív egy függvényt. Az implicit meghívások, például az implicit szülőkonstruktorhívások nem rendelkeznek forráshellyel, és nem helyettesítik a hívó adatait. Emellett a dinamikusan kötött hívások nem helyettesítik a hívó adatait. Ha ilyen esetekben egy hívóinformációs attribútummal rendelkező paramétert hagy ki, a rendszer ehelyett a paraméter megadott alapértelmezett értékét használja.
Az egyik kivétel a lekérdezési kifejezések. Ezek szintaktikai expanzióknak minősülnek, és ha az általuk kibontott hívások nem kötelező paramétereket hagynak ki hívóinformációs attribútumokkal, a hívó információi lecserélődnek. A használt hely annak a lekérdezési záradéknak a helye, ahonnan a hívást létrehozták.
Ha egy adott paraméteren egynél több hívó-info attribútum van megadva, a rendszer a következő sorrendben ismeri fel őket: CallerLineNumber, CallerFilePath, CallerMemberName, CallerArgumentExpression. Vegye figyelembe a következő paraméterdeklarációt:
[CallerMemberName, CallerFilePath, CallerLineNumber] object p = ...
CallerLineNumber elsőbbséget élvez, a másik három attribútumot pedig figyelmen kívül hagyja. Ha CallerLineNumber nem lett volna megadva, CallerFilePath elsőbbséget élvezne, és CallerMemberNameCallerArgumentExpression figyelmen kívül hagyná. Ezeknek az attribútumoknak a lexikális sorrendje irreleváns.
23.5.6.2 A CallerLineNumber attribútum
Az attribútum System.Runtime.CompilerServices.CallerLineNumberAttribute akkor engedélyezhető választható paramétereken, ha az állandó értékről a paraméter típusára standard implicit átalakítás (int.MaxValue. §) van. Ez biztosítja, hogy az adott értékig nem negatív sorszám hiba nélkül átadható legyen.
Ha a forráskód egy helyéről történő függvényhívás kihagy egy választható paramétert a CallerLineNumberAttributeforráskódban, akkor a rendszer az alapértelmezett paraméterérték helyett argumentumként az adott hely sorszámát képviselő numerikus literált használja.
Ha a meghívás több sorra is kiterjed, a kiválasztott sor implementációfüggő.
A sorszámot az irányelvek befolyásolhatják #line (6.5.8. §).
23.5.6.3 A CallerFilePath attribútum
Az attribútum System.Runtime.CompilerServices.CallerFilePathAttribute akkor engedélyezhető választható paramétereken, ha a paraméter típusához standard implicit átalakítás (string. §) tartozik.
Ha a forráskód egy helyéről történő függvényhívás kihagy egy választható paramétert a forráskódban, akkor az CallerFilePathAttributealapértelmezett paraméterérték helyett az adott hely fájlútvonalát képviselő sztringkonstanst használ a rendszer a meghívás argumentumaként.
A fájl elérési útjának formátuma implementációfüggő.
A fájl elérési útját az irányelvek befolyásolhatják #line (6.5.8. §).
23.5.6.4 A CallerMemberName attribútum
Az attribútum System.Runtime.CompilerServices.CallerMemberNameAttribute akkor engedélyezhető választható paramétereken, ha a paraméter típusához standard implicit átalakítás (string. §) tartozik.
Ha egy függvényhívás egy függvénytag törzsén belüli helyről vagy a függvénytagra alkalmazott attribútumon belül, vagy annak visszatérési típusa, a forráskódban szereplő paraméterek vagy típusparaméterek kihagynak egy választható paramétert a CallerMemberNameAttributekövetkezővel, akkor a rendszer az alapértelmezett paraméterérték helyett argumentumként az adott tag nevét képviselő karakterlánc-literált használja a meghíváshoz. (Legfelső szintű utasításból (7.1.3.§) származó függvényhívás esetén a tag neve a végrehajtás által generált.)
Az általános metódusokon belül előforduló meghívások esetén a típusparaméter-lista nélkül csak a metódus nevét használja a rendszer.
Az explicit felülettag-implementációkban előforduló meghívások esetében a rendszer csak magát a metódusnevet használja az előző felületi minősítés nélkül.
A tulajdonságon vagy eseményen belüli meghívások esetén a használt tagnév maga a tulajdonság vagy az esemény neve.
Az indexelő tartozékaiban előforduló meghívások esetén a használt tagnév az indexelőtagon (IndexerNameAttribute) megadott név, ha van ilyen, vagy az alapértelmezett névItem.
A mező- vagy esemény-inicializálókban előforduló meghívások esetén a használt tagnév az inicializálandó mező vagy esemény neve.
A példánykonstruktorok, statikus konstruktorok, véglegesítők és operátorok deklarációiban előforduló meghívások esetében a használt tagnév implementációfüggő.
Helyi vagy névtelen függvényen belüli meghívás esetén a rendszer annak a tagmetódusnak a nevét használja, amely meghívja a függvényt.
Példa: Fontolja meg a következőket:
class Program { static void Main() { F1(); void F1([CallerMemberName] string? name = null) { Console.WriteLine($"F1 MemberName: |{name}|"); F2(); } static void F2([CallerMemberName] string? name = null) { Console.WriteLine($"F2 MemberName: |{name}|"); } } }amely létrehozza a kimenetet
F1 MemberName: |Main| F2 MemberName: |Main|Ez az attribútum adja meg a hívó függvény tagjának nevét, amely a helyi függvény
F1esetében a metódusMain. Annak ellenéreF2, hogy a függvény meghívjaF1, a helyi függvény nem függvénytag, így a jelentett hívóF2isMain. záró példa
23.5.6.5 A CallerArgumentExpression attribútum
Az attribútum System.Runtime.CompilerServices.CallerArgumentExpressionAttribute egy célparaméterre van alkalmazva, és egy testvérparaméter argumentumának forráskódszövegét sztringként rögzíti, amelyet itt rögzített sztringnek nevezünk.
A bővítménymetódus első paraméterének kivételével a célparaméternek default_argument kell rendelkeznie.
Vegye figyelembe a következő módszerdeklarációt:
using System;
using System.Runtime.CompilerServices;
#nullable enable
class Test
{
public static void M(int val = 0, [CallerArgumentExpression("val")] string? text = null)
{
Console.WriteLine($"val = {val}, text = <{text}>");
}
}
amelyben a célparaméter és text a testvérparaméter van val, amelynek a megfelelő argumentum forráskódszövege rögzíthető text a meghíváskor M .
Az attribútumkonstruktor típus argumentumot stringvesz fel. Ez a sztring
- A testvérparaméter nevét kell tartalmaznia; ellenkező esetben a rendszer figyelmen kívül hagyja az attribútumot.
- Kihagyja a bevezetőt
@egy olyan paraméternévből, amely rendelkezik ezzel az előtaggal.
Egy parameter_list több célparamétert is tartalmazhat.
A célparaméter típusának szabványos átalakítással kell rendelkeznie string.
Megjegyzés: Ez azt jelenti, hogy a felhasználó által definiált konverziók nem engedélyezettek
string, és a gyakorlatban azt jelenti, hogy az ilyen paraméter típusának kell lenniestring,objectvagy egy felületnek, amelyet astringrendszer implementál. végjegyzet
Ha explicit argumentumot ad át a célparaméterhez, a rendszer nem rögzíti a sztringet, és a paraméter felveszi az argumentum értékét. Ellenkező esetben a testvérparaméternek megfelelő argumentum szövege rögzített sztringgé alakul az alábbi szabályok szerint:
- A vezető és a záró fehér tér el lesz távolítva a legkülső csoportosítási zárójelek eltávolítása előtt és után is.
- Minden legkülső csoportosítási zárójel el lesz távolítva a kezdő és a záró szóköz eltávolítása előtt és után is.
- Az összes többi input_elementszó szerint megmarad (beleértve a szóközöket, a megjegyzéseket, a Unicode_Escape_Sequences-eket és
@az azonosítók előtagjait).
A rögzített sztring ezután a célparaméternek megfelelő argumentumként lesz átadva. Ha azonban a testvérparaméter argumentuma nincs megadva, a célparaméter a default_argument értékét veszi fel.
Példa: Tekintettel a fenti deklarációra
M, vegye figyelembe a következő hívásokatM:Test.M(); Test.M(123); Test.M(123, null); Test.M(123, "xyz"); Test.M( 1 + 2 ); Test.M(( ( (123) + 0) ) ); int local = 10; Test.M(l\u006fcal /*...*/ + // xxx 5);a létrehozott kimenet
val = 0, text = <> val = 123, text = <123> val = 123, text = <> val = 123, text = <xyz> val = 3, text = <1 + 2> val = 123, text = <(123) + 0> val = 15, text = <l\u006fcal /*...*/ + // xxx 5>záró példa
23.5.7 Kódelemzési attribútumok
23.5.7.1 Általános
Az alcím attribútumai további információkat nyújtanak a nullabilitás és null állapotú diagnosztikát biztosító fordítók támogatásához (§8.9.5). A nullállapotú diagnosztika elvégzéséhez nincs szükség fordítóra. Ezeknek az attribútumoknak a jelenléte vagy hiánya nem befolyásolja a program nyelvét és viselkedését. A nullállapot-diagnosztikát nem biztosító fordítónak be kell olvasnia és figyelmen kívül kell hagynia ezeknek az attribútumoknak a jelenlétét. A nullállapot-diagnosztikát biztosító fordítónak az ebben az albekezdésben meghatározott jelentést kell használnia azokra az attribútumokra, amelyeket diagnosztikai célból használ.
A kódelemzési attribútumok névtérben System.Diagnostics.CodeAnalysisvannak deklarálva.
| Attribútum | Jelentés |
|---|---|
AllowNull (23.5.7.2. §) |
A nem null értékű argumentumok lehetnek null értékűek. |
DisallowNull (23.5.7.3. §) |
A null értékű argumentumok soha nem lehetnek null értékűek. |
MaybeNull (23.5.7.6. §) |
A nem null értékű visszatérési érték null értékű lehet. |
NotNull (23.5.7.10. §) |
A null értékű visszatérési érték soha nem lesz null értékű. |
MaybeNullWhen (23.5.7.7. §) |
A nem null értékű argumentum null értékű lehet, ha a metódus a megadott bool értéket adja vissza. |
NotNullWhen (23.5.7.12. §) |
A null értékű argumentumok nem lesznek null értékűek, ha a metódus a megadott bool értéket adja vissza. |
NotNullIfNotNull (23.5.7.11. §) |
A visszatérési érték nem null, ha a megadott paraméter argumentuma nem null. |
MemberNotNull (23.5.7.8. §) |
A listában szereplő tag nem lesz null értékű, amikor a metódus visszatér. |
MemberNotNullWhen (23.5.7.9. §) |
A listában szereplő tag nem lesz null értékű, ha a metódus a megadott bool értéket adja vissza. |
DoesNotReturn (23.5.7.4. §) |
Ez a metódus soha nem tér vissza. |
DoesNotReturnIf (23.5.7.5. §) |
Ez a metódus soha nem ad vissza értéket, ha a társított bool paraméter a megadott értékkel rendelkezik. |
A 23.5.7. § -ban a következő alklámok feltételesen normatívak.
23.5.7.2 Az AllowNull attribútum
Megadja, hogy a null érték akkor is engedélyezett bemenetként, ha a megfelelő típus nem engedélyezi azt.
Példa: Fontolja meg az alábbi olvasási/írási
nulltulajdonságot, amely soha nem ad vissza, mert ésszerű alapértelmezett értékkel rendelkezik. A felhasználó azonban null értéket adhat a beállított tartozéknak, hogy a tulajdonságot az alapértelmezett értékre állítsa.#nullable enable public class X { [AllowNull] public string ScreenName { get => _screenName; set => _screenName = value ?? GenerateRandomScreenName(); } private string _screenName = GenerateRandomScreenName(); private static string GenerateRandomScreenName() => ...; }Tekintettel a tulajdonság készlettartozékának alábbi használatára
var v = new X(); v.ScreenName = null; // may warn without attribute AllowNullaz attribútum nélkül a fordító figyelmeztetést generálhat, mert úgy tűnik, hogy a nem null értékű tulajdonság null értékűre van állítva. Az attribútum jelenléte letiltja ezt a figyelmeztetést. záró példa
23.5.7.3 A DisallowNull attribútum
Megadja, hogy a null érték nem engedélyezett bemenetként, még akkor is, ha a megfelelő típus engedélyezi.
Példa: Vegye figyelembe az alábbi tulajdonságot, amelyben a null az alapértelmezett érték, de az ügyfelek csak nem null értékűre állíthatják be.
#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; }A lekérő metódus visszaadhatja a
nullalapértelmezett értékét, ezért a fordító figyelmeztetheti, hogy a hozzáférést megelőzően ellenőrizni kell. Emellett arra is figyelmezteti a hívókat, hogy annak ellenére, hogy null értékű lehet, a hívónak nem szabad explicit módon null értékre állítania. záró példa
23.5.7.4 A DoesNotReturn attribútum
Azt adja meg, hogy egy adott metódus soha nem ad vissza.
Példa: Fontolja meg a következőket:
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; }Az attribútum jelenléte számos módon segíti a fordítót. Először is a fordító figyelmeztetést adhat ki, ha van olyan elérési út, ahol a metódus kivétel nélkül kiléphet. Másodszor, a fordító el tudja tiltani a null értékű figyelmeztetéseket bármely kódban az adott metódus meghívása után, amíg meg nem találja a megfelelő fogási záradékot. Harmadszor, a nem elérhető kód semmilyen null állapotra nem lesz hatással.
Az attribútum nem változtatja meg az elérhetőséget (13.2.§) vagy a határozott hozzárendelést (§9.4) az attribútum jelenléte alapján. Csak a nullitásra vonatkozó figyelmeztetések befolyásolására használható. záró példa
23.5.7.5 A DoesNotReturnIf attribútum
Azt adja meg, hogy egy adott metódus soha nem ad vissza értéket, ha a társított bool paraméter a megadott értékkel rendelkezik.
Példa: Fontolja meg a következőket:
#nullable enable public class X { private void ThrowIfNull([DoesNotReturnIf(true)] bool isNull, string argumentName) { if (isNull) { throw new ArgumentException(argumentName, $"argument {argumentName} cannot 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!; }záró példa
23.5.7.6 A MaybeNull attribútum
Azt határozza meg, hogy a nem null értékű visszatérési érték null értékű lehet.
Példa: Fontolja meg a következő általános módszert:
#nullable enable [return: MaybeNull] public T Find<T>(IEnumerable<T> sequence, Func<T, bool> predicate) { ... }Az attribútum nélkül a fordító figyelmeztetést generálhat, ha a metódus vissza tud térni
null. Az attribútum jelenléte letiltja ezt a figyelmeztetést. záró példa
23.5.7.7 A MaybeNullWhen attribútum
Azt adja meg, hogy nem null értékű argumentum lehet null , ha a metódus a megadott bool értéket adja vissza. Ez hasonló az MaybeNull attribútumhoz (23.5.7.6. §), de tartalmaz egy paramétert a megadott visszatérési értékhez.
23.5.7.8 A MemberNotNull attribútum
Azt adja meg, hogy az adott tag nem lesz null , amikor a metódus visszatér.
Példa: Egy segédmetódus tartalmazhat olyan attribútumot, amely felsorolja az
MemberNotNulladott metódus nem null értékéhez rendelt mezőket. Egy olyan fordító, amely konstruktorokat elemez annak megállapítására, hogy az összes nem null értékű referenciamező inicializálva lett-e, ezt az attribútumot használhatja annak felderítésére, hogy mely mezők lettek beállítva ezek a segédmeteorizálási módszerek. Vegye figyelembe a következő példát:#nullable enable public class Container { private string _uniqueIdentifier; // must be initialized. private string? _optionalMessage; public Container() { Helper(); } public Container(string message) { Helper(); _optionalMessage = message; } [MemberNotNull(nameof(_uniqueIdentifier))] private void Helper() { _uniqueIdentifier = DateTime.Now.Ticks.ToString(); } }Több mezőnév is megadható argumentumként az attribútum konstruktorának. záró példa
23.5.7.9 A MemberNotNullWhen attribútum
Azt adja meg, hogy a listatag nem lesz null , amikor a metódus visszaadja a megadott bool értéket.
Példa: Ez az attribútum hasonló
MemberNotNull(23.5.7.8. §), kivéve, haMemberNotNullWhenargumentumotboolvesz fel.MemberNotNullWhenolyan helyzetekben való használatra szolgál, amikor egy segédmetódus aztbooljelzi, hogy inicializálta-e a mezőket. záró példa
23.5.7.10 A NotNull attribútum
Azt adja meg, hogy a null értékű érték soha nem lesz null , ha a metódus (a dobás helyett) ad vissza.
Példa: Fontolja meg a következőket:
#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); }Ha engedélyezve vannak a null értékű hivatkozástípusok, a metódus
ThrowWhenNullfigyelmeztetések nélkül fordítható le. Ha ez a metódus visszatér, azvalueargumentum garantáltan nemnulllesz . A null referenciával történő hívásThrowWhenNullazonban elfogadható. záró példa
23.5.7.11 A NotNullIfNotNull attribútum
Azt adja meg, hogy a visszaadott érték nem null akkor legyen, ha a megadott paraméter argumentuma nem null.
Példa: Egy visszatérési érték null állapota egy vagy több argumentum null állapotától függhet. A fordítóelemzés segítése érdekében a
nullattribútum használható, ha egy metódus mindig nem null értéket ad vissza, amikor bizonyos argumentumok nemNotNullIfNotNullértékűek. Fontolja meg a következő módszert:#nullable enable string GetTopLevelDomainFromFullUrl(string url) { ... }Ha az
urlargumentum nemnull,nullakkor a függvény nem adja vissza. Ha engedélyezve vannak a null értékű hivatkozások, az aláírás megfelelően működik, feltéve, hogy az API soha nem fogad el null argumentumot. Ha azonban az argumentum null értékű lehet, akkor a visszatérési érték is null lehet. A szerződés helyes kifejezéséhez fűzze megjegyzésként ezt a módszert az alábbiak szerint:#nullable enable [return: NotNullIfNotNull("url")] string? GetTopLevelDomainFromFullUrl(string? url) { ... }záró példa
23.5.7.12 A NotNullWhen attribútum
Azt adja meg, hogy a null értékű argumentum nem lesz null akkor, ha a metódus a megadott bool értéket adja vissza.
Példa: A kódtár metódus
String.IsNullOrEmpty(String)akkor adtruevissza, ha az argumentumnullvagy egy üres sztring. Ez a null-ellenőrzés egyik formája: A hívóknak nem kell null-ellenőrzéssel ellenőrizni az argumentumotfalse, ha a metódus visszatér. Ha egy ilyen null értékű metódust szeretne felismerni, állítsa a paramétertípust null értékű hivatkozástípussá, és adja hozzá a NotNullWhen attribútumot:#nullable enable bool IsNullOrEmpty([NotNullWhen(false)] string? value) { ... }záró példa
23.5.8 Az EnumeratorCancellation attribútum
Megadja az aszinkron CancellationToken iterátor paraméterét (15.15. §). Ennek a paraméternek az argumentumát össze kell kapcsolni a megadott IAsyncEnumerable<T>.GetAsyncEnumerator(CancellationToken)argumentummal. Ezt az egyesített jogkivonatot IAsyncEnumerator<T>.MoveNextAsync() a (15.15.5.2. §) kell lekérdezni. A jogkivonatokat egyetlen jogkivonatba kell egyesíteni, mintha az CancellationToken.CreateLinkedTokenSource adott jogkivonat és annak tulajdonsága Token lenne. Az egyesített jogkivonat akkor lesz megszakítva, ha a két forrásjogkivonat egyikét megszakítja. Az egyesített jogkivonat az aszinkron iterátormetódus (15.15.15. §) argumentuma a metódus törzsében.
Hiba, ha az System.Runtime.CompilerServices.EnumeratorCancellation attribútum egynél több paraméterre van alkalmazva. A fordító figyelmeztetést okozhat, ha:
- Az
EnumeratorCancellationattribútum egy olyan paraméterre lesz alkalmazva, amely nemCancellationTokenaz , - vagy ha az
EnumeratorCancellationattribútum nem aszinkron iterátort használó metódus paraméterére van alkalmazva (15.15.§), - vagy ha az
EnumeratorCancellationattribútum egy olyan metódus paraméterére van alkalmazva, amely aszinkron enumerátorfelületet (15.15.2. §) aszinkron számba vevő interfész helyett aszinkron számbavételi felületet ad vissza (15.15.3. §).
Az iterátor nem fér hozzá az CancellationToken argumentumhoz GetAsyncEnumerator , ha egyetlen attribútum sem rendelkezik ezzel a paramétersel.
Példa: A metódus
GetStringsAsync()egy aszinkron iterátor. Mielőtt bármilyen munkát végez a következő érték lekérése érdekében, ellenőrzi a lemondási jogkivonatot annak megállapításához, hogy az iterációt le kell-e mondani. Ha a rendszer lemondást kér, nem történik további művelet.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(); } }záró példa
23.5.9 A ModuleInitializer attribútum
Az attribútum ModuleInitializer egy metódus modul inicializálójaként való megjelölésére szolgál. Ezt a metódust a modul inicializálása során hívjuk meg. Egy modul több inicializálóval is rendelkezhet, amelyeket implementáció által meghatározott sorrendben hív meg.
A modul inicializálójában engedélyezett kódra nincs korlátozás.
A modul inicializálójának a következő jellemzőkkel kell rendelkeznie:
- A method_modifier
static. - Nincs parameter_list.
- A return_type .
void - Nincs type_parameter_list.
- Nem deklarálható class_declarationtype_parameter_list.
- Legyen elérhető a tartalmazó modulból (azaz rendelkezik hozzáférés-módosítóval
internalvagypublic). - Nem lehet helyi függvény.
23.5.9.1 Egyéni interpolált sztringkifejezés-kezelők
23.5.9.1.1 Egyéni kezelő deklarálása
Fontolja meg a következő programot, amely egy egyszerű üzenetnaplózót implementál:
using System;
public class Logger
{
public void LogMessage(string msg)
{
Console.WriteLine(msg);
}
}
public class Program
{
static void Main()
{
var logger = new Logger();
int val = 255;
logger.LogMessage($"val = {{{val,4:X}}}; 2 * val = {2 * val}.");
}
}
A létrehozott kimenet a következő:
val = { FF}; 2 * val = 510.
A hívásban LogMessageaz interpolált sztringkifejezés argumentumának célja a paraméter msg, amelynek típusa van string. Ennek megfelelően a 12.8.3. § szerint a rendszer meghívja az alapértelmezett interpolált sztringkifejezés-kezelőt. Az alábbi alklám (23.5.9.1.1.1.) bemutatja az egyéni kezelő használatát.
Ahhoz, hogy a fenti program egyéni feldolgozást biztosíthasson, egyéni interpolált sztringkifejezés-kezelőre van szükség. Ekkor megjelenik az üzenetnaplózó egy egyéni kezelővel (amely bár nem tesz mást, mint az alapértelmezett kezelőhöz hasonlóan viselkedik, a testreszabáshoz biztosítja a horgokat):
using System;
using System.Text;
using System.Runtime.CompilerServices;
[InterpolatedStringHandler]
public ref struct LogInterpolatedStringHandler
{
StringBuilder builder; // Storage for the built-up string
public LogInterpolatedStringHandler(int literalLength, int formattedCount)
{
builder = new StringBuilder(literalLength);
}
public void AppendLiteral(string s)
{
builder.Append(s);
}
public void AppendFormatted<T>(T t)
{
builder.Append(t?.ToString());
}
public void AppendFormatted<T>(T t, string format) where T : IFormattable
{
builder.Append(t?.ToString(format, null));
}
public void AppendFormatted<T>(T t, int alignment, string format)
where T : IFormattable
{
builder.Append(String.Format("{0" + "," + alignment + ":" + format + "}", t));
}
public override string ToString() => builder.ToString();
}
public class Logger
{
public void LogMessage(string msg)
{
Console.WriteLine(msg);
}
public void LogMessage(LogInterpolatedStringHandler builder)
{
Console.WriteLine(builder.ToString());
}
}
public class Program
{
static void Main()
{
var logger = new Logger();
int val = 255;
logger.LogMessage($"val = {{{val,4:X}}}; 2 * val = {2 * val}.");
}
}
A létrehozott kimenet a következő:
val = { FF}; 2 * val = 510.
Az attribútummal System.Runtime.CompilerServices.InterpolatedStringHandlerAttribute rendelkező típus állítólag egy alkalmazható interpolált sztringkezelő típus.
Az egyéni interpolált sztringkifejezés-kezelőnek való minősítéshez egy osztály- vagy struktúratípusnak a következő jellemzőkkel kell rendelkeznie:
- Legyen megjelölve az attribútummal
System.Runtime.CompilerServices.InterpolatedStringHandlerAttribute. - Legyen egy akadálymentes konstruktor, amelynek első két paramétere típussal
intrendelkezik. (Egyéb paraméterek is követhetők, amelyek a kezelőnek vagy a kezelőtől érkező információk átadására szolgálnak. Ezekről a 23.5.9.1.3. Deklarálható egy opcionális végső paraméter, amely meggátolja a kezelőt az interpolált sztring feldolgozásában. Ezt a 23.5.9.1.2.
Amikor a fordító által létrehozott kód meghívja a konstruktort, az első paraméter az interpolált sztringkifejezések (12.8.3.§) hosszának összegére van beállítva az interpolált sztringkifejezésben, a második paraméter pedig az interpolációk számának. (Ezek az értékek a ($"val = {{{val,4:X}}}; 2 * val = {2 * val}."21- és a 2-et jelölik.)
- Legyen elérhető metódusa az aláírással
void AppendLiteral(string s), amelyet egyetlen interpolált sztringkifejezés literális szegmensének feldolgozására hívunk fel. - Legyen egy akadálymentes túlterhelt metódus
AppendFormatted, amelynek egyikét egyetlen interpoláció feldolgozására hívjuk fel az interpoláció tartalma alapján. Aláírásuk a következő:-
void AppendFormatted<T>(T t)elemet, amely az olyan interpolációkkal foglalkozik, amelyek nem rendelkeznek explicit formátummal vagy igazítással{2 * val}, mint például a . -
void AppendFormatted<T>(T t, string format) where T : System.IFormattable, amely explicit formátumú interpolációkkal foglalkozik, de nem igazítással, mint például a{val:X4}. -
void AppendFormatted<T>(T t, int alignment, string format) where T : System.IFormattable, amely explicit formátumú és igazítású interpolációkkal foglalkozik, ahogyan az{val,4:X}a .
-
- Legyen egy nyilvános metódusa az aláírással
override string ToString(), amely a beépített sztringet adja vissza.
Megjegyzés: A túlterhelések kihagyása
AppendFormattednem fordítási idejű hiba, de ha a kezelő maximálisan robusztus, az alapértelmezett kezelő által felismert összes formátumot támogatnia kell. végjegyzet
Az új túlterhelés LogMessage helyett stringegy egyéni kezelőt használ, és a sztringet a kezelő által formázott módon kéri le. Ilyen túlterhelések esetén, ha létezik egy megfelelő kezelő, és az interpolált sztringkifejezés nem állandó (12.8.3. §), a fordító kódot hoz létre, amely meghívja a kezelőt. Ilyen esetekben a fordító olyan kódot hoz létre, amely
- a kezelő konstruktor meghívása
- lexikális sorrendben az interpolált sztringkifejezésen belül
- adja át az egyes interpolált sztringkifejezés-szegmenseket a
AppendLiteral - adja át az egyes interpolációt a megfelelő módszernek
AppendFormatted.
- adja át az egyes interpolált sztringkifejezés-szegmenseket a
- az interpolált sztringkifejezés értékeként adja vissza az utolsó sztringet.
- hajtsa végre a következő törzsét
LogMessage: .
23.5.9.1.2 Egyéni kezelő akadályozása
Ha egy kezelőkonstruktor rendelkezik egy kimenő paramétert bool tartalmazó végső paraméterrel, akkor a konstruktor neve annak a paraméternek az értéke lesz tesztelve. Ha ez igaz, a viselkedés olyan, mintha a paramétert kihagyták volna. Ha azonban hamis, az interpolált sztringkifejezés feldolgozása nem történik meg tovább; vagyis a kezelő gátlásos. Az interpolációs kifejezések kiértékelése nem történik meg, a metódusok AppendLiteral pedig AppendFormatted nem lesznek meghívva.
public LogInterpolatedStringHandler(int literalLength, int formattedCount,
out bool processString)
{
if (some_condition)
{
processString = false;
return;
}
else
{
processString = true;
// continue construction
}
}
Megjegyzés: Az interpolált sztringkifejezések interpolációi mellékhatásokat tartalmazhatnak (a , , --hozzárendelés és néhány metódushívás eredményeként++). Ha egy kezelőt gátol, az interpolált sztringkifejezés egyik mellékhatását sem értékeli ki a rendszer. Ha a kezelő nem gátolja, az interpolált sztringkifejezés összes mellékhatását kiértékeli a rendszer.
végjegyzet
23.5.9.1.3 Adatok továbbítása egyéni kezelőknek vagy onnan
Hasznos lehet, ha más információkat ad át az egyéni kezelőnek, és visszafogadja az adatokat. Ez az attribútumon System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentkeresztül történik. Vegye figyelembe az alábbi új túlterheléseket az üzenetnaplózó program számára:
public class Logger
{
// …
public void LogMessage(bool flag, int count,
[InterpolatedStringHandlerArgument("count","flag","")]
LogInterpolatedStringHandler builder)
{
// …
}
}
public ref struct LogInterpolatedStringHandler
{
// …
public LogInterpolatedStringHandler(int literalLength, int formattedCount,
int count, bool flag, Logger logger)
{
// …
}
}
Az attribútumot InterpolatedStringHandlerArgument a kezelőparaméterre alkalmazza a rendszer, amely a kezelőnek átadni kívánt paraméterek deklarációit követi. Az attribútumkonstruktor argumentuma nulla vagy több olyan sztring vesszővel tagolt listája, amely az átadott paramétereket és azok sorrendjét adja meg. Egy üres sztring jelöli ki azt a példányt, amelyből a kezelőt meghívják. Ezért a fenti "count","flag","" attribútumkonstruktor-hívás egyező kezelőkonstruktort igényel. Ha az attribútumkonstruktor argumentumlistája üres, a viselkedés olyan, mintha az attribútum ki lett hagyva.
Ha egy out bool paramétert úgy is deklarálnak, hogy lehetővé teszi a kezelő akadályozását (23.5.9.1.2. §), akkor ez a paraméter lesz az utolsó.
23.6 Az együttműködés attribútumai
Más nyelvekkel való együttműködés esetén az indexelő indexelt tulajdonságok használatával implementálható. Ha egy indexelőhöz nincs IndexerName attribútum, a rendszer alapértelmezés szerint a nevet Item használja. Az IndexerName attribútum lehetővé teszi, hogy a fejlesztő felülbírálja ezt az alapértelmezett értéket, és adjon meg egy másik nevet.
Példa: Alapértelmezés szerint az indexelő neve .
ItemEzt felül lehet bírálni az alábbiak szerint:[System.Runtime.CompilerServices.IndexerName("TheItem")] public int this[int index] { get { ... } set { ... } }Most az indexelő neve .
TheItemzáró példa
ECMA C# draft specification