Megjegyzés: ebben a fejezetben az attribútum szót nem a megszokott értelemben használjuk, azaz itt nem az objektumok egy-egy tulajdonságára utal a szó.
Az attribútumok olyan objektumok, amelyekkel entitásokat jelölhetünk meg, így deklaratív információkat is hozzákapcsolhatunk a programhoz.
Egy új attribútum mindig a System.Attribute osztályból származik. Megadható, hogy az attribútum milyen entitásokhoz legyen kapcsolható: például csak osztályhoz, vagy interfészhez. Megadható az is, hogy az attribútum milyen paramétereket vár, illetve hogy mik legyek a metódusai. Ettől kezdve az attribútum bármilyen - a definícióban megadott - entitáshoz kapcsolható.
Az attribútum osztályok public konstruktorainak a paraméterlistája határozza meg a pozícionális paramétereket. Minden példányváltozó, ill. property nevesített paramétere lesz az attribútumnak. A pozícionális paraméterek mindig megelőzik a nevesítetteket az attribútum deklarációjában.
Példa:
Használata:
Némi megkötés van a paraméterek típusára vonatkozóan, ui. csak következő típusok használhatóak: bool, byte, char, double, float, int, long, short, string, object, System.Type.
A program futása alatt a felcímkézett entitás aktivációja előtt lefut az attribútum konstruktora. Az attribútumok értékei futás közben lekérdezhetőek.
Ez egy általános célú attribútum, amelyet más attribútumok deklarálásánál használhatunk fel azért, hogy meghatározzuk, hogy milyen entitáshoz kapcsoljuk az attribútumunkat.
Például:
A fenti esetben a [SimpleAttribute] attribútumunkat (amit [Simple]-ként is írhatnánk) osztályhoz vagy interfészhez kapcsolhatjuk.
Segítségével feltételes metódusokat készíthetünk. Az attribútum paraméterét kiértékelve az adott metódus a hívásra vagy végrehajtódik vagy nem.
Példák:
A delegált típust függvénymutatók kiváltására vezették be.
Példa:
Egy delegált típus definíciójában egy paramétertípus-listát és egy visszatérési értéket rögzít. Az így meghatározott delegált típussal azok a metódusok kompatibilisek, amelyek paraméterlistája és visszatérési értéke megegyezik a delegált típuséval.
Ha a függvény visszatérési értéke void akkor lehetőség van hívási listák (invocation list) megadására is. A + illetve - operátorokkal adhatóak kompatibilis metódusok a listához. Híváskor ezek fognak rendre végrehajtódni.
Példa:
Egy-egy osztály tagjaként definiálhatóak események (event), melyek az eseménykezelést egyszerűsítik. Fontos, hogy az event kulcsszó után csak delegált típus szerepelhet.
Példa:
A névtelen metódusok lehetővé teszik, hogy metódusokat (általában delegáltakat) definiáljunk közvetlenül egy esemény deklarálása után. A delegáltak definícióit oda lehet drótozni az eseményekhez. Ezek a metódusok az őket tartalmazó osztály részei, így láthatják az osztályt megvalósító adattagokat és meg is változtathatják azokat. További előny, hogy változókat lehet kötni a névtelen metódusokhoz, így hozzá lehet adni, illetve el lehet őket távolítani egy eseményből. Ugyanazok a lehetőségeink, mint az esemény deklarációknál.
Példa:
, vagy:
Ez a funkció lehetőséget ad arra, hogy egy osztály teljes definícióját fizikailag is különálló forrásfájlokban tároljuk. Ebből a célból bevezettek egy új kulcsszót, a partial -t. Egy szétválasztott osztály minden részének tartalmaznia kell a partial kulcsszót. Az osztály összes részének egy projektben kell lennie és minden formális követelménynek meg kell felelnie. Ekkor a fordító felkutatja az osztály összes részét, majd összevágja egy osztállyá, így futási időben semmi különbséget nem tapasztalunk.
A .NET keretrendszer is használja ezt a megoldást a generált és a kézzel írt kód elkülönítésére.
Példa:
A szérializáció egy folyamat, amely objektum példányokat ment merevlemezre. A művelet eltárolja az objektumok állapotait, pl.: az attribútumok értékét egy fájlba. Ennek ellentettje a deszérializáció, amely egy fájl egy adathalmazából objektumokat hoz létre.
Főbb lépések:
A deszerializáció menete hasonló, azzal az eltéréssel, hogy nem a Serialize függvényt, hanem a Deserialize -t kell meghívni.
Példa:
A C#-ban megjelent egy új módosító kulcsszó, az unsafe. Az unsafe kifejezi, hogy az entitás, melyre alkalmazzuk, olyan nyelvi elemet tartalmaz, amely nem "biztonságos". Biztonságosság alatt elsősorban a pointerkezelést kell érteni. Ilyenkor a fordító engedélyezi a pointerek kezelését, illetve a heap -ben létrehozott objektumokra a pointerállítást (fixed kulcsszó). Mivel a GC ilyenkor is működik, ezért külön jelezni kell a fordítónak, ha egy referenciát pointerrel is el akarunk érni. Az entitás lehet blokk, típus, metódus stb. A kulcsszó hatásköre a mindenkori entitás hatáskörével egyezik meg. A nem biztonságos programozási elemek az alábbiak: mutatók (akár void*), a veremfoglalás, tehát a dinamikus memóriakezelés.
Példa:
, de ahogy azt említettük, osztályok és metódusok megjelölésére is alkalmas a kulcsszó:
A CRL háromféle pointert támogat: a kezelt, a kezeletlen és a kezeletlen függvény pointereket.
A kezelt pointerek a memória használt, a heap -ben tárolt blokkjaira hivatkoznak.
A kezeletlen pointerek a tradicionális C++ pointerek, ezek csak unsafe blokkban használhatóak.
A kezeletlen függvény pointerek is tradicionális C++ pointerek, amelyek függvények címére mutatnak (a „delegate” típust tekinthetjük kezeletlen függvénypointereknek).
Pointer deklaráció példa:
A típus lehet: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, felsorolási típus, más pointer típusok, bármely a felhasználó által definiált, kezeletlen rekord típus...
Példa:
Az unsafe környezeten belül használható még a fixed utasítás. A pointerek használata a C#-ban nagyobb figyelmet igényel, mint a C++-ban. Ennek oka a garbage collector. Tisztítás alatt a garbage collector megváltoztatja az objektumok fizikai helyét, így az objektumra állított pointer rossz helyre fog mutatni a memóriában. Ezeknek a problémáknak az elkerülésére tartalmazza a C# a „fixed” kulcsszót, mely a benne létrehozott pointer helyét rögzíti a memóriában.
Példa:
, valamint pointerek inicializációja:
Ha elhagyjuk a „fixed” kulcsszót, a fordító figyelmeztetni fog a potenciális hibára, de a fordítás végrehajtódik.
Példa:
Látható, hogy ugyanarra a pointerre két különböző értéket kaptunk. A valóságban nagyon kicsi az ilyen egyszerű hibák esélye, de ennek csupán az az oka, hogy kicsi az esélye a garbage collector elindulásának.
Szabályként azonban érdemes betartani azt, hogy pointereket nem használunk fixed blokkokon kívül! A mi esetünkben a ’pi’ pointer minden használata a fixed blokkon kívül esett. Ez olyan hibákhoz vezethet, amelyeket futási időben nagyon nehéz felderíteni.
Másik unsafe környezeten belüli kulcsszó a stackalloc, ami veremből foglal le területet egy változónak.
Példa:
Bár lehet, hogy objektumorientált környezetben furcsának tűnhet a mutatók használata, a nyelv tervezői a kritikus algoritmusok és rendszerszintű elérések lehetőségének fenntartása miatt hagyták meg.
A környezet fogalmához tartozik még a DLL függvények importálásakor alkalmazott paraméterátadási érték, vagy a struktúrák igazítási módjai. Ezeket a tulajdonságokat a fent említett attribútumként lehet megadni unsafe környezetben. (PIS = Platform Invocation Services)
A másik módosító kulcsszó-pár a checked és unchecked. Ezek alkalmazhatóak blokkra és operátorként is: az egész típusú aritmetikai műveletek és konverziók túlcsordulás-ellenőrzésének be- illetve kikapcsolására használhatóak.
Megjegyzés: a mutatók használata lényegében megegyezik a C++-ban megszokottakkal, ugyanúgy használhatóak a *, -> & operátorok, valamint megtalálható pointer-aritmetika.
A C# 3.0 a nyelv következő verziója. A változások nagy részét olyan funkcionális nyelvek inspirálták, mint a Haskell, az ML, és a Language Integrated Query minta bevezetése a Common Language Runtime-ba.
A C# 3.0 -át a 2005-ös Professional Developers Conference -en mutatták be először. Az előzetes és a specifikáció a Microsoft Visual C# oldalán elérhető. Még nincs szabványosítva egy szervezet által sem, de feltehetőleg az ECMA és az ISO ezen hamarosan változtat.
A Microsoft azt nyilatkozta, hogy semmilyen változás nem lesz az új verzió futtatásában, ami azt jelenti, hogy a régi 2.0 -ás kód változtatás nélkül fordítható lesz az új compiler -rel.
Az új nyelvi elemek csak kis mértékben változtatják meg a memórián belüli lekérdezéseket, mint például a List.FindAll vagy a List.RemoveAll metódusokat.