Sunteți pe pagina 1din 162

CSharp

Adrian Zau 4 martie 2010

Cuprins
1 Prezentarea limbajului 1.1 Un program simplu . . . . . . . . . . 1.2 Tipuri . . . . . . . . . . . . . . . . . 1.2.1 Tipuri predenite . . . . . . . 1.2.2 Conversii . . . . . . . . . . . 1.2.3 Tipuri matrice . . . . . . . . 1.2.4 Sistemul de tipuri unicat . . 1.3 Variabile si parametrii . . . . . . . . 1.4 Managementul automat al memoriei 1.5 Expresii . . . . . . . . . . . . . . . . 1.6 Instruct iuni . . . . . . . . . . . . . . 1.7 Clase . . . . . . . . . . . . . . . . . . 1.7.1 Constante . . . . . . . . . . . 1.7.2 C ampuri . . . . . . . . . . . . 1.7.3 Metode . . . . . . . . . . . . 1.7.4 Propriet a ti . . . . . . . . . . 1.7.5 Evenimente . . . . . . . . . . 1.7.6 Operatori . . . . . . . . . . . 1.7.7 Indexatori . . . . . . . . . . . 1.7.8 Constructori de instant a. . . 1.7.9 Destructori . . . . . . . . . . 1.7.10 Constructori statici . . . . . . 1.7.11 Mo stenirea . . . . . . . . . . 1.8 Structuri . . . . . . . . . . . . . . . . 1.9 Interfet e . . . . . . . . . . . . . . . . 1.10 Delegat i . . . . . . . . . . . . . . . . 1.11 Enumer ari . . . . . . . . . . . . . . . 1.12 Spat ii de nume si ansamble . . . . . 1.13 Versionare . . . . . . . . . . . . . . . 1.14 Atribute . . . . . . . . . . . . . . . . 2 Concepte de baza 2.1 Pornirea aplicatiei . . . . . . . 2.2 Terminarea aplicatiei . . . . . . 2.3 Declaraii . . . . . . . . . . . . . 2.4 Membrii . . . . . . . . . . . . . 2.4.1 Membrii nume de spatiu 2.4.2 Membrii structura . . . 3 9 9 11 13 16 17 19 20 24 27 28 32 34 35 36 37 38 40 41 42 43 44 44 46 47 48 49 49 51 53 57 57 58 58 61 62 62

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

4 2.4.3 Membrii enumerare . . . . . . . . . . . . . . . 2.4.4 Membrii clasa . . . . . . . . . . . . . . . . . . 2.4.5 Membrii interfata . . . . . . . . . . . . . . . . 2.4.6 Membrii matrice . . . . . . . . . . . . . . . . 2.4.7 Membrii delegati . . . . . . . . . . . . . . . . 2.5 Accesarea membrilor . . . . . . . . . . . . . . . . . . 2.5.1 Declararea accesabilitatii . . . . . . . . . . . 2.5.2 Domenii de accesibilitate . . . . . . . . . . . 2.5.3 Protejarea accesului pentru membrii instanta 2.5.4 Constr angeri de accesabilitate . . . . . . . . . 2.6 Semnaturi si supra ncarcare . . . . . . . . . . . . . . 2.7 Domenii de vizibilitate . . . . . . . . . . . . . . . . . 2.7.1 Ascunderea numelui . . . . . . . . . . . . . . 2.8 Nume de spatiu si nume de tip . . . . . . . . . . . . 2.8.1 Nume complet calicate . . . . . . . . . . . . 2.9 Managementul automat al memoriei . . . . . . . . . 2.10 Ordinea de executie . . . . . . . . . . . . . . . . . . 3 Variabile 3.0.1 Categorii de variabile . . . . . . 3.0.2 Variabile statice . . . . . . . . . 3.0.3 Variabile de instant a . . . . . . . 3.0.4 Variabile matrice . . . . . . . . . 3.0.5 Parametrii valoare . . . . . . . . 3.0.6 Parametrii referint a . . . . . . . 3.0.7 Parametrii de ie sire . . . . . . . 3.0.8 Variabile locale . . . . . . . . . . 3.1 Valori implicite . . . . . . . . . . . . . . 3.2 Variabile cert atribuite . . . . . . . . . . 3.2.1 Variabile init ializate . . . . . . . 3.2.2 Variabile neinit ializate . . . . . . 3.2.3 Reguli pentru determinarea st arii 3.3 Variabile referint a . . . . . . . . . . . . 3.4 Atomicitatea variabilelor referint a . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

CUPRINS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62 63 63 63 63 63 63 65 67 68 69 71 74 76 78 78 81

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . de atribuire . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

83 . 83 . 84 . 84 . 84 . 84 . 85 . 85 . 85 . 86 . 86 . 88 . 88 . 88 . 100 . 101 103 103 103 104 105 105 106 107 107 107 107 107 108 111 112

4 Clase 4.1 Declararea claselor . . . . . . . . . . . . . . . 4.1.1 Modicatori pentru clase . . . . . . . 4.1.2 Specicarea claselor de baz a. . . . . . 4.1.3 Corpul claselor . . . . . . . . . . . . . 4.1.4 Declarat ii part iale . . . . . . . . . . . 4.2 Membrii claselor . . . . . . . . . . . . . . . . 4.2.1 Mo stenirea . . . . . . . . . . . . . . . 4.2.2 Modicatorul new . . . . . . . . . . . 4.2.3 Modicatoir de acces . . . . . . . . . . 4.2.4 Tipuri constituente . . . . . . . . . . . 4.2.5 Membrii statici si membrii de instant a 4.2.6 Tipuri imbricate . . . . . . . . . . . . 4.2.7 Nume de membrii rezervate . . . . . . 4.3 Constante . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

CUPRINS C ampuri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.4.1 C ampuri statice si c ampuri de instant a . . . . . . . . 4.4.2 C ampuri read-only . . . . . . . . . . . . . . . . . . . . 4.4.3 C ampuri volatile . . . . . . . . . . . . . . . . . . . . . 4.4.4 Init ializarea c ampurilor . . . . . . . . . . . . . . . . . 4.4.5 Init ializarea variabilelor . . . . . . . . . . . . . . . . . 4.5 Metode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.5.1 Parametrii metodelor . . . . . . . . . . . . . . . . . . 4.5.2 Metode statice si metode de instant a. . . . . . . . . . 4.5.3 Metode virtuale . . . . . . . . . . . . . . . . . . . . . . 4.5.4 Suprascrierea metodelor . . . . . . . . . . . . . . . . . 4.5.5 Metode sigilate . . . . . . . . . . . . . . . . . . . . . . 4.5.6 Metode abstracte . . . . . . . . . . . . . . . . . . . . . 4.5.7 Metode externe . . . . . . . . . . . . . . . . . . . . . . 4.5.8 Corpul metodelor . . . . . . . . . . . . . . . . . . . . . 4.5.9 Supra nc arcarea metodelor . . . . . . . . . . . . . . . 4.6 Propriet a ti . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.6.1 Propriet a ti statice si de instant a . . . . . . . . . . . . 4.6.2 Accesori . . . . . . . . . . . . . . . . . . . . . . . . . . 4.6.3 Accesori virtuali, sigilat i, suprascri si, supra nc arcat i . 4.7 Evenimente . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.7.1 Evenimente de tip c amp . . . . . . . . . . . . . . . . . 4.7.2 Declan sarea evenimentelor . . . . . . . . . . . . . . . . 4.7.3 Evenimente statice si de instant a . . . . . . . . . . . . 4.7.4 Declan satori virtuali, sigilat i, suprascri si sau abstract i 4.8 Indexatori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.8.1 Supra nc arcarea indexatorilor . . . . . . . . . . . . . . 4.9 Operatori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.9.1 Operatori unari . . . . . . . . . . . . . . . . . . . . . . 4.9.2 Operatori binari . . . . . . . . . . . . . . . . . . . . . 4.9.3 Operatori pentru conversie . . . . . . . . . . . . . . . 4.10 Constructorii de instant a . . . . . . . . . . . . . . . . . . . . 4.10.1 Init ializtorii constructorilor . . . . . . . . . . . . . . . 4.10.2 Init ializarea variabilelor de instant a . . . . . . . . . . 4.10.3 Execut ia constructorului . . . . . . . . . . . . . . . . . 4.10.4 Constructori implicit i . . . . . . . . . . . . . . . . . . 4.10.5 Constructori privat i . . . . . . . . . . . . . . . . . . . 4.10.6 Parametrii opt ionali ai constructorului de instant a . . 4.11 Constructori statici . . . . . . . . . . . . . . . . . . . . . . . . 4.12 Destructori . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 Iteratori 5.1 Blocuri iteratoare . . . . . . . 5.1.1 Interfet e de enumerare 5.1.2 Interfet e enumeratoare 5.1.3 Tipul yield . . . . . . 5.1.4 Accesorul this . . . . . 5.2 Obiecte enumeratoare . . . . 5.2.1 Metoda MoveNext . . 5.2.2 Proprietatea Current . 4.4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

5 113 114 114 114 115 115 117 118 121 121 123 124 124 125 126 126 126 127 127 131 132 134 136 137 137 137 140 140 140 141 141 141 142 142 142 144 144 145 145 146 149 150 150 150 150 151 151 152 153

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

6 5.2.3 Metoda Dispose . . . . . 5.2.4 Obiecte enumerabile . . . Metoda GetEnumerator . . . . . 5.3.1 Exemple de implementare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

CUPRINS . . . . . . . . . . . . . . . . 153 154 154 155

5.3

List a de tabele
1.1 1.2 1.3 Tipuri predenite . . . . . . . . . . . . . . . . . . . . . . . . . . . Operatori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Modicatori de acces . . . . . . . . . . . . . . . . . . . . . . . . . 15 27 32

DE TABELE LISTA

Capitolul 1

Prezentarea limbajului
C# (pronunt at C Sharp) este un limbaj de programare type-safe simplu, modern, orientat pe obiecte. Un limbaj este type-safe dac a acceseaz a doar zonele de memorie n care este autorizat accesul si numai ntr-un mod bine denit, cu metodele prev azute special n acest scop. Un limbaj type-safe nu poate efectua asupra unui obiect dec at operat iile valide pentru acel obiect. Acest este adoptat foarte u sor de programatorii n C si C++. C# combin a puterea brut a a limbajului C++ cu o productivitate ridicat a n scrierea programelor. In acest capitol sunt descrise principalele caracteristici ale limbajului. Fat a de capitolele urm atoare care descriu regulile si except iile ntr-o manier a matematic a detaliat a, acest capitol cont ine o prezentare informal a, c at mai put in formalizat a n detrimentul completitudinii prezent arii. Obiectivul urm arit este s a ofere cititorului o introducere despre limbaj care s a permit a scrierea rapid a a unor programe de test si s a faciliteze citirea capitolelor urm atoare.

1.1

Un program simplu

Tipurile suportate de C# sunt tip valoare si tip referint a. Dintre tipurile valoare fac parte tipurile simple (char, int si oat), enumer arile si structurile. Tipul referint a include clase, interfet e, delegat i si matrice. Tipurile valoare difer a de tipurile referint a prin aceea c a variabilele de tip valoare cont in direct valorile acestora pe c and tipurile referint a cont in o referint a c atre adresa de memoria la care este stocat a valoarea. Utiliz and tipurile referint a este posibil ca dou a variabile s a indice c atre acela si obiect de memorie, iar modicarea obiectului indicat de una dintre acestea va afecta implicit obiectul indicat de cea de a doua variabil a. Variabilele de tip valoare cont in ecare propria copie a datelor si nu este posibil ca o operat ie asupra uneia dintre acestea s a o modice pe alta. Exemplul:
using System ; class Class1 { public i n t Value = 0 ; } c l a s s Test

10
{

CAPITOLUL 1. PREZENTAREA LIMBAJULUI

s t a t i c void Main ( ) { int val1 = 0 ; int val2 = val1 ; val2 = 123; C l a s s 1 r e f 1 = new C l a s s 1 ( ) ; Class1 r e f 2 = r e f 1 ; r e f 2 . Value = 1 2 3 ; C o n s o l e . WriteLine ( " Values : {0} , {1} " , v a l 1 , v a l 2 ) ; C o n s o l e . WriteLine ( " Refs : {0} , {1} " , r e f 1 . Value , r e f 2 . Value ) ; } }

scoate n evident a aceast a diferent a. Rezultatul execut iei programului este:


Values : 0 , 123 R e f s : 1 2 3 , 123

Atribuirea unei valori variabilei locale val1 nu inuent eaz a valoarea variabilei locale val2 deoarece am andou a sunt de tip valoare (tipul int) si ecare variabil a local a de tip valoarea are propria zon a de memorare a valorii. In contrast, atribuirea ref2.Value=123; afecteaz a obiectul referit at at de variabila ref1 c at si ref2. Liniile
C o n s o l e . WriteLine ( " Values : {0} , {1} " , v a l 1 , v a l 2 ) ; C o n s o l e . WriteLine ( " Refs : {0} , {1} " , r e f 1 . Value , r e f 2 . Value ) ;

sunt utilizate pentru a dovedi cele de mai sus si ilustreaz a o parte din tehnica de formatare a sirurilor de caractere pus la dispozit ie de Console.WriteLine care utilzeaz a numere pentru a indica pozit iile variabilelor cu ale c aror valori este construit sirul a sat. Primul argument este un sir de caractere care poate cont ine referint e c atre pozit ii sub forma {0} si {1}. Fiecare referint a c atre o pozit ie indic a un argument din lista de argumente ce urmeaz a dup a sir. {0} indic a spre al doilea argument, {1} indic a spre al treilea argument si tot a sa. Inainte ca sirul indicat de primul argumenmt s a e trimis spre consol a, ecare indicator de argument este nlocuit cu valoarea formatat a cont inut a de argumentul referit. Dezvoltatorii pot deni un nou tip valoare prin enumerare sau declarat ii de structuri si pot deni noi tipuri referint a prin declararea de clase, interfet e sau delegat i. Exemplul:
using System ; public enum C o l o r { Red , Blue , Green } public struct P o i n t { public i n t x , y ; }

1.2. TIPURI

11

public i n t e r f a c e I B a s e { void F ( ) ; } public i n t e r f a c e I D e r i v e d : I B a s e { void G( ) ; } public c l a s s A { protected v i r t u a l void H( ) { C o n s o l e . WriteLine ( "A.H" ) ; } } public c l a s s B : A, I D e r i v e d { public void F ( ) { C o n s o l e . WriteLine ( "B.F , implementation of IDerived .F" ) ; } public void G( ) { C o n s o l e . WriteLine ( "B.G , implementation of IDerived .G" ) ; } override protected void H( ) { C o n s o l e . WriteLine ( "B.H , override of A.H" ) ; } } public delegate void EmptyDelegate ( ) ;

arat a cum pot declarate diverse tipuri noi. Mai t arziu vor descrise n detaliu declarat iile de tip.

1.2

Tipuri

C# suport a dou a feluri de tipuri: tip valoare si tip referint a. Dintre tipurile valoare fac parte tipurile simple (char, int si oat), enumer arile si structurile. Tipul referint a include clase, interfet e, delegat i si matrice. Tipurile valoare difer a de tipurile referint a prin aceea c a variabilele de tip valoare cont in direct valorile acestora pe c and tipurile referint a cont in o referint a c atre adresa de memorie la care este stocat a valoarea. Utiliz and tipurile referint a este posibil ca dou a variabile s a indice c atre acela si obiect de memorie, iar modicarea obiectului indicat de una dintre acestea va afecta implicit obiectul indicat de cea de a doua variabil a. Variabilele de tip valoare cont in ecare propria copie a datelor si nu este posibil ca o operat ie asupra uneia dintre acestea s a o modice pe alta. Exemplul:
using System ;

12

CAPITOLUL 1. PREZENTAREA LIMBAJULUI

class Class1 { public i n t Value = 0 ; } c l a s s Test { s t a t i c void Main ( ) { int val1 = 0 ; int val2 = val1 ; val2 = 123; C l a s s 1 r e f 1 = new C l a s s 1 ( ) ; Class1 r e f 2 = r e f 1 ; r e f 2 . Value = 1 2 3 ; C o n s o l e . WriteLine ( " Values : {0} , {1} " , v a l 1 , v a l 2 ) ; C o n s o l e . WriteLine ( " Refs : {0} , {1} " , r e f 1 . Value , r e f 2 . Value ) ; } }

scoate n evident a aceast a diferent a. Rezultatul execut iei programului este:


Values : 0 , 123 39 R e f s : 1 2 3 , 123

Atribuirea unei valori variabilei locale val1 nu inuent eaz a valoarea variabilei locale val2 deoarece am andou a sunt de tip valoare (tipul int) si ecare variabil a local a de tip valoarea are propria zon a de memorare a valorii. In contrast, atribuirea ref2.Value=123; afecteaz a obiectul referit at at de variabila ref1 c at si ref2. Liniile
C o n s o l e . WriteLine ( " Values : {0} , {1} " , v a l 1 , v a l 2 ) ; C o n s o l e . WriteLine ( " Refs : {0} , {1} " , r e f 1 . Value , r e f 2 . Value ) ;

sunt utilizate pentru a dovedi cele de mai sus si ilustreaz a o parte din tehnica de formatare a sirurilor de caractere pus la dispozit ie de Console.WriteLine care utilzeaz a numere pentru a indica pozit iile variabilelor cu ale c aror valori este construit sirul a sat. Primul argument este un sir de caractere care poate cont ine referint e c atre pozit ii sub forma {0} si {1}. Fiecare referint a c atre o pozit ie indic a un argument din lista de argumente ce urmeaz a dup a sir. {0} indic a spre al doilea argument, {1} indic a spre al treilea argument si tot a sa. Inainte ca sirul indicat de primul argumenmt s a e trimis spre consol a, ecare indicator de argument este nlocuit cu valoarea formatat a cont inut a de argumentul referit. Dezvoltatorii pot deni un nou tip valoare prin enumerare sau declarat ii de strructuri si pot deni noi tipuri referint a prin declararea de clase, interfet e sau delegat i. Exemplul:
using System ; public enum C o l o r { Red , Blue , Green

1.2. TIPURI

13

} public struct P o i n t { public i n t x , y ; } public i n t e r f a c e I B a s e { void F ( ) ; } public i n t e r f a c e I D e r i v e d : I B a s e { void G( ) ; } public c l a s s A { protected v i r t u a l void H( ) { C o n s o l e . WriteLine ( "A.H" ) ; } } public c l a s s B : A, I D e r i v e d { public void F ( ) { C o n s o l e . WriteLine ( "B.F , implementation of IDerived .F" ) ; } public void G( ) { C o n s o l e . WriteLine ( "B.G , implementation of IDerived .G" ) ; } override protected void H( ) { C o n s o l e . WriteLine ( "B.H , override of A.H" ) ; } } public delegate void EmptyDelegate ( ) ;

arat a cum pot declarate diverse tipuri noi. Mai t arziu vor descrise n detaliu declarat iile de tip.

1.2.1

Tipuri predenite

C# pune la dispozit ie o gam a de tipuri predenite, majoritatea dintre acestea ind familiare dezvoltatorilor de programe n limbajele C si C++. Tipurile referint a predenite sunt object si string. Tipul object este tipul de baz a al tuturor celorlalte tipuri. Tipul string este utilizat pentru reprezentarea sirurilor de caractere UNICODE. Valorile de tip string sunt imutable. Valorile imutable sunt valori ce se nu se pot modica prin schimbare part ial a. De exemplu nu se poate schimba numai al treilea caracter al unui sir. Modicarea celui de al treilea caracter se face prin atribuirea variabilei cu un alt sir n care al treilea caracter are valoarea nou a iar celelalte caractere au valoarea

14

CAPITOLUL 1. PREZENTAREA LIMBAJULUI

veche. Tipurile valoare predenite includ tipul ntreg cu si f ar a semn, tipul cu virgul a mobil a si tipurile bool, char si decimal. Tipurile ntregi cu semn sunt sbyte, short, int si long, tipurile ntreg f ar a semn sunt byte, ushort, uint si ulong, iar tipurile cu virgul a mobil a sunt oat si double. Tipul bool este utilizat pentru reprezentarea valorilor boolene: valori reprezentate prin true sau false. Includerea tipului bool u sureaz a scrierea de cod auto-documentabil si, de asemenea, elimin a erorile de codare datorate caracteristicii totul prea la fel a limbajului C++ n care dezvoltatorii utilzeaz a din gre seal a = n loc de ==. In C#, codul
F( i ) ; i f ( i = 0 ) // Bug : t h e t e s t s h o u l d be ( i == 0) G( ) ;

conduce la o eroare n momentul compil arii deoarece expresia i = 0 este de tipul int si sintaxa instruct iunii if impune o expresie de tip bool. Tipul char este utilizat pentru reprezentarea elementelor codului UNICODE. O variabil a de tip caracter reprezint a un singur cod UNICODE pe 16 bit i. Tipul decimal este adecvat pentru calcule n care rotunjirea f acut a de operat iile n virgul a mobil a nu este de dorit. Printre exemplele uzuale se a a calculele nanciare cum ar deducerea taxelor si conversia ntre diverse monezi. Tipul decimal ofer a calcule cu 28 de cifre semnicative. Tabelul 1.1 cont ine descrierea tipurilor predenite si modul n care sunt scrise valori pentru acestea n program. Tip object string sbyte short int long Descriere / Exemplu tip de baz a pentru toate celelalte tipuri object o = null; tip sir de caractere: o secvent a de coduri UNICODE string s = hello; tip ntreg cu semn reprezentat pe 8 bit i sbyte val = 12; tip ntreg cu semn reprezentat pe 16 bit i short val = 12; tip ntreg cu semn reprezentat pe 32 bit i int val = 12; tip ntreg cu semn reprezentat pe 64 bit i long val1 = 12; long val2 = 34L; tip ntreg f ar a semn reprezentat pe 8 bit i byte val1 = 12; tip ntreg f ar a semn reprezentat pe 16 bit i ushort val1 = 12; tip ntreg f ar a semn reprezentat pe 32 bit i uint val1 = 12; uint val2 = 34U; tip ntreg f ar a semn reprezentat pe 64 bit i ulong val1 = 12; ulong val2 = 34U; ulong val3 = 56L;

byte ushort uint

ulong

1.2. TIPURI Tip oat double Descriere / Exemplu ulong val4 = 78UL; tip virgul a mobil a simpl a precizie oat val = 1.23F; tip virgul a mobil a dubl a precizie double val1 = 1.23; double val2 = 4.56D; tip boolean care poate primi valorile true sau false bool val1 = true; bool val2 = false; tip caracter ale c arui valori sunt reprezentate de un cod UNICODE char val = h; tip zecimal cu 28 de cifre semnicative decimal val = 1.23M; Tabela 1.1: Tipuri predenite

15

bool

char

decimal

Fiecare dintre tipurile predenite reprezint a o scriere prescurtat a pentru un tip declarat n sistem. De exemplu, cuv antul cheie int face referire la structura System.Int32. Utilizarea unui cuv ant cheie este preferat a n locul numelui complet al tipului de sistem. Tipurile predenite cum ar int este tratat a special n anumite situat ii, dar, n general, este interpretat a ca o structur a obi snuit a. Supra nc arcarea operatorilor permite dezvoltatorilor s a deneasc a structuri noi care se comport a ca ni ste tipuri predenite. De exemplu, o structur a Digit poate permite acelea si operat ii matematice ca tipurile ntregi predenite si, mai mult, pot denite conversii ntre Digit si tipurile predenite. Tipurile predenite utilizeaz a ele nsele supra nc arcarea operatorilor. De exemplu, operatorii de comparare == si != au nt eles diferit pentru tipuri predenite diferite: dou a expresii de tip int sunt considerate egale dac a ele reprezint a aceea si valoare ntreag a. dou a expresii de tip object sunt considerate egale dac a ele refer a acela si obiect din memorie sau dac a ambele au valoarea null. dou a expresii de tip string sunt considerate egale dac a sirurile instant a au lungimi egale si au acela si caracter pe aceea si pozit ie sau dac a ambele sunt null. Exemplul
using System ; c l a s s Test { s t a t i c void Main ( ) { s t r i n g s = " Test " ; s t r i n g t = s t r i n g . Copy ( s ) ; C o n s o l e . WriteLine ( s == t ) ;

16

CAPITOLUL 1. PREZENTAREA LIMBAJULUI


C o n s o l e . WriteLine ( ( object ) s == ( object ) t ) ; }

produce ie sirea:
True False

deoarece prima comparat ie se face ntre dou a expresii de tip string, si a dou a comparat ie se face ntre dou a tipuri object. (C and libr aria standard: Standard Library produce un sir n care este reprezentat a o valoare boolean a, ca n cazul instruct iunii Console.WriteLine de mai sus este utilizat sirul True pentru adev arat si sirul False pentru fals.)

1.2.2

Conversii

Tipurile predenite sunt prev azute cu conversii predenite. De exemplu exist a o conversia predenit a ntre tipurile predenite int si long. C# permite dou a tipuri de conversii: conversia implicit a si conversia implicit a. COnversia implicit a este utilizat a atunci c and poate efectuat a f ar a nici un fel de pierdere de informat ie. De exemplu, conversia de la int la long este o conversie implicit a. Aceast a conversie reu se ste ntotdeauna, si niciodat a nu pierde informat ie. Exemplul urm ator:
using System ; c l a s s Test { s t a t i c void Main ( ) { int intValue = 123; long l o n g V a l u e = i n t V a l u e ; C o n s o l e . WriteLine ( " {0} , {1} " , i n t V a l u e , l o n g V a l u e ) ; } }

implic a conversia de la int la long. Pe de alt a parte, conversia explicit a se face cu ajutorul unei expresii de conversie. In exemplul urm ator:
using System ; c l a s s Test { s t a t i c void Main ( ) { long l o n g V a l u e = I n t 6 4 . MaxValue ; int intValue = ( int ) longValue ; C o n s o l e . WriteLine ( "( int ) {0} = {1} " , longValue , intValue ) ; } }

este utilizat a conversia exsplicit a de la long la int. Rezultatul rul arii este:
( i n t ) 9223372036854775807 = 1

1.2. TIPURI

17

deoarece a ap arut o dep a sire. Expresia de conversie permite at at ambele tipuri de conversie: at at explicit a c at si implicit a.

1.2.3

Tipuri matrice

Matricele pot unidimensionale sau multidimensionale. Sunt suportate at at matrice uniforme (rectangulari) c at si matrice neuniforme (jagged). Matricele unidimensionale sunt cele mai des utilizate. In exemplul:
using System ; c l a s s Test { s t a t i c void Main ( ) { i n t [ ] a r r = new i n t [ 5 ] ; f o r ( i n t i = 0 ; i < a r r . Length ; i ++) arr [ i ] = i i ; f o r ( i n t i = 0 ; i < a r r . Length ; i ++) C o n s o l e . WriteLine ( " arr [{0}] = {1} " , i , a r r [ i ] ) ; } }

este creat a o matrice unidimensional a de valori int, sunt init ializate elementele acesteia si apoi sunt tip arite . Programul a seaz a:
arr arr arr arr arr [0] [1] [2] [3] [4] = = = = = 0 1 4 9 16

Tipul int[] utiliyat n exemplul precedent este un tip matrice. Tipurile matrice sunt scrise utiliz and un tip non-matrice urmat de specicarea uneia sau a mai multor dimensiuni. Exemplul:
c l a s s Test { s t a t i c void Main ( ) { i n t [ ] a1 ; ntreg i n t [ , ] a2 ; i n t [ , , ] a3 ; ntreg int [ ] [ ] j 2 ;

// m a t r i c e u n i d i m e n s i o n a l de t i p // m a t r i c e b i d i m e n s i o n a l de t i p ntreg // m a t r i c e cu 3 d i m e n s i u n i de t i p // j a g g e d // m a t r i c e neuniform ( m a t r i c e de m a t r i c e de ntregi ) // m a t r i c e de m a t r i c e de m a t r i c e de

int [ ] [ ] [ ] j 3 ; ntregi } }

cont ine mai multe declarat ii de variabile locale de tip matrice care utilizeaz a elemente de tip int.

18

CAPITOLUL 1. PREZENTAREA LIMBAJULUI

Tipurile matrice sunt tipuri referint a, a sa c a declararea unei variabile de tip matrice aloc a implicit spat iu pentru referirea zonei de date din memorie. Instant ele tipurilor matrice sunt create prin init ializarea implicit a sau cu ajutorul expresiilor de init ializare a matricelor. In exemplul:
c l a s s Test { s t a t i c void Main ( ) { i n t [ ] a1 = new i n t [ ] { 1 , 2 , 3 } ; i n t [ , ] a2 = new i n t [ , ] { { 1 , 2 , 3 } , { 4 , 5 , 6 } } ; i n t [ , , ] a3 = new i n t [ 1 0 , 2 0 , 3 0 ] ; i n t [ ] [ ] j 2 = new i n t [ 3 ] [ ] ; j 2 [ 0 ] = new i n t [ ] { 1 , 2 , 3 } ; j 2 [ 1 ] = new i n t [ ] { 1 , 2 , 3 , 4 , 5 , 6 } ; j 2 [ 2 ] = new i n t [ ] { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 } ; } }

sunt ar atate mai multe tipuri de expresii pentru crearea matricelor. Variabilele a1, a2 si a3 sunt matrice uniforme (rectangulari) si variabila j2 este o matrice neuniform a (jagged). Nu este o surpriz a c a ace sti termeni se bazeaz a pe forma geometric a a matricelor. Matricele rectangulare au ntotdeauna o form a dreptunghiular a. Lungimea prestabilit a a ec arei dimensiuni implic a o form a rectangular a. De exemplu, cele trei dimensiuni ale variabilei a3 sunt 10, 20 si 30. Este u sor s a ne d am seama c a aceasta este format a din 10 20 30 elemente. Pe de alt a parte, variabila j2 indic a o matrice neuniform a sau, altfel zis, o matrice de matrici. Prin declarare j2 indic a o matrice de matrice sau, altfel spus, o matrice unidimensional a de cu elemente de tip int[]. Fiecare element int[] al matricei poate init ializat individual, ceea ce permite obt inerea de matrice neuniforme. In exemplul dat pentru ecare element este specicat ao alt a dimensiune: lungimea lui j2[0] este 3, a lui j2[1] este 6 si a lui j2[2] este 9. In C++ o matrice declarat a int x[3][5][7] este o matrice unform a n timp ce n C# int[][][] indic a o matrice neuniform a. Tipul elementelor si forma matricei - incluz and informat ia de uniform a sau neuniform a si num arul de dimensiuni - fac parte din tipul matricei. Pe de alt a parte, m arimea unei matrice - a sa cum este specicat a ecare dimensiune - nu fac parte din tip. Aceast a separare se face clar prin sintaxa limbajului: m arimea ec arei dimensiuni este specicat a la crearea instant ei si nu la declararea variabilei. De exemplu , declarat ia:
i n t [ , , ] a3 = new i n t [ 1 0 , 2 0 , 3 0 ] ;

cont ine o matrice de tipul int[,,] si expresia de creare a matricei este new int[10, 20, 30]. Pentru variabilele locale si declararea de c ampuri este permis a o scriere prescurtat a, nemaiind necesar a reutilizarea tipului de matrice. De exemplu, n locul instruct iunii:
i n t [ ] a1 = new i n t [ ] { 1 , 2 , 3 } ;

putem utiliza:
i n t [ ] a1 = { 1 , 2 , 3 } ;

1.2. TIPURI

19

f ar a modic ari n comportamentul programului. Contextul n care matricea {1, 2, 3} este utilizat a determin a tipul matricei init ializate. De exemplu
c l a s s Test { s t a t i c void Main ( ) { short [ ] a = { 1 , 2 , 3 } ; int [ ] b = { 1 , 2 , 3 } ; long [ ] c = { 1 , 2 , 3 } ; } }

arat a cum aceea si sintax a de init ializare a unei matrice poate utilizat a pentru diverse tipuri de matrice. Deoarece contextul cere determinarea tipului matricei de init ializare nu este posibil a utilizarea unei matrice de utilizare n contextul unei expresii f ar a a specicat explicit tipul matricei.

1.2.4

Sistemul de tipuri unicat

C# este un sistem de tipuri unicat. Toate tipurile, inclusiv tipurile valoare sunt derivate din tipul object. Este posibil apelul metodelor pentru orice valoare, chiar si pentru tipurile primitive cum ar int. In exemplul
using System ; c l a s s Test { s t a t i c void Main ( ) { C o n s o l e . WriteLine ( 3 . T o S t r i n g ( ) ) ; } }

este apelat a funct ia ToString denit a pentru tipul object pe un intreg exprimat printr-un literal, rezult and ie sirea 3. Exemplul
c l a s s Test { s t a t i c void Main ( ) { int i = 123; object o = i ; // b o x i n g i n t j = ( i n t ) o ; // u n b o x i n g } }

este mult mai interesant. O valoare de tip int poate convertit a la tipul object si napoi la tipul int. Acest exemplu evident iaz a at at procesul de ncapsulare c at si procesul invers. C and o variabil a de un tip trebuie convertit a la un tip referint a un obiect este desemnat entru stocarea valorii si valoarea este copiat a n acesta. Extragerea este procesul invers. C and obiectul desemnat pentru

20

CAPITOLUL 1. PREZENTAREA LIMBAJULUI

p astrarea valorii este convertit la tipul original valoarea este copiat a din container n zona de memorare indicat a. Unicarea tipurilor valoare din sistem aduce beneciile utiliz arii obiectelor f ar a supra nc arc ari inutile. In programele n care tipul int nu trebuie s a se comporte ca un obiect, valoarea de tip int este o simpl a valoare pe 32v de bit i. Pentru programele n care valorile de tip int trebuie s a se comporte ca un obiect este disponibil a aceast a capabilitate a sistemului . Abilitatea de a trata tipurile valoare ca obiecte face s a dispar a o parte din diferent ele n utilizarea tipurilor valoare si tipurilor referint a. De exemplu, o clas a Stack implementeaz a metodele Push si Pop astfel nc at s a returneze valori de tio object.
public c l a s s Stack { public object Pop ( ) { . . .} public void Push ( object o ) { . . .} }

Deoarece C# are un sistem de tipuri unicat clasa Stack poate utiliyat[ cu elemente de orice tip, inclusiv cu tipuri valoare cum este int.

1.3

Variabile si parametrii

Variabilele reprezint a locat ii de stocare. Fiecare variabil a are un tip care determin a ce valori pot stocate n variabil a. Variabilele locale sunt variabile declarate n metode, propriet a ti, sau indexeri. Un indexer este o metod a prin care se descrie modul de accesare a elementelor unei colect ii. Parametrii indexerilor joac a acela si rol ca si un index pentru o structur a vectorial a. O variabil a locala este denit a prin specicarea tipului, a numelui variabilei si, optional, a valoarii init ial a, ca n:
int a ; int b = 1 ;

Intr-o declarat ie de variabile locale este acceptat a numirea simultan a a mai multe variabile. Declarat iile variabilelor a si b pot rescrise astfel:
int a , b = 1 ;

Unei variabile trebuie s a i se atribuie o valoare nainte ca ea s a poat a folosit a. In exemplul:


c l a s s Test { s t a t i c void Main ( ) { int a ; int b = 1 ; i n t c = a + b ; // e r o a r e : l u i a nu i a f o s t a t r i b u i t a o valoare ... } }

1.3. VARIABILE S I PARAMETRII

21

rezult a o eroare la compilare, pentru c a s-a ncercat utilizarea unei variabile nainte de a i se atribui o valoare. Regulile care stabilesc modul de atribuire sunt denite n ??. Un c amp ?? este o variabil a asociat a cu o clas a sau structur a, sau cu o instant a a unei clase sau structuri.Un c amp declarat cu modicatorul static dene ste o variabil a static a, si un c amp declarat f ar a acest modicator dene ste, de exemplu, o variabil a instant a. Un c amp static are asociat cu un tip at ata timp c at o variabil a instant a este asociat a cu o instanta.De exemplu: using Personnel.Data;
c l a s s Employee { private s t a t i c DataSet ds ; public s t r i n g Name ; public decimal S a l a r y ; ... }

arat a o clas a Employee care cont ine o variabil a privat a static a si dou a variabile de instant a publice. Declarat iile de parametrii formali denesc, de asemenea, variabilele. Exist a patru tipuri de parametri: parametrii valoare, parametrii referint a, parametrii de ie sire, si parametrii tip matrice. Un parametru valoare este utilizat pentru transmiterea valorii unui argument ntr-o metod a. Modic ariile parametrului nu au nici un efect asupra argumentului original. Un parametru de valoare se refer a la propriile sale variabile, diferite de argumentul corespondent. Variabila este preg atita prin copierea valorii argumentului. Exemplul :
using System ; c l a s s Test { s t a t i c void F( i n t p ) { C o n s o l e . WriteLine ( "p = {0} " , p ) ; p++; } s t a t i c void Main ( ) { int a = 1 ; C o n s o l e . WriteLine ( " pre : a = {0} " , a ) ; F( a ) ; C o n s o l e . WriteLine ( " post : a = {0} " , a ) ; } }

cont ine o metod a F care are un parametru de valoare numit p. Exemplu produce la ie sire:
pre : a = 1 p = 1 post : a = 1

chiar dac a valoarea parametrului p este modicat a.

22

CAPITOLUL 1. PREZENTAREA LIMBAJULUI

Un parametru referint a este utilizat pentru transmiterea valorii prin. Acesta act ioneaz a ca un alias pentru argumentul utilizat n momentul apel arii. Un parametru referint a nu dene ste o variabil a, ci se refer a la variabila argumentului corespondent. Modicarea unui parametru de referint a are impact asupra argumentului corespondent. Un parametru referint a este declarat cu ajutorul modicatorului ref. Exemplul
using System ; c l a s s Test { s t a t i c void Swap ( r e f in t a , r e f i nt b ) { int t = a ; a = b; b = t; } s t a t i c void Main ( ) { int x = 1 ; int y = 2 ; C o n s o l e . WriteLine ( " pre : x = {0} , y = {1} " , x , y ) ; Swap ( r e f x , r e f y ) ; C o n s o l e . WriteLine ( " post : x = {0} , y = {1} " , x , y ) ; } }

cont ine o metod a Swap care are doi parametri referint a. Apelarea acesteia produce la ie sire:
pre : x = 1 , y = 2 post : x = 2 , y = 1

Cuvantul cheie ref trebuie s a e folosit at at n declarat ia parametru formal c at si n utilizarea acestuia. Utilizarea cuv antului cheie ref la punctul de apel al procedurii indic a unui cititor de cod c a valoarea argumentului ar putea schimbat a ca urmare a efectu arii apelului. Un parametru de ie sire este similar cu un parametru referint a, cu except ia faptului c a valoarea init ial a a argumentului nu are important a. Scopul acestui tip parametru este de a memora valoarea atribuit a lui n timpul execut iei procedurii apelate si a o pune la dispozit ie la revenirea din apel. Un parametru de ie sire este declarat cu ajutorul modicatorului out. In exemplul
using System ; c l a s s Test { s t a t i c void D i v i d e ( i n t a , i n t b , out i n t r e s u l t , out i n t remainder ) { result = a / b; remainder = a % b ; } s t a t i c void Main ( ) { f o r ( i n t i = 1 ; i < 1 0 ; i ++)

1.3. VARIABILE S I PARAMETRII

23

f o r ( i n t j = 1 ; j < 1 0 ; j ++) { i n t ans , r ; D i v i d e ( i , j , out ans , out r ) ; C o n s o l e . WriteLine ( " {0} / {1} = {2} r {3} " , i , j , ans , r ) ; } } }

este descris a o metod a Divide care are doi parametrii de ie sire: unul pentru rezultatul diviz arii si un altul pentru rest. Pentru parametrii valoare, referint a si de ie sire exist a o corespondent a unula-unu ntre argumentele din momentul apelului si parametrii folosit i pentru ai reprezenta. Un parametru matrice permite o relat ie de multe-la-unu: mai multe argumente pot reprezentate de un singur parametru matrice.Cu alte cuvinte parametrii matrice permit ca argument liste de lungime variabil a. Un parametru matrice este declarat cu ajutorul modicatorului params. Poate doar un singur parametru matrice pentru o metoda dat a si intotdeauan trebuie sa e ultimul parametru specicat. Tipul unui parametru matrice este ntotdeauna un unidimensional. Un apel poate transmite e un singur argument e orice num ar de argumente. Argumentele trebuie s a e de tipul de baz a al matricei.In cazul exemplului
using System ; c l a s s Test { s t a t i c void F( params i n t [ ] a r g s ) { C o n s o l e . WriteLine ( "# of arguments : {0} " , a r g s . Length ) ; f o r ( i n t i = 0 ; i < a r g s . Length ; i ++) C o n s o l e . WriteLine ( "\ targs [{0}] = {1} " , i , a r g s [ i ] ) ; } s t a t i c void Main ( ) { F() ; F(1) ; F(1 , 2) ; F(1 , 2 , 3) ; F( new i n t [ ] { 1 , 2 , 3 , 4 } ) ; } }

o metod a F prime ste un num ar variabil de argumente de tip int n mai multe apeluri. La ie sire furnizeaz a:
# of # of args # of args args # of arguments : arguments : [0] = 1 arguments : [0] = 1 [1] = 2 arguments : 0 1 2

24
args args args # of args args args args [0] = 1 [1] = 2 [2] = 3 arguments : 4 [0] = 1 [1] = 2 [2] = 3 [3] = 4

CAPITOLUL 1. PREZENTAREA LIMBAJULUI

introducere folosesc metoda WriMulte din exemplele prezentate In aceastA teLine a clasei Console. Comportamentul argumentului de substitut ie din aceast a metod a prezentat n exemplul:
int a = 1 , b = 2 ; C o n s o l e . WriteLine ( "a = {0} , b = {1} " , a , b ) ;

este construit utiliz and un parametru matrice. Metoda WriteLine ofer a mai multe posibilit a ti de supra nc arcare pentru cazurile obi snuite, n care este transmis un num ar mic de argumente si o metod a care folose ste un parametru matrice:
namespace System { public c l a s s C o n s o l e { public s t a t i c void public s t a t i c void public s t a t i c void object b ) { . . .} ... public s t a t i c void args ) { . . .} } }

WriteLine ( s t r i n g s ) { . . .} WriteLine ( s t r i n g s , object a ) { . . .} WriteLine ( s t r i n g s , object a ,

WriteLine ( s t r i n g s , params object [ ]

1.4

Managementul automat al memoriei

Managementul manual al memoriei impune dezvoltatorilor s a gestioneze alocarea si dealocarea de blocuri de memorie. Managementul manual al memoriei este consumatoar de timp dar este si dicil. In C# gestiunea memoriei este automat a, a sa c a dezvoltatorii sunt eliberat i de aceast a sarcin a dicil a. In marea majoritate a cazurilor, gestiunea automat a a memoriei cre ste calitatea codului si cre ste productivitatea dezvoltatorului, f ar a un impact negativ asupra clarit a tii sau performant ei. In exemplul
using System ; public c l a s s Stack { private Node f i r s t = null ; public bool Empty { get

1.4. MANAGEMENTUL AUTOMAT AL MEMORIEI


{ return ( f i r s t == null ) ; }

25

} public object Pop ( ) { i f ( f i r s t == null ) throw new E x c e p t i o n ( " Can t Pop from an empty Stack ." ) ; else { object temp = f i r s t . Value ; f i r s t = f i r s t . Next ; return temp ; } } public void Push ( object o ) { f i r s t = new Node ( o , f i r s t ) ; } c l a s s Node { public Node Next ; public object Value ; public Node ( object v a l u e ) : t h i s ( v a l u e , null ) { } public Node ( object v a l u e , Node next ) { Next = next ; Value = v a l u e ; } } }

este implementat a o clasa Stack utiliz and o structur a de tip list a n format a din noduri de tip Node. Instant ele de tip Node sunt create n metoda Push si colectate de GarbageCollector atunci c and nu mai sunt necesare. O instanta Node devine eligibil a pentru colectare atunci c and nu mai exist a nici o referint a c atre ea prin intermediul variabilelor declarate n program (nimeni nu o mai refer a). De exemplu, c and un element este eliminat din Stack, instant a Node asociat a devine eligibil a pentru colectare. In exemplul
c l a s s Test { s t a t i c void Main ( ) { Stack s = new Stack ( ) ; f o r ( i n t i = 0 ; i < 1 0 ; i ++) s . Push ( i ) ; s = null ; } }

este prezentat codul care utilizeaz a clasa Stack. Stack este creat a si init ializat a cu 10 elemente si apoi i este atribuit a valoarea null. Odat a ce i se atribuie

26

CAPITOLUL 1. PREZENTAREA LIMBAJULUI

variabilei s valoarea null, Stack si cele 10 instante Node asociate devin cazuri eligibile pentru colectarea. Colectorului de gunoi i este permis sa recupereze toat a memoria neutilizat a imediat, dar nu este necesar sa fac a acest lucru. Colectorul de gunoi din C# poate lucra prin mutarea obiectelor n memorie ntr-un mod transparent pentru cei mai multi dezvoltatori de C#. Pentru dezvoltatorii, care sunt, n general, mult umit i cu managementul automat al memoriei, atunci c and au nevoie de un control mai n sau de un plus de performant a, C# ofer a posibilitatea de a scrie coduri nesigure (unsafe). Un astfel de cod poate s a trateze direct cu tipul referint a si cu referint ele obiectelor, dar este necesar a xarea prin marcarea obiectelor pentru a preveni mutarea temporara a acestora de c atre colectorul de gunoi. Codurile nesigure sunt de fapt o facilitate sigura din perspectiva dezvoltatorilor, c at si a utilizatorilor. Codurile nesigure trebuie s a e marcate clar, n cod cu modicatorul unsafe, a sa c a dezvoltatorii nu pot utiliza accidental facilit a tile unsafe ale limbajului. Compilatorul si motorul de execut ie colaboreaz a pentru a se asigura c a liniile de cod nesigure nu pot s a treac a drept cod sigure. Aceste restrict ii limiteaz a utilizarea de cod nesigur doar n situat ii n care codul nesigur provine dintr-o surs a sigur a. Exemplul
using System ; c l a s s Test { s t a t i c void W r i t e L o c a t i o n s ( byte [ ] a r r ) { unsafe { fixed ( byte pArray = a r r ) { byte pElem = pArray ; f o r ( i n t i = 0 ; i < a r r . Length ; i ++) { byte v a l u e = pElem ; C o n s o l e . WriteLine ( " arr [{0}] at 0x {1: X} is {2} " , i , ( uint ) pElem , v a l u e ) ; pElem++; } } } } s t a t i c void Main ( ) { byte [ ] a r r = new byte [ ] { 1 , 2 , 3 , 4 , 5 } ; WriteLocations ( arr ) ; } }

arat a un bloc nesigur ntr-o metod a numita WriteLocations care xeaz a o matrice si utilizeaz a manipularea referint elor pentru a parcurge elementeel matricei. Indexul, valoarea si locat ia ec arui element din matrice sunt scrise la consol a. Un posibil exemplu de a sare este:

1.5. EXPRESII
arr arr arr arr arr [0] [1] [2] [3] [4] at at at at at 0 x8E0360 0 x8E0361 0 x8E0362 0 x8E0363 0 x8E0364 is is is is is 1 2 3 4 5

27

dar, desigur, cont inutul locat iilor de memorie pot s a se modice de la o execut ie la alta.

1.5

Expresii

C# include operatori unari, operatori binari si un operator ternar. Urm atorul tabel cont ine operatorii n ordinea priorit a tii de execut ie de la cei mai prioritari la cei mai put in priooritari: Sect iunea ?? ?? ?? ?? ?? Categoria Primar Unar Multiplicativ Aditiv Deplasare Relational Testare de tip Egalitatea S I Logic XOR logic SAU logic S I condit ional SAU condit ional Condit ional Atribuire Operatori x.y f(x) a[x] x++ x-typeof checked unchecked + - ! ~ ++x --x (T)x * / % + << >> < > <= >= is as == != & ^ | && || ?: = *= /= %= += -= <<= >>= &= ^= |=

??

?? ?? ??

Tabela 1.2: Operatori C and o expresie cont ine mai mult i operatori precedent a acestora controleaza ordinea n care se face evaluarea. De exemplu, expresia x + y * z este evaluata ca x + (y * z), deoarece * este un operator cu prioritate mai mare dec at a operatorului +. C and un operator apare ntre alt i doi operatori aceea si prioritate asociativitatea operatorilor controleaz a ordinea n care operat iile sunt efectuate: Except and operatorii de atribuire, tot i operatorii binari sunt asociativi la st anga, n sensul c a operat iunile sunt executate de la st anga la dreapta. De exemplu, x + y + z este evaluat ca (x + y) + z Operatorii de atribuire si operatorul condit ionat a (?:) sunt asociativi la dreapta, n sensul c a operat iunile sunt efectuate de la dreapta la st anga. De exemplu, x = y = z este evaluat ca x = (y = z).

28

CAPITOLUL 1. PREZENTAREA LIMBAJULUI

Prioritatea si asociativitatea pot controlate cu ajutorul parantezelor. De exemplu, x + y * z prima dat a multiplic a y cu z si apoi adaug a la rezultat pe x, dar (x + y) * z prima dat a adun ax si y si apoi multiplic a rezultatul cu z.

1.6

Instruct iuni

C# mprumut a cele mai multe din declarat iile sale direct de la C si C++, de si exist a unele complet ari si modic are demne de ment ionat. In exemplele de mai jos sunt evident iate tipurile de declarat ii. Liste si blocuri de declarat ii
s t a t i c void Main ( ) { F() ; G( ) ; { H( ) ; I () ; } }

Declararea etichetelor si utilizarea instruct iunii goto


s t a t i c void Main ( s t r i n g [ ] a r g s ) { i f ( a r g s . Length == 0 ) goto done ; C o n s o l e . WriteLine ( a r g s . Length ) ; done : C o n s o l e . WriteLine ( " Done " ) ; }

Declarat ii locale de constante


s t a t i c void Main ( ) { const f l o a t p i = 3 . 1 4 f ; const i n t r = 1 2 3 ; C o n s o l e . WriteLine ( p i r r ) ; }

Declarat ii locale de variabile


s t a t i c void Main ( ) { int a ; int b = 2 , c = 3 ; a = 1; C o n s o l e . WriteLine ( a + b + c ) ; }

1.6. INSTRUCT IUNI Declarat ii de expresii


s t a t i c in t F( i n t a , i n t b ) { return a + b ; } s t a t i c void Main ( ) { F ( 1 , 2 ) ; // E x p r e s s i o n s t a t e m e n t }

29

Instruct iunea if
s t a t i c void Main ( s t r i n g [ ] a r g s ) { i f ( a r g s . Length == 0 ) C o n s o l e . WriteLine ( " No args " ) ; else C o n s o l e . WriteLine ( " Args " ) ; }

Instruct iunea switch


s t a t i c void Main ( s t r i n g [ ] a r g s ) { switch ( a r g s . Length ) { case 0 : C o n s o l e . WriteLine ( " No args " ) ; break ; case 1 : C o n s o l e . WriteLine ( " One arg " ) ; break ; default : i n t n = a r g s . Length ; C o n s o l e . WriteLine ( " {0} args " , n ) ; break ; } }

Instruct iunea while


s t a t i c void Main ( s t r i n g [ ] a r g s ) { int i = 0 ; while ( i < a r g s . Length ) { C o n s o l e . WriteLine ( a r g s [ i ] ) ; i ++; } }

Instruct iunea do

30

CAPITOLUL 1. PREZENTAREA LIMBAJULUI

s t a t i c void Main ( ) { string s ; do { s = C o n s o l e . ReadLine ( ) ; } while ( s != " Exit " ) ; }

Instruct iunea for


s t a t i c void Main ( s t r i n g [ ] a r g s ) { f o r ( i n t i = 0 ; i < a r g s . Length ; i ++) C o n s o l e . WriteLine ( a r g s [ i ] ) ; }

Instruct iunea foreach


s t a t i c void Main ( s t r i n g [ ] a r g s ) { foreach ( s t r i n g s in a r g s ) C o n s o l e . WriteLine ( s ) ; }

Instruct iunea break


s t a t i c void Main ( s t r i n g [ ] a r g s ) { int i = 0 ; while ( true ) { i f ( i == a r g s . Length ) break ; C o n s o l e . WriteLine ( a r g s [ i ++]) ; } }

Instruct iunea continue


s t a t i c void Main ( s t r i n g [ ] a r g s ) { int i = 0 ; while ( true ) { C o n s o l e . WriteLine ( a r g s [ i ++]) ; i f ( i < a r g s . Length ) continue ; break ; }

Instruct iunea return

1.6. INSTRUCT IUNI

31

s t a t i c in t F( i n t a , i n t b ) { return a + b ; } s t a t i c void Main ( ) { C o n s o l e . WriteLine (F ( 1 , 2 ) ) ; return ; }

instruct iunile throw si return


s t a t i c in t F( i n t a , i n t b ) { i f ( b == 0 ) throw new E x c e p t i o n ( " Divide by zero " ) ; return a / b ; } s t a t i c void Main ( ) { try { C o n s o l e . WriteLine (F ( 5 , 0 ) ) ; } catch ( E x c e p t i o n e ) { C o n s o l e . WriteLine ( " Error " ) ; } }

Instruct iunile checked si unchecked


s t a t i c void Main ( ) { i n t x = I n t 3 2 . MaxValue ; C o n s o l e . WriteLine ( x + 1 ) ; // O v e r f l o w checked { C o n s o l e . WriteLine ( x + 1 ) ; // E x c e p t i o n } unchecked { C o n s o l e . WriteLine ( x + 1 ) ; // O v e r f l o w } }

Instruct iunea lock


s t a t i c void Main ( ) { A a = . . .; lock ( a ) {

32 Denumire public protected internal protected internal private

CAPITOLUL 1. PREZENTAREA LIMBAJULUI Semnicat ie Acces nelimitat Accesul limitat la clasa care o cont ine sau la tipuri derivate din clasa care o cont in Acces limitat la acest program Accesul limitat la acest program sau la tipurile derivate din clasa care o cont in Acces limitat la tipul care o contine Tabela 1.3: Modicatori de acces
a .P = a .P + 1; } }

Instruct iunea using


s t a t i c void Main ( ) { using ( R e s o u r c e r = new R e s o u r c e ( ) ) { r .F() ; } }

1.7

Clase

Declarat iile de clase denesc noi tipuri referint a. O clas a poate mo steni elemente de la o alt a clas a si poate implementa interfet e. Membrii unei clase pot include constante, c ampuri, metode, propriet a ti, evenimente, indexatori, operatori, constructori de instant a, destructori, constructori statici si declarat ii de tipuri imbricate. Fiecare membru are asociat un modicator de accesibilitate (??), care controleaz a regiuni alte textului program care pot accesa membrul. Sunt denite cinci forme de accesare. Acestea sunt prezentate n tabelul 1.3. Exemplicare:
using System ; c l a s s MyClass { public MyClass ( ) { C o n s o l e . WriteLine ( " Instance constructor " ) ; } public MyClass ( i n t v a l u e ) { MyField = v a l u e ; C o n s o l e . WriteLine ( " Instance constructor " ) ; } MyClass ( )

1.7. CLASE
{

33

C o n s o l e . WriteLine ( " Destructor " ) ; } public const i n t MyConst = 1 2 ; public i n t MyField = 3 4 ; public void MyMethod ( ) { C o n s o l e . WriteLine ( " MyClass . MyMethod " ) ; } public i n t MyProperty { get { return MyField ; } set { MyField = v a l u e ; } } public i n t t h i s [ i n t i n d e x ] { get { return 0 ; } set { C o n s o l e . WriteLine ( " this [{0}] = {1} " , index , v a l u e ) ; } } public event EventHandler MyEvent ; public s t a t i c MyClass operator +(MyClass a , MyClass b ) { return new MyClass ( a . MyField + b . MyField ) ; } internal c l a s s MyNestedClass { } }

arat a o clas a care cont ine ecare fel de membru. Exemplul:


c l a s s Test { s t a t i c void Main ( ) { // I n s t a n c e c o n s t r u c t o r u s a g e MyClass a = new MyClass ( ) ; MyClass b = new MyClass ( 1 2 3 ) ; // Constant u s a g e C o n s o l e . WriteLine ( " MyConst = {0} " , MyClass . MyConst ) ; // F i e l d u s a g e a . MyField++; C o n s o l e . WriteLine ( "a. MyField = {0} " , a . MyField ) ;

34

CAPITOLUL 1. PREZENTAREA LIMBAJULUI


// Method u s a g e a . MyMethod ( ) ; // P r o p e r t y u s a g e a . MyProperty++; C o n s o l e . WriteLine ( "a. MyProperty = {0} " , a . MyProperty ) ; // I n d e x e r u s a g e a[3] = a[1] = a [2]; C o n s o l e . WriteLine ( "a [3] = {0} " , a [ 3 ] ) ; // Event u s a g e a . MyEvent += new EventHandler ( MyHandler ) ; // O v e r l o a d e d o p e r a t o r u s a g e MyClass c = a + b ; } s t a t i c void MyHandler ( object s e n d e r , EventArgs e ) { C o n s o l e . WriteLine ( " Test . MyHandler " ) ; } internal c l a s s MyNestedClass { }

arat a utiliz ari ale acestor membri.

1.7.1

Constante

O constant a este membrul unei clase care reprezint a o valoare constant a: o valoare care poate calculata la momentul compil arii. Constantelor li se permite s a depind a de alte constante n cadrul aceluia si program, at at timp c at nu exist a dependent ele circulare. Normele care reglementeaz a expresiile constante sunt denite n (??). Exemplul
class Constants { public const i n t A = 1 ; public const i n t B = A + 1 ; }

arat a o clasa cu numele Constants care are dou a constante publice. Chiar dac a sunt considerate sunt considerate membrii statici, o declarat ie de constante nu necesit a si nu permite modicatorul static. Constantele pot accesate prin intremediul clasei, ca n exemplul:
using System ; c l a s s Test { s t a t i c void Main ( ) { C o n s o l e . WriteLine ( " {0} , {1} " , C o n s t a n t s . A, C o n s t a n t s . B ); } }

care tip are ste valorile Constants.A si respectiv Constants.B.

1.7. CLASE

35

1.7.2

C ampuri

Un c amp este un membru care reprezint a o variabil a asociat a cu un obiect sau clas a. De exemplu
class Color { internal ushort r e d P a r t ; internal ushort b l u e P a r t ; internal ushort g r e e n P a r t ; public C o l o r ( ushort red , ushort blue , ushort g r e e n ) { redPart = red ; bluePart = blue ; greenPart = green ; } public s t a t i c C o l o r Red = new C o l o r ( 0xFF , 0 , 0 ) ; public s t a t i c C o l o r Blue = new C o l o r ( 0 , 0xFF , 0 ) ; public s t a t i c C o l o r Green = new C o l o r ( 0 , 0 , 0xFF) ; public s t a t i c C o l o r White = new C o l o r ( 0xFF , 0xFF , 0xFF) ; }

arat a o clas a Culoare, care cont ine c ampurile instant a interne numite redPar, bluePart si greenPart, si domeniile statice numite red, blue, green si white. Nu este recomandat a utilizarea domeniilor statice n acest mod. C ampurile sunt init ializate la un moment dat, nainte ca ele sa e folosite, dar dup a aceea nimic nu oprea ste un client de la modicarea lor. O astfel de modicare, imprevizibil a, poate cauza erori n alte programe care utilizeaz a Culoare si presupune c a valorile nu au fost schimbate. C ampurile readonly pot utilizate pentru a mpiedica astfel de probleme. Atribuirea valorii unui c amp readonly poate apare doar ca parte a declarat iei, sau ntr-un constructor de instant a sau static, n aceea si clas a. Un c amp static readonly poate atribuit ntr-un constructor static. Un c amp nestatic readonly pot atribuit ntr-un constructor de instant a . Astfel, clasa de culori poate mbun at a tit a prin ad augarea modicatorul static readonly la c ampurile statice:
class Color { internal ushort r e d P a r t ; internal ushort b l u e P a r t ; internal ushort g r e e n P a r t ; public C o l o r ( ushort red , ushort blue , ushort g r e e n ) { redPart = red ; bluePart = blue ; greenPart = green ; } public s t a t i c readonly C o l o r Red = new C o l o r ( 0xFF , 0 , 0 ) ; public s t a t i c readonly C o l o r Blue = new C o l o r ( 0 , 0xFF , 0 ) ; public s t a t i c readonly C o l o r Green = new C o l o r ( 0 , 0 , 0xFF) ; public s t a t i c readonly C o l o r White = new C o l o r ( 0xFF , 0xFF , 0xFF) ; }

36

CAPITOLUL 1. PREZENTAREA LIMBAJULUI

1.7.3

Metode

O metod a este un membru care implementeaza o act iune sau un calcul ce poate executat a de un obiect sau o clas a. Metodele sunt statice sau nestatice si sunt caracterizate printr-o list a de parametrii formali (list a posibil goal a), o valoare returnat a (cu except ia cazului n care tipul metodei este void). Metodele statice sunt accesate prin intermediul clasei. Metodele nestatice, numite si metode de instant a, sunt accesate prin instant e ale clasei. De exemplu
using System ; public c l a s s Stack { public s t a t i c Stack Clone ( Stack s ) { . . .} public s t a t i c Stack F l i p ( Stack s ) { . . .} public object Pop ( ) { . . .} public void Push ( object o ) { . . .} public override s t r i n g T o S t r i n g ( ) { . . .} ... } c l a s s Test { s t a t i c void Main ( ) { Stack s = new Stack ( ) ; f o r ( i n t i = 1 ; i < 1 0 ; i ++) s . Push ( i ) ; Stack f l i p p e d = Stack . F l i p ( s ) ; Stack c l o n e d = Stack . Clone ( s ) ; C o n s o l e . WriteLine ( " Original stack : " + s . T o S t r i n g ( ) ) ; C o n s o l e . WriteLine ( " Flipped stack : " + f l i p p e d . T o S t r i n g () ) ; C o n s o l e . WriteLine ( " Cloned stack : " + c l o n e d . T o S t r i n g ( ) ); } }

arat a o clasa Stack care are mai multe metode statice (Clone si Flip) si de mai multe metode de instanta (Pop, Push, si ToString). Metodele pot supra nc arcate, ceea ce nseamn a c a mai multe metode pot avea acela si nume, at at timp c at ele au semn aturi unice. Semn atura unei metode const a din numele metodei, modicatorii si tipurile parametrilor formali. Semn atura unei metode nu include tipul ntors. De exemplu
using System ; c l a s s Test { s t a t i c void F ( ) { C o n s o l e . WriteLine ( "F () " ) ; } s t a t i c void F( object o ) { C o n s o l e . WriteLine ( "F( object )" ) ; }

1.7. CLASE
s t a t i c void F( i n t v a l u e ) { C o n s o l e . WriteLine ( "F( int )" ) ; } s t a t i c void F( r e f in t v a l u e ) { C o n s o l e . WriteLine ( "F( ref int )" ) ; } s t a t i c void F( i n t a , i n t b ) { C o n s o l e . WriteLine ( "F( int , int )" ) ; } s t a t i c void F( i n t [ ] v a l u e s ) { C o n s o l e . WriteLine ( "F( int []) " ) ; } s t a t i c void Main ( ) { F() ; F(1) ; int i = 1 0 ; F( r e f i ) ; F ( ( object ) 1 ) ; F(1 , 2) ; F( new i n t [ ] { 1 , 2 , 3 } ) ; } }

37

arat a o clas a care con sine mai multe metode numite F. La ie sire programul va a sa:
F() F( i n t ) F( r e f i nt ) F( object ) F( int , i n t ) F( i n t [ ] )

1.7.4

Propriet a ti

O proprietate este un membru care ofer a acces la o caracteristic a a unui obiect sau a unei clase. Exemplele de propriet a ti includ lungimea unui sir de caractere, m arimea unui font, legenda unei fereastre, numele unui client si a sa mai departe. Propriet a tile sunt o extensie natural a a c ampurilor. Ambele sunt numite membrii cu tipuri asociate. Sintaxa pentru accesarea c ampurilor si propriet a tilor este aceea si. Cu toate acestea, spre deosebire de c ampuri, propriet a tile nu denot a locat ii de memorie. In schimb, propriet a tile au accesori care precizeaz a instruct iunile ce trebuie executate atunci c and valorile lor sunt citite sau scrise. Propriet a tile sunt denite cu ajutorul declarat iilor de propriet a ti. Prima parte a unei propriet a ti arat a similar cu o declarat ie de c amp. A doua parte include accesorii get si/sau set. In exemplul de mai jos, clasa Buton dene ste o proprietate Caption.

38

CAPITOLUL 1. PREZENTAREA LIMBAJULUI

public c l a s s Button { private s t r i n g c a p t i o n ; public s t r i n g Caption { get { return c a p t i o n ; } set { caption = value ; Repaint ( ) ; } } ... }

Propriet a ti, care poate at at citite, c at si scrise, cum ar Caption, includ ambii accesori: get si set. Accessorul get este apelat de proprietate n cazul n care valoarea acesteia este citit a; accessorul set este apelat de proprietate atunci c and valoarea acesteia este modicat a. Intr-un accessor set, noua valoare pentru proprietate este pus a la dispozit ie printr-un parametru implicit numit value. Declararea propriet a tilor este relativ simpl a. Valoarea real a a propriet a tilor este evident iat a c and sunt utilizate. De exemplu, proprietatea Caption poate citit a si scris a n acela si fel n care pot citite si scrise c ampurile:
Button b = new Button ( ) b . Caption = " ABC " ; s t r i n g s = b . Caption ; b . Caption += " DEF " ; ; // s e t ; c a u s e s r e p a i n t // g e t // g e t & s e t ; c a u s e s r e p a i n t

1.7.5

Evenimente

Un eveniment este un membru care permite unui obiect sau clas a sa furnizeze notic ari. O clas a dene ste un eveniment oferind o declarat ie eveniment (care seam an a cu o declarat ie de c amp suplimentat a cu un cuvint cheie event) si, opt ional, un set de accesori pentru eveniment. Tipul acestei declarat ii trebuie s a e un tip delegat. Instant a unui tip delegat ncapsuleaz a una sau mai multe entit a ti ce pot apelate ca funct ii (callable). Pentru metodele instant a, o entitate apellabil a const a dintr-o instant a si o metod a peste instant a. Pentru metodele statice, o entitate apelabil a const a doar dintr-o metod a. Dat a ind o instant a delegat si un set de argumente adecvate, un apel invoc a toate metodele delegat ale instant ei prev azute cu acel set de argumente. In exemplu
public delegate void EventHandler ( object s e n d e r , System . EventArgs e ) ; public c l a s s Button { public event EventHandler C l i c k ;

1.7. CLASE
public void R e s e t ( ) { C l i c k = null ; } }

39

clasa Button dene ste un eveniment Click de tip EventHandler. In interiorul clasei Button membrul Click este exact ca un c amp de tip privat EventHandler. Cu toate acestea, n afara clasei Button, membru Click poate utilizat doar ca valoare st anga a operatorilor += si -=. Operatorul += adaug a o nou a metod a la eveniment, si operatorul -= elimin a o metod a din eveniment. De exemplu:
using System ; public c l a s s Form1 { public Form1 ( ) { // Add B u t t o n 1 C l i c k as an // e v e n t h a n d l e r f o r Button1 s C l i c k e v e n t Button1 . C l i c k += new EventHandler ( B u t t o n 1 C l i c k ) ; } Button Button1 = new Button ( ) ; void B u t t o n 1 C l i c k ( object s e n d e r , EventArgs e ) { C o n s o l e . WriteLine ( " Button1 was clicked !" ) ; } public void D i s c o n n e c t ( ) { Button1 . C l i c k = new EventHandler ( B u t t o n 1 C l i c k ) ; } }

arat a o clas a Form1 ce adaug a Button1 Click ca metod a pentru evenimentul Click asociat instant ei Button1. In metoda Disconect este eliminat a metoda asociat a evenimentului. Pentru o simpl a declarat ie de eveniment, cum ar
public event EventHandler C l i c k ;

compilatorul prevede automat implementarea operatorilor += si -=. Un implementator care vrea mai mult control poate obt ine acest lucru n mod explicit prin implementarea accesorilor de adugare si stergere a metodelor asociate evenimentului. Spre exemplu, clasa Button ar putea rescrisa dup a cum urmeaz a:
public c l a s s Button { private EventHandler h a n d l e r ; public event EventHandler C l i c k { add { h a n d l e r += v a l u e ; } remove { h a n d l e r = v a l u e ; } } }

40

CAPITOLUL 1. PREZENTAREA LIMBAJULUI

Aceast a modicare nu are nici un efect asupra codului clientului, dar permite clasei Button o implementare mult mai exibil a. Spre exemplu, evenimentul manipulant n cazul Click nu trebuie s a e reprezentat de un c amp.

1.7.6

Operatori

Un operator este un membru care dene ste sensul unei expresii. Un operator care pot aplicat instant ei unei clasa. Exist a trei tipuri de operatori: operatori unari, operatori binari, si operatori de conversie. Urm atorul exemplu dene ste un tip Digit care reprezint a cifre zecimale cu valori ntregi ntre 0 si 9:
using System ; public struct D i g i t { byte v a l u e ; public D i g i t ( byte v a l u e ) { i f ( v a l u e < 0 | | v a l u e > 9 ) throw new ArgumentException ( ) ; this . value = value ; } public D i g i t ( i n t v a l u e ) : t h i s ( ( byte ) v a l u e ) {} public s t a t i c i m p l i c i t operator byte ( D i g i t d ) { return d . v a l u e ; } public s t a t i c e x p l i c i t operator D i g i t ( byte b ) { return new D i g i t ( b ) ; } public s t a t i c D i g i t operator +( D i g i t a , D i g i t b ) { return new D i g i t ( a . v a l u e + b . v a l u e ) ; } public s t a t i c D i g i t operator ( D i g i t a , D i g i t b ) { return new D i g i t ( a . v a l u e b . v a l u e ) ; } public s t a t i c bool operator==(D i g i t a , D i g i t b ) { return a . v a l u e == b . v a l u e ; } public s t a t i c bool operator !=( D i g i t a , D i g i t b ) { return a . v a l u e != b . v a l u e ; } public override bool Equals ( object v a l u e ) { i f ( v a l u e == null ) return f a l s e ; i f ( GetType ( ) == v a l u e . GetType ( ) ) return t h i s == ( Digit ) value ; return f a l s e ; }

1.7. CLASE
public override i n t GetHashCode ( ) { return v a l u e . GetHashCode ( ) ; } public override s t r i n g T o S t r i n g ( ) { return v a l u e . T o S t r i n g ( ) ; } } c l a s s Test { s t a t i c void Main ( ) { Digit a = ( Digit ) 5; Digit b = ( Digit ) 3; Digit plus = a + b ; D i g i t minus = a b ; bool e q u a l s = ( a == b ) ; C o n s o l e . WriteLine ( " {0} + {1} = {2} " , a , b , p l u s ) ; C o n s o l e . WriteLine ( " {0} - {1} = {2} " , a , b , minus ) ; C o n s o l e . WriteLine ( " {0} == {1} = {2} " , a , b , e q u a l s ) ; } }

41

Tipul Digit dene ste urm atorii operatori: O conversie implicit a a operatorului de Digit la byte. O conversie explicita a operatorului de byte la Digit. Un operatorde ad augare care adaug a dou a valori Digit si returneaz a o valoare Digit. Un operator de scadere care scade o valoare Digit din alta, si returneaz a o valoare Digit. Operatorii de egalitate (==) si inegalitatea (!=) , care compar a dou a valori Digit.

1.7.7

Indexatori

Un indexator este un membru care permite unui obiect s a e indexat n acela si mod ca o matrice. Propriet a tile sunt accesate n mod identic cu c ampurile si indexatorii permit accesarea obiectelor n mod identic cu accesarea matricelor. Ca exemplu, luat i n considerare clasa Stack prezentat a mai devreme. Proiectantul acestei clase ar vrea s a expunet i o accesare de tip matrice astfel nc at s a e posibil a inspectarea sau modicarea elementelor din stiv a f ar a efectuarea inutil a a operat iunilor Push si Pop. Clasa Stack este implementat a ca o list a nl nt uit a, dar este posibil a accesarea cont inutului acesteia ca si cont inutul unei matrice. Declarat iile indexer sunt similare cu declarat iile de proprietate, principalele diferent e const and n faptul c a indexatorii nu au nume ( numele folosit n declarat ie este this, deoarece obiectul curent este indexat) si permit parametrii. Parametrii de indexare sunt furnizat i ntre paranteze p atrate. De exemplu

42

CAPITOLUL 1. PREZENTAREA LIMBAJULUI

using System ; public c l a s s Stack { private Node GetNode ( i n t i n d e x ) { Node temp = f i r s t ; while ( i n d e x > 0 ) { temp = temp . Next ; index ; } return temp ; } public object t h i s [ i n t i n d e x ] { get { i f ( ! ValidIndex ( index ) ) throw new E x c e p t i o n ( " Index out of range ." ) ; else return GetNode ( i n d e x ) . Value ; } set { i f ( ! ValidIndex ( index ) ) throw new E x c e p t i o n ( " Index out of range ." ) ; else GetNode ( i n d e x ) . Value = v a l u e ; } } ... } c l a s s Test { s t a t i c void Main ( ) { Stack s = new Stack ( ) ; s . Push ( 1 ) ; s . Push ( 2 ) ; s . Push ( 3 ) ; s [ 0 ] = 3 3 ; // Changes t h e t o p item from 3 t o 33 s [ 1 ] = 2 2 ; // Changes t h e m i d d l e item from 2 t o 22 s [ 2 ] = 1 1 ; // Changes t h e bottom item from 1 t o 11 } }

exemplic a un indexator pentru clasa Stack.

1.7.8

Constructori de instant a

Un constructor de instant a este un membru care implementeaz a act iunile necesare pentru init ializarea ueni instant e de clas a. De exemplu:
using System ;

1.7. CLASE

43

class Point { public double x , y ; public P o i n t ( ) { this . x = 0 ; this . y = 0 ; } public P o i n t ( double x , double y ) { this . x = x ; this . y = y ; } public s t a t i c double D i s t a n c e ( P o i n t a , P o i n t b ) { double x d i f f = a . x b . x ; double y d i f f = a . y b . y ; return Math . S q r t ( x d i f f x d i f f + y d i f f y d i f f ) ; } public override s t r i n g T o S t r i n g ( ) { return s t r i n g . Format ( " ({0} , {1}) " , x , y ) ; } } c l a s s Test { s t a t i c void Main ( ) { P o i n t a = new P o i n t ( ) ; P o i n t b = new P o i n t ( 3 , 4 ) ; double d = P o i n t . D i s t a n c e ( a , b ) ; C o n s o l e . WriteLine ( " Distance from {0} to {1} is {2} " , a , b , d) ; } }

indic a o clas a Point care ofer a doi constructori publici de instant a, unul f ar a argumente si unul cu dou a argumente de tip double. Dac a nu este furnizat nici un constructor de instant a pentru o clas a este furnizat n mod automat unul f ar a argumente.

1.7.9

Destructori

Un destructor este un membru care implementeaza act iunile necesare pentru a distruge o instant a a unei clase. Destructorii nu au parametrii, nu au modicator de acces si nu pot apelat i n mod explicit. Destructorul este apelat n mod automat n timpul colect arii memoriei ce nu mai este folosit a (grabage collector ). Exemplul
using System ; class Point { public double x , y ; public P o i n t ( double x , double y )

44
{ this . x = x ; this . y = y ;

CAPITOLUL 1. PREZENTAREA LIMBAJULUI

} Point ( ) { C o n s o l e . WriteLine ( " Destructed {0} " , t h i s ) ; } public override s t r i n g T o S t r i n g ( ) { return s t r i n g . Format ( " ({0} , {1}) " , x , y ) ; } }

cont ine o clasa Point cu un destructor declarat explicit.

1.7.10

Constructori statici

Un constructor static este un membru care implementeaz a act iunile necesare pentru a init ializa o clas a. Constructorii statici nu pot avea parametri si nu pot avea modicatori de acces. Ace stia nu pot apelat i n mod explicit. Constructorul static pentru o clas a este apelat n mod automat.De exemplu:
using P e r s o n n e l . Data ; c l a s s Employee { private s t a t i c DataSet ds ; s t a t i c Employee ( ) { ds = new DataSet ( . . .) ; } public s t r i n g Name ; public decimal S a l a r y ; ... }

arat a o clas a Employee cu un constructor static, care init ializeaz a c ampul static.

1.7.11

Mo stenirea

Clasele suport a o singur a mo stenire si tipul object este clas a de baz a pentru toate clasele. Clasele de prezentate n exemplele precedente sunt derivate din clasa de baz a object. De exemplu
using System ; class A { public void F ( ) { C o n s o l e . WriteLine ( "A.F" ) ; } }

arat a o clas a A care provine, implicit, de la object. De exemplu

1.7. CLASE

45

class B: A { public void G( ) { C o n s o l e . WriteLine ( "B.G" ) ; } } c l a s s Test { s t a t i c void Main ( ) { B b = new B( ) ; b .F() ; // I n h e r i t e d from A b .G( ) ; // I n t r o d u c e d i n B A a = b; // Treat a B as an A a .F() ; } }

arat a o clas a B, care deriv a din clasa A. B mo stene ste o metod a F a lui A si introduce o metoda proprie G. Metode, propriet a ti si indexatoarele pot virtuale, ceea ce nseamn a c a implementarea lor poate suprascris a n clasele derivate. De exemplu
using System ; class A { public v i r t u a l void F ( ) { C o n s o l e . WriteLine ( "A.F" ) ; } } class B: A { public override void F ( ) { base . F ( ) ; C o n s o l e . WriteLine ( "B.F" ) ; } } c l a s s Test { s t a t i c void Main ( ) { B b = new B( ) ; b .F() ; A a = b; a .F() ; } }

arat a o clasa A cu o metod a virtual a F, si o clas a B, care ignor a F. Metoda suprascrisa n B cont ine un apel, base.F(), care solicit a metoda suprascris a n A. O clas a poate indica faptul c a este incomplet a, si este destinat a numai a o clas a de baz a pentru alte clase, de c atre modicatorul abstract. O astfel de clas a este numit a clas a abstract a. Intr-o clas a abstract a pot specicat i membrii abstracti - membri care trebuie implementat i ntr-o clas a derivat a neabstract a. De exemplu:

46

CAPITOLUL 1. PREZENTAREA LIMBAJULUI

using System ; abstract c l a s s A { public abstract void F ( ) ; } class B: A { public override void F ( ) { C o n s o l e . WriteLine ( "B.F" ) ; } } c l a s s Test { s t a t i c void Main ( ) { B b = new B( ) ; b .F() ; A a = b; a .F() ; } }

introduce o metod a F abstract a, n clasa abstracta A. Clasa non-abstract B, ofer a implementarea aceastei metode.

1.8

Structuri

Lista de asem an ari ntre clase si structuri este mare. Structurile pot implementa interfet e si pot avea acela si tip de membri ca si clasele. Structurile difer a de clase din mai multe puncte de vedere: structurile sunt mai degrab a tip valoare dec at tip referint a si mo stenirea nu este acceptat a pentru structuri. Valorile structurilor sunt stocate pe stiva sau in-line. Programatorii pot spori uneori performant a prin utilizarea judicioas a a structurilor. De exemplu, utilizarea unei structuri este de preferat unei clase Point. Utilizarea structurilor reduce num arul de aloc ari de memorie efectuate n timpul rul arii. Programul de mai jos creaz a si init ializeaz a o secvent a de 100 de puncte. Cu Point implementat ca o clasa sunt instant iate 101 de obiecte separat unul pentru matrice si unul pentru ecare din cele 100 de elemente.
class Point { public i n t x , y ; public P o i n t ( i n t x , i n t y ) { this . x = x ; this . y = y ; } } c l a s s Test { s t a t i c void Main ( ) { P o i n t [ ] p o i n t s = new P o i n t [ 1 0 0 ] ; f o r ( i n t i = 0 ; i < 1 0 0 ; i ++)

1.9. INTERFET E
p o i n t s [ i ] = new P o i n t ( i , i i ) ; } }

47

Daca Point este implementat a ca structur a, ca n


struct P o i n t { public i n t x , y ; public P o i n t ( i n t x , i n t y ) { this . x = x ; this . y = y ; } }

numai un singur obiect este instant iat - cel pentru matrice. Instant e Pointului sunt alocate in-line n cadrul matricei. Aceast a abordare poate gre sit a. Utilizarea structurilor n loc de clase poate face, de asemenea, ca o aplicatie s a ruleze mai lent sau de a folosi mai multa memorie. Atribuind o valoare structurii determin a crearea unei copi a structurii.

1.9

Interfet e

O interfat a dene ste un tipar. O clasa sau o structur a care pune n aplicare o interfat a trebuie s a respecte tiparul. Interfet ele pot s a cont in a metode, propriet a ti, evenimente si indec si n calitate de membri. De exemplu:
i n t e r f a c e IExample { string this [ int index ] { get ; s e t ; } event EventHandler E ; void F( i n t v a l u e ) ; string P { get ; s e t ; } } public delegate void EventHandler ( object s e n d e r , EventArgs e ) ;

arat a o interfat a care cont ine un index, un eveniment E, o metod a F, si o proprietate P. Interfet ele pot folosi mai multe mo steniri. In exemplul de mai jos interfat a IComboBox mo stene ste at at de la ITextBox si IListBox:
interface { void } interface { void } interface { void IControl Paint ( ) ; ITextBox : I C o n t r o l SetText ( s t r i n g t e x t ) ; IListBox : IControl SetItems ( string [ ] items ) ;

48

CAPITOLUL 1. PREZENTAREA LIMBAJULUI

} i n t e r f a c e IComboBox : ITextBox , I L i s t B o x {}

1.10

Delegat i

Delegatii sunt n alte limbaje adresati cu ajutorul functiilor pointeri. Spre deosebire de functiile pointeri, delegatii sunt orientate pe obiecte si mai siguri (type-safe). Declararea unui delegat deneste o clasa care este derivata din clasa System.Delegate. O instanta delegat poate cuprinde una sau mai multe metode, ecare ind referita ca si o entitate apelabila. Pentru metodele de instanta, o entitate apelabila consta intr-o instanta si o metoda a acelei instante. Pentru metodele statice, o entitate apelabila consista doar intr-o metoda. Oferint o instanta delegat si un set adecvat de argumente, una poate invoca toate instantele metodelor delegat cu acel set de argumente. O proprietate interesanta si utila a instantelor delegat este ca nu stie sau nu-I pasa de clasele metodelor pe care le cuprinde; tot ce conteaza este ca acele metode sa e compatibile cu tipul delegat. Aceasta face tipul delegat sa se potriveasca perfect pentru invocarile anonime. Aceasta este o capacitate puternica. Sunt 3 pasi in denirea si utilizarea delegatilor: declaratia, instantierea si invocarea. Delegatii sunt declarati utilizand sintaxa de declarare delegate. Exemplu:
delegate void S i m p l e D e l e g a t e ( ) ;

declara un delegat numit SimpleDelegate care nu are argumente si nu returneaza rezultat. Exemplu:
c l a s s Test { s t a t i c void F ( ) { System . C o n s o l e . WriteLine ( " Test .F" ) ; } s t a t i c void Main ( ) { S i m p l e D e l e g a t e d = new S i m p l e D e l e g a t e (F) ; d() ; } }

creaza o instanta SimpleDelegate si apoi o apeleaza. Asta este tot ce trebuie sa faceti pentru a instantia un delegat pentru o metoda, si apoi apelata metoda prin delegate, ca sic and ar mai simplu sa apelati metoda in mod direct. Delegatii isi arata utilizarea cand este utilizata anonimitatea lor. Exemplu:
void M u l t i C a l l ( S i m p l e D e l e g a t e d , i n t count ) { f o r ( i n t i = 0 ; i < count ; i ++) {

1.11. ENUMERARI
d() ; } }

49

arata o metoda MultiCall si repetat apeleaza SimpleDelegate. Metoda MultiCall nu sties au nu-I pasa de tipul metodei pentru SimpleDelegate, ce accesibilitate are metoda, sau daca e sau nu metoda statica. Tot ce conteaza este ca metoda apelata sa e compatibila cu SimpleDelegate.

1.11

Enumer ari

Declararea unui tip enum deneste un nume de tip pentru un grup legat de simboluri constante. Enumerarile sunt utilizare pentru alegeri multiple, in care o decizie de rulare este facuta dintr-un numar x de alegeri care sunt stiute la compilare. Exemplu:
enum C o l o r { Red , Blue , Green } c l a s s Shape { public void F i l l ( C o l o r c o l o r ) { switch ( c o l o r ) { case C o l o r . Red : break ; case C o l o r . Blue : break ; case C o l o r . Green : break ; default : break ; } } }

arata o enumerare Color si o metoda care foloseste aceasta enumerare. Semnatura metodei Fill arata ca forma poate umpluta cu una din culorile date. Utilizarea enumerarilor este superioara utilizarii constantelor intregi, pentru ca utilizarea enumerarilor face codul mai usor de citit. De exemplu, utilizarea enumerarii Color in locul tipurilor int ca si parametru, permit editoarelor cu sistem gen intellisense sa sugereze valori Color.

1.12

Spat ii de nume si ansamble

Programele prezentate pana acum s-au bazat pe propriile dependinte cu exceptia catorva clase oferite de sistem, cum ar System.Console. Este mult mai comun pentru aplicatiile reale sa e construite din bucati diferite, ecare compilata separate. De exemplu, o aplicatie mare poate depinde de cateva componente

50

CAPITOLUL 1. PREZENTAREA LIMBAJULUI

diferite, incluzand cele dezvoltate intern si cele cumparate independent de la producatorii de software. Spatiile de nume si asamblarea permit acest sistem bazat pe componente. Spatiile de nume ofera o organizare logica a sistemului. Spatiile de nume sunt utilizate atat cu o organizare de sistem internal, dar si external - o modalitate de a prezenta elementele programului care sunt expuse altor programe. Asamblarea este utilizata pentru impachetare si instalare. O asamblare poate contine tipuri, codul executabil folosit la implementarea acestor tipuri, si referintele catre alte asamblari. Clasa librarie va contine o singura clasa numita HelloMessage. Exemplu:
// H e l l o L i b r a r y . c s namespace CSharp . I n t r o d u c t i o n { p u b 1 i c c 1 a s s He11oMessage { p u b 1 i c s t r i n g Message { get { return " he11o , wor1d " ; } } } }

arata clasa HelloMessage intr-un spatiu de nume denumit CSharp.Introduction. Clasa HelloMessage ofera o proprietate read-only numita Message. Spatiile de nume pot folosi mai multe tipuri de declaratii:
namespace CSharp . l n t r o d u c t i o n { . . . }

Alta declaratie:
namespace CSharp { namespace I n t r o d u c t i o n {...} }

Urmatorul pas este scrierea unei aplicatiid e consola care foloseste clasa HelloMessage. Denumirea completa a clasei este - Csharp.Introduction.HelloMessage - si poate utilizata, dar numele este destul de mare si ciudat. O cale mai usoara este sa utilizarea directive using, care poate face posibilia folosirea tuturor tipurilor dintr-un spatiu de nume. Exemplu:
// HelloApp . c s using c s h a r p . l n t r o d u c t i o n ; c l a s s HelloApp { s t a t i c void Main ( ) { H e l l o M e s s a g e m = new H e l l o M e s s a g e ( ) ;

1.13. VERSIONARE
System . C o n s o l e . WriteLine (m. Message ) ; } }

51

arata folosirea directivei using pentru a face referire la CSharp.Introduction. C# permite denirea si folosirea poreclelor (alias). O directive using alias deneste un tip alias. Un astfel de alias poate util in situatii in care coliziunea dintre nume apare intre doua librarii de clase. Exemplu:
using MessageSource = CSharp . I n t r o d u c t i o n . H e l l o M e s s a g e ;

arata utilizarea directivei alias care deneste MessageSource ca si alias pentru clasa HelloMessage. Codul de mai sus poate compilat intr-o clasa librarie continand clasa HelloMessage si o aplicatie continand clasa HelloApp. Detaliile acestei compilari poate diferi in functie de compilatorul sau uneltele folosite. Un compilator in linie de comanda poate permite compilarea unei clase librarii si o aplicatie care foloseste acea librarie cu urmatoarele invocari in linia de comanda:
csc / target : l i b r a r y HelloLibrary . cs c s c / r e f e r e n c e : H e l l o L i b r a r y . d l l HelloApp . c s

produce o librarie de clasa numita HelloLibrary.dll si o aplicatie numita HelloApp.exe.

1.13

Versionare

Versionarea este procesul de evoluare a componentei intr-un anumit timp intrun mod compatibil. O noua versiune a componentei este compatibila sursa cu o versiune anterioara, iar in cazul in care codul depinde de versiunea anterioara poate recompilat, si se lucreaza cu versiunea noua. In contrast, o versiune noua de componenta este compatibila binar daca o aplicatie care depinde de versiunea anterioara poate, fara compilare, sa lucreze cu versiunea noua. Majoritatea limbajelor nu suporta compatibilitatea binara. Ca si exemplu, considerate situatia unei clase de baza author care cumpara o clasa numita Base. In prima versiune, Base nu contine metoda F. O component numita Derived deriveaza din Base, si introduce metoda F. Clasa Derived, impreuna cu clasa Base de care depinde, este vanduta la client, care instaleaza nu numar mare de client si servere.
// Author A namespace A { public c l a s s Base // v e r s i o n 1 { } } // Author B namespace B { c l a s s D e r i v e d : A. Base { public v i r t u a l void F ( ) { System . C o n s o l e . WriteLi ne ( " Derived .F" ) ; } }

52
}

CAPITOLUL 1. PREZENTAREA LIMBAJULUI

Pana aici toate bune, dar acum la o versiune noua apar problemele. Autorul clasei Base produce o noua versiune, continand metoda F.
// Author A namespace A { public c l a s s Base // v e r s i o n 2 { public v i r t u a l void F ( ) // added i n v e r s i o n 2 { System . C o n s o l e . WriteLine ( " Base .F" ) ; } } }

Noua versiune a clasei Base ar trebui sa e compatibila si binar si sursa cu versiunea initiala. Din pacate, noua metoda F din clasa Base face ca intelesul metodei F din clasa derivate Derived sa e neclar. S-a referit clasa Derived sa rescrie metoda F din clasa Base ? Acest lucru pare unic, din moment ce Derived a fost compilata, iar Base nici nu avea metoda F. Mai departe, daca metoda F din Derived rescrie metoda F din Base, atunci trebuie sa adere la contractual specicat de Base - un contract care a fost nespecicat cand Derived a fost scrisa. In unele cazuri, este imposibil. De exemplu, metoda F din clasa Base necesita rescrierea ei sa e apelata de baza. Metoda F din Derived nu poate sa adere la un astfel de contract. C# adreseaza acesta problema de versiune pentru ca interventia programatorilor sa e clara. In exemplul de cod original, codul era clar, din moment ce clasa Base nu continea metoda F. Metoda F din Derived intentiona sa e o noua metoda decat una rescrisa din clasa de baza, din moment ce nu exista in clasa de baza. Daca Base adauga metoda F si apare o noua versiune, intentia versiunii binare a clasei Derived este clara - metoda F din Derived nu este legata din punct de vedere semantic , si trebuie sa nu e tratata ca si o metoda rescrisa. Oricum, cand Derived este recompilata, intelesul este neclar - autorul clasei Derived poate intentioneaza ca metoda F sa rescrie metoda F din clasa Base, sau sa o ascunda. Din moment ce intentia este neclara, compilatorul produce o avertizare, si standard face ca metoda F din Derived sa ascunda metoda F din Base. Avertizarea generate alerteaza autorul clasei Derived de prezenta metode F din Base. Daca metoda F din Derived nu este semantic legata de F din Base, atunci autorul clasei Derived poate exprima acesta intentie - si in efect, avertizarea va oprita - prin utilizarea cuvantului cheie new in declararea lui F.
// Author A namespace A { public c l a s s Base // v e r s i o n 2 { public v i r t u a l void F ( ) // added i n v e r s i o n 2 { System . C o n s o l e . WriteLine ( " Base .F" ) ; } }

1.14. ATRIBUTE
} // Author B namespace B { c l a s s D e r i v e d : A. Base // v e r s i o n 2a : new { new public v i r t u a l void F ( ) { System . Conso1e . w r i t e L i ne ( " Derived .F" ) ; } } }

53

Pe de alta parte, autorul clasei Derived poate investiga mai departe, si poate decide ca metoda F din Derived sa rescrie metoda F din Base. Acesta intentie poate specicata utilizand cuvantul cheie override, ca mai jos:
// Author A namespace A { public c l a s s Base // v e r s i o n 2 { public v i r t u a l void F ( ) // added i n v e r s i o n 2 { System . Conso1e . w r i t e L i n e ( " Base .F" ) ; } } } // Author B namespace B { c l a s s D e r i v e d : A. Base // v e r s i o n 2 b : o v e r r i d e { public override void F ( ) { base . F ( ) ; System . Conso1e . w r i t e L i ne ( " Derived .F" ) ; } } }

Autorul clasei Derived mai are o optiune, si anume sa schimbe numele lui F, astfel se evita complet coliziunea de nume. Desi acesta schimbare va intnrerupe compatibilitatea binara si sursa pentru clasa Derived, importanta acestei compatibilitati depinde de scenariu. Daca Derived nu este expusa altor programe, schimbarea numelui F este o idee buna, pentru ca imbunatateste citirea programului - si nu vor mai confuzii legate de intelesul metodei F.

1.14

Atribute

C# este un limbaj impreativ, dar ca si alte limbaje imperative are cateva elemente declarative. De exemplu, accesibilitatea unei metode dintr-o clasa este specicata prin declararea ei ca public, protected, internal, protected internal, sau private. C# generalizeaza aceasta capabilitate, astfel ca programatorii pot inventa noi tipuri de informatii declarative, atasand aceste informatii declarative diverselor entitati din program, si returna astfel de informatii la rulare.

54

CAPITOLUL 1. PREZENTAREA LIMBAJULUI

De exemplu, un framework poate deniun atribut HelpAttribute, care poate plasat in elementele programului, cum ar clasele si metodele, permitand programatorilor sa ofere translatarea elementelor programului in documentatie pentru acestea. Exemplu:
using System ; [ Attributeusage ( Attri buteTargets . All ) ] pub1ic c1ass He1pAttribute : Attribute { pub1ic He1pAttribute ( string u r l ) { this . u r l = u r l ; } p u b 1 i c s t r i n g Topic = null ; private s t r i n g u r l ; public s t r i n g Url { get { return u r l ; } } } }

Deneste o clasa atribut numita HelpAttribute, sau Help mai scurt, care are un parametru positional (string url) si un nume de parametru (string Topic). Parametrii pozitional sunt deniti de parametrii formali pentru constructorii de insante publici ai clasei attribute, iar numele parametrilor sunt denite de campurile non-statice si proprietatille clasei attribute. Exemplu:
[ He1p ( " http :// www . mycompany . com /.../ Class1 .htm ) ] public c1ass C1ass1 { [ He1p (" h t t p : //www . mycompany . com / . . . / C1ass1 . htm , Topic = F) ] p u b 1 i c void F ( ) {} }

arata cateva utilizari ale atributului Help. Informatia atribut poentru un element de program poate returnata la rulare utilizand suportul reectarii. Exemplu:
using System ; c 1 a s s Test { s t a t i c void Main ( ) { Type type = typeof ( C1ass1 ) ; object [ ] a r r = type . GetCustomAttributes ( typeof ( H e 1 p A t t r i b u t e ) , true ) ; i f ( a r r . Length == 0 ) Conso1e . WriteLine ( " C1ass1 has no He1p attribute ." ) ; else

1.14. ATRIBUTE
{

55

H e 1 p A t t r i b u t e ha = ( H e 1 p A t t r i b u t e ) a r r [ 0 ] ; Conso1e . WriteLine ( " ur1 = {0} , Topic = {1} " , ha . Ur1 , ha . Topic ) ; } } }

verica daca exista atributul Help in clasa Class1, si aseaza valorile associate Topic si Url daca atributul este present.

56

CAPITOLUL 1. PREZENTAREA LIMBAJULUI

Capitolul 2

Concepte de baza
2.1 Pornirea aplicatiei

Aplicatia startup se intalneste atunci cand mediul de executie/efectuare numeste o metoda indicata, care este atribuita punctului/nivelului de inregistrare/intrare al aplicatiei. Aceasta metoda punct de inregistrare/intrare este mereu numit Main (fundamental/principal) si va avea una din urmatoarele indicatii :
static static static static void void int int Main ( ) { . . . } Main ( s t r i n g [ ] a r g s ) { . . . } Main ( ) { . . . } Main ( s t r i n g [ ] a r g s ) { . . . }

Dupa cum se arata, punctul de inregistrare poate in mod optional sa raporteze o valoare int . Aceasta valoare raport este folosita in terminarea aplicatiei. Punctul de inregistrare poate in mod optional sa ai aiba un parametru exact si acest parametru exact poate avea orice denumire. Daca un asemenea parametru este numit, trebuie sa se conformeze urmatoarelor constrangeri : Implementarea va asigura ca valoarea acestui parametru nu este null . Permiteti ca args sa e denumirea parametrului. Daca lungimea dispunerii desemnata de args este mai mare de zero, elementele dispuse args[0] prin args[args. Lungime-1] , inclusiv, trebuie sa se refere la serii, numite parametrii aplicatiei, unde le sunt date valori denite implementate de purtatorul de mediu precedent pornirii aplicatiei. Scopul este sa raspunda la informatia aplicatiei determinata precedent pornirii aplicatiei din alta parte din mediul purtat. Daca purtatorul de mediu nu este capabil sa completeze seriile cu litere mari si mici, implementarea va asigura ca seriile sunt completate cu litere mici. [Nota : La sistemele care folosesc o linie de comanda, parametrii aplicatiei corespund la ceea ce este in general cunoscut argumente linie-comanda. sf. nota]. De cand C# necesita metoda de supraincarcare, o clasa sau structura poate contine multiple denitii ale unei metode, cu conditia ca ecare sa aiba o semnatura diferita. Cu toate acestea, intr-un singur program, nici o clasa sau structura nu va contine mai mult decat o metoda numita Main, a carei denitie o calica 57

58

CAPITOLUL 2. CONCEPTE DE BAZA

sa e utilizata ca punct de inregistrare al aplicatiei. Alte versiuni supraincarcate de Main sunt permise, totusi cu conditia ca ele sa aiba mai mult de un parametru, sau singurul lor parametru sa e altul decat cel de tipul string (serie). O aplicatie poate compusa din multiple clase sau structuri. Daca este posibil ca pentru mai mult de una dintre aceste clase sau structuri sa contina o metoda numita Main a carei denitie o calica sa e folosita ca un punct de inregistrare aplicatie. In asemenea cazuri, una dintre aceste metode Main trebuie sa e alese ca punct de inregistrare pentru ca pornirea aplicatiei sa aiba loc. Aceasta alegere ca punct de inregistrare este in afara sferei de specicatie nici un mecanism de specicare sau de determinare al unui punct de inregistrare nu este prevazut. In C# ecare metoda trebuie sa e denita ca un element al unei clase sau structuri. In mod ordinal, accesibilitatea declarata a unei metode este determinata de modicatorii de acces specicati in declaratia sa si in mod similar accesibilitatea declarata a unui simbol este determinata de modicatorii de acces specicati in declaratia sa. Pentru ca o metoda data a unui simbol dat, sa e numita, si tipul si elementul trebuie sa e accesibile. Totusi, punctul de inregistrare al aplicatiei este un caz special. In mod specic, mediul de executie poate accesa punctul de inregistrare al aplicatie indiferent de accesibilitatea sa declarata si indiferent de accesibilitatea declarata a declaratiilor tip concrete. In toate celelalte privintele, metodele punct de inregistrare se comporta ca acelea care nu sunt puncte de inregistrare.

2.2

Terminarea aplicatiei

Terminarea aplicatiei schimba comanda la mediul de executie. Daca forma de schimb a punctului de inregistrare al aplicatiei este int , valoarea de schimb foloseste ca terminarea statusului cod a aplicatiei. Scopul acestui cod este sa permita informatia de reusita sau eroare la mediul de executie. Daca forma de schimb a metodei punctului de inregistrare este void (spatiu gol), folosind acolada dreapta (}) care delimiteaza aceasta metoda, sau executand o formulare de shimb care nu are denumire, are drept rezultat terminarea codului status de 0. Precedent terminatiei unei aplicatii, distrugatoare pentru toate obiectele sale care nu au fost inca colectate ca resturi sunt denumite, doar daca asemenea stergere a fost suprimata (de o denumire la metoda biblioteca, de exemplu : GC.SuppressFinalize ).

2.3

Declaraii

Declaratiile intr-un program C# denesc elemenetele componenete ale programului. Programele C# sunt organizate folosind namespaces, care contin declaratii tip si decalaratii namespace inserate. Declaratiile tip sunt folosite pentru a deni clase, structuri, interfete, enunturi si sarcini. Aceste feluri de elemente permise intr-o declaratie tip, depinde de forma declaratiei tip. De exemplu, declaratiile clasa pot contine declaratii pentru constante, campuri, metode, pro-

2.3. DECLARAII

59

prietati, evenimente, indicilor, administratori, constructori de situatie, distrugatori, constructori statici, metode inserate. Declaratiile denesc un nume un spatiul de declaratie, in care declaratia apartine. Cu exceptia elementelor supraincarcate, este o eroare de durata compilata sa aiba doua sau mai multe declaratii, care introduc elemente cu aceeasi denumire in spatiul de declaratie. Cu toate acestea, nici un diagnostic este cerut daca spatiul de declaratie este un namespace pentru spatiile de declaratie globale si declaratii de conict, sunt in programe separate. Nu este posibil vreodata pentru un spatiu de declaratie sa contina diferite tipuri de elemente cu aceeasi denumire. [De exemplu, un spatiu de declaratie nu poate contine un camp si o metoda cu aceeasi denumire.] Sunt descrise cateva tipuri de spatii de declaratii, dupa cum urmeaza : In toate sierele de origine ale unui program, declaratiile-element-namespace fara declaratii-namespace anexate, sunt elemente ale unui singur spatiu de declaratie combinat numit spatiul de decalaratie global. In toate sierele de origine ale unui program, declaratiile-element-namespace in cadrul declaratiilor-namespace care au aceeasi denumire namespace complet calicata sunt elemente ale unui singur spatiu de declaratie combinat. Fiecare clasa, structura sau declaratie interfata creeaza un nou spatiu de declaratie. Denumirile sunt introduse in acest spatiu de declaratieelement-clasa, declaratie-element-structura, declaratie-element-interfata. Exceptand declaratiile constructor de situatie supraincarcate si declaratiile constructor xe, o declaratie element structura sau clasa nu poate introduce un element cu aceeasi denumire ca cea a clasei sau a structurii. O clasa, structura sau interfata, permite declaratia metodelor supraincarcate si a indicilor. In plus, o clasa sau structura permit declaratia constructorilor de situatie supraincarcati si administratori. [ De exemplu : o clasa, structura sau interfata, poate contine declaratii metode multiple cu aceeasi denumire, cu conditia ca aceste declaratii metoda sa difere in semnatura lor ]. Clasele de baza nu contribuie la spatiul de declaratie al unei clase si interfetele de baza nu contribuie la spatiul de declaratie al unei interfate. Prin urmare, unei interfete sau clase derivate ii este permis sa declare un element cu aceeasi denumire ca si elementul ereditar. Fiecare declaratie de listare creeaza un spatiu de declaratie nou. Denumirile sunt introduse in acest spatiu de declaratie prin declaratiile-elementenunt. Fiecare bloc sau bloc de modicare creeaza un spatiu de declaratie pentru variabilele locale si constantele locale. Denumirile sunt introduse in acest spatiu de declaratie prin declaratiile-variabila-locala si declaratiileconstanta-locala. Daca un bloc este componenta uni constructor de situatie, metoda, sau declaratie administrator, sau un set accesoriu pentru o declaratie indice, parametrii desemnati intr-o asemenea declaratie sunt membrii spatiului de declaratie variabil local al unui bloc. Spatiul de declaratie variabil local al unui bloc include orice blocuri inserate. Prin

60

CAPITOLUL 2. CONCEPTE DE BAZA urmare, in interiorul unui bloc inserat nu este posibil sa se declare o variabila locala sau constanta cu aceeasi denumire ca cea a variabilei locale sau constante intr-un bloc inclus. Fiecare bloc sau bloc de modicare creeaza un spatiu de declaratie separat pentru etichete. Denumirile sunt introduse in acest spatiu de declaratie prin declaratiile-eticheta si denumirile sunt mentionate prin enunturilegoto. Spatiul de declaratie eticheta din blocuri include orice blocuri inserate. Asadar, inauntrul unui bloc inserat nu este posibil sa enuntam o eticheta cu acceasi denumire ca si o eticheta dintr-un bloc inclus.

Comanda textuala in care denumirile sunt enuntate, este in general fara semnicatie. In particular, comanda textuala este fara semnicatie pentru enuntarea si folosirea namespaces-urilor, constantelor, metodelor, proprietatilor, evenimentelor, indicilor, adminitratorilor, constructorilor de situatie, distrugatorilor, constructorilor statici si tipurilor. Comanda de declaratie este importanta in urmatoarele moduri: Comanda de declaratie pentru declaratiile camp si declaratiile variabila locala determina ordinea in care initializatorii (daca exista) sunt efectuati. Variabilele locale trebuie sa e denite inainte sa e utilizate. Comanda de declaratie pentru declaratiile element enunt este importanta valorile expresie-constanta sut omise. Exemplu : spatiul de declaratie al unui namespace este deschidere nalizata si doua declaratii namespace cu acelasi nume complet calicat contribuie la acelasi spatiu de declaratie. De exemplu:
namespace Megacorp . Data { c l a s s Customer { ... } } namespace Megacorp . Data { class order { ... } }

Cele doua declaratii namespace de mai sus cotribuie la acelasi spatiu de declaratie, in cazul enuntarii doua clase cu denumiri complet calicate Megacorp.Data.Customer(client) si Megacorp.Data.Order(comanda). Deoarece cele doua declaratii contribuie la acelasi spatiu de declaratie ar dus la o eroare timp-compilat daca ecare cuprindea cate o declaratie a unei clase cu aceeasi denumire. Nota: cum este specicat mai sus, spatiul de declaratie al unui corp orice blocuri inserate. Asadar, in exemplul urmator, metodele F si G rezulta intr-o eroare timp-compilat deoarece numele i este declarat in blocul exterior si nu

2.4. MEMBRII

61

poate redeclarat in blocul interior. Totusi metoda H s I sunt valabile de cand cei doi i sunt declarati in spatii separate neinserate.
class A { void F ( ) { int i = 0 i f ( true ) { int i = 1 } } void G( ) { i f ( true ) { int i = 0 } int i = 1 } void H( ) { i f ( true ) { int i = 0 } i f ( true ) { int i = 1 } } void I ( ) { f o r ( i n t i = 0 ; i < 1 0 ; i ++) H () ; f o r ( i n t i = 0 ; i < 1 0 ; i ++) H () } } }

2.4

Membrii

Spat iile de nume si metodele prezinta elemente. [Nota: Elementele unei entitati sunt in general prin utilizarea unui nume calicat care incepe cu o trimitere la entitate, urmat e un semn . si de denumirea membrului. Elementele unei metode sunt e declarate in tipul sau forma ereditara din clasa de baza a unei metode. Cand o metoda primeste de la o clasa de baza toate elementele clasei de baza, exceptand constructorii de situatie, distrugatorii si constructorii statici,devin elemente ale unei metode derivate. Accesibilitatea enuntata a unui element clasa de baza nu controleaza e elementul primit-precedarea se prelungeste la orice element care nu este un constructor de

62

CAPITOLUL 2. CONCEPTE DE BAZA

situatie, constructor static sau distrugator. Totusi, un element primit poate sa nu e accesibil intr-o metoda derivata, e din cauza accesibilitatii sale declarate sau e este ascunsa de o declaratie in metoda insasi.

2.4.1

Membrii nume de spatiu

Namespace-urile si metodele care nu au namespace anexat sunt elemente ale namespace-ului global. Aceasta corespunde in mod direct cu denumirile enuntate in spatiul de declaratie global. Namespace-urile si metodele declarate intr-un namespace sunt elemente ale namespace-ului. Aceasta corespunde in mod direct cu denumirile enuntate in spatial de declaratie al namespace-ului. Namespace-urile nu prezinta restrictii de acces. Nu este posibil sa e numit privat, protejat sau namespace-uri interne si denumirile namespace sunt mereu in mod public accesibile.

2.4.2

Membrii structura

Elementele unei structuri sunt elemente declarate in structura si elementele mostenite de la clasa de baza directa System.ValueType(sistem.valoare.tip) al structurii si clasa de baza indirecta object(obiect). Elementele unei metode simple corespund in mod direct elementelor metodei structura cunoscute de metoda simpla: Elementele lui sbyte sunt elementele structurii System.SByte. Elementele lui byte(octet) sunt elementele structurii System.SByte. Elementele lui short(scurt) sunt elementele structurii System.Int16. Elementele lui ushort sunt elementele structurii System.UInt16. Elementele lui int sunt elementele structurii System.Int32. Elementele lui uint sunt elementele structurii System.UInt32. Elementele lui long(lung) sunt elementele structurii System.Int64. Elementele lui ulong(lung) sunt elementele structurii System.UInt64. Elementele lui char sunt elementele structurii System.Char. Elementele lui float(stabilizare) sunt elementele structurii System.Single. Elementele lui double(dublu)sunt elementele structurii System.Double. Elementele lui decimal(decimal) sunt elementele structurii System.Decimal. Elementele lui bool sunt elementele structurii System.Boolean.

2.4.3

Membrii enumerare

Elementele unei enumeratii sunt constantele declarate in enumeratie si elementele mostenite de la clasa de baza directa System.Enum si clasa de baza indirecta System.ValueType si object(obiect) a enumeratiei.

2.5. ACCESAREA MEMBRILOR

63

2.4.4

Membrii clasa

Elementele unei clase sunt elementele declarate in clasa si elementele mostenite de la clasa de baza (cu exceptia clasei objet care nu are nici o clasa de baza). Elementele mostenite de la clasa de baza cuprind constante, campuri, metode, proprietati, evenimente, indici, administratori si tipuri de clase de baza, dar nu si constructorii de situatie, distrugatorii si constructorii statici ai clasei de baza. Elementele clasa de baza sunt mostenite fara considerent la accesibilitatea lor. Un enunt clasa poate cuprinde enunturi de constante, campuri, metode, proprietati, evenimente, indici, administratori, constructori de situatie, distrugatori, constructori statici si metode. Elementele unui obiect si serii corespund in mod direct cu elementele metodelor de clasa cunoscute ca: Elementele de obiect sunt elementele clasei System.Object(sistem.obiect). Elementele de serie sunt elementele clasei System.String(sistem.serie).

2.4.5

Membrii interfata

Elementele unei interfete sunt elemente declarate in interfata si in toate interfetele de baza ale interfetei. Nota: elementele unei clase obiect nu sunt, drept vorbind, elementele oricarei interfete. Totusi, elementele din clasa obiect sunt valabile prin vericarea de element in orice tip de interfata.

2.4.6

Membrii matrice

Elementele oricarui tabel sunt elemente mostenite din clasa System.Array.

2.4.7

Membrii delegati

Membrii unui delegat sunt mosteniti din clasa System.Delegate.

2.5

Accesarea membrilor

Declaratiile de elemente permit controlul asupra accesului element. Accesibilitatea unui element este stabilita de accesibilitatea declarata a unui element combinat cu accesibilitatea tipului continut, daca exista. Cand accesul la un element particular este permis, elementul se spune ca este accesibil. Invers, cand accesul la un element particular nu este permis, elementul se spune ca este inaccesibil. Accesul la un element este permis atunci cand locatia textuala in care accesul are loc este inclusa in domeniul de accesibilitate al elementului.

2.5.1

Declararea accesabilitatii

Accesibilitatea declarata a unui element poate una din urmatoarele: Publica, care este selectata prin includerea unui calicativ public in declaratia element. Intelesul intuitiv al lui public este accesul nu este restrictionat.

64

CAPITOLUL 2. CONCEPTE DE BAZA Protejata, care este selectata prin includerea unui calicativ protejat in declaratia element. Intelesul intuitiv al lui protejat este acces restrictionat la metodele sau clasele incluse, derivate din clasa inclusa . Interna, care este selectata prin includerea unui calicativ intern in declaratia de clasa. Intelesul intuitiv al lui intern este acces restrictionat la acest program . Protejata intern, care este selectata prin includerea ambelor calicative protejat si intern, in declaratia element. Intelesul intuitiv al lui protejat intern este acces restrictionat la acest program sau tipuri derivate din clasa inclusa . Particulara, care este selectata prin includerea unui calicativ particular in declaratia element. Intelesul intuitiv al lui particular este acces limitat la aceasta metoda inclusa .

In functie de contextul de care depinde in care o declaratie element are loc, numai anumite tipuri de accesibilitate declarata sunt permise. Mai mult decat atat, cand o declaratie element nu include nici un calicativ de acces, contextul in care declaratia are loc determina accesibilitatea declarata initiala. Namespace-urile au implicit, accesibiliatte declarata public . nici un calicativ de acces nu este in declaratiile namspace. Metodele declarate in colectia unitatilor sau namespace-urilor, pot avea accesibilitate declarata interna sau publica si initiala la accesibilitate declarata interna. Elementele de clasa pot oricare dintre cele cinci feluri de accesibilitate interna si initiala, la accesiblitatea declarata interna . [Nota : o metoda declarata al unui element al unei clase poate avea oricare dintre cele cinci feluri de accesibilitate declarata, pe cand o metoda declarata a unui element al unui namespace poate avea numai accesibilitate publica sau interna . Elementele de structura pot avea accesibilitate declarata publica , interna , particulara si initiala la accesibilitatea declarata particulara deoarece structurile sunt implicit inchise. Elementele de structura introduse intr-o structura (care nu este mostenit de aceea structura) nu pot avea accesibilitate declarata protejata sau protejata intern . [Nota : o metoda declarata ca element al unei structuri poate avea accesibilitate declarata publica, interna, particulara, pe cand o metoda declarata a unui ca un element al unui namespace poate avea numai accesibilitate declarata publica sau interna . Elementele interfata au implicit accesibilitate declarata publica . Nici un calicativ de acces nu permis la declaratiile element interfata. Enumerarea elementelor are implicit accesibilitate declarata publica . . Nici un calicativ de acces nu permis la declaratiile element enumerare.

2.5. ACCESAREA MEMBRILOR

65

2.5.2

Domenii de accesibilitate

Domeniul de accesibilitate al unui element consta in (posibila detasare) sectiuni ale textului program in care accesul la un element este permis. Pentru scopurile denirii domeniului de accesiblitate al unui element, un element este numit primul nivel daca nu este declarat in cadrul unei metode si un element este numit inclus daca este declarat in cadrul altei metode. In plus, textul unui ansamblu este denit ca toate textele sursa continute in toate sierele sursa, al acelui ansamblu, si textul sursa al unei metode este denit ca toate textele sursa continute intre semnele de inceput si sfarsit and , in organizatia-clasa , organizatia-structura , organizatia-interfata sau organizatia-enumeratie a metodei (incluzand diferite tipuri care sunt incluse in cadrul metodei). Domeniul de accesibilitate al unei metode predenite este (ca obiect, int sau dublu ) nelimitat. Domeniul de accesibilitate al unei metode primul nivel T care este declarata intr-un program P, este denita dupa cum urmeaza: Daca accesibilitatea declarata a lui T este publica , atunci domeniul de accesibilitate al lui T este textul program al lui P si oricare alt program care face referinta la P. Daca accesibilitatea declarata a lui T este interna , atunci domeniul de accesibilitate al lui T este textul program al lui P. [Nota : din aceste denitii se observa ca domeniul de accesibilitate al lui T este textul program al lui P.] Domeniul de accesibilitate al unui element M inclus intr-o metoda T intr-un program P este denit dupa cum urmeaza (chiar M insusi poate o metoda) : Daca accesibilitatea declarata a lui M este publica , atunci domeniul de accesibilitate al lui M este textul program al lui T. Daca accesibilitatea declarata a lui M este protejata intern , permiteti D sa e imbinarea textului program al lui T si textul program al oricarui tip derivat din T, care este declarat in afara lui P. Domeniul de accesibilitate al lui M este intersectia domeniului de accesibilitate al lui T cu D. Daca accesibilitatea declarata a lui M este protejata , permiteti D sa e imbinarea textului program al lui T si textul program al oricarui tip derivat din T. Domeniul de accesibilitate al lui M este intersectia domeniului de accesibilitate al lui T cu D. Daca accesibilitatea declarata a lui M este interna , atunci domeniul de accesibilitate al lui M este intersectia domeniului de accesibilitate al lui T cu textul program al lui P. Daca accesibilitatea declarata a lui M este particulara , atunci domeniul de accesibilitate al lui M este testul program al lui T. Nota : in termeni intuitivi, cand un tip sau element M este accesat, urmatorii pasi sunt evaluati sa asigure ca accesul este permis : Intai, daca M este declarat in cadrul unui tip (ca opus la unitatea colectie sau namespace), o eroare timp-colectie are loc daca acel tip nu este accesibil

66

CAPITOLUL 2. CONCEPTE DE BAZA Dupa aceea, daca M este public, accesul este permis. Altfel, daca M este protejat intern , accesul este permis daca exista in cadrul programului in care M este declarat sau daca are loc in cadrul unei clase derivate din clasa in care M este declarat si are loc prin tipul clasa derivat. Altfel, daca M este protejat accesul este permis daca exista in cadrul clasei in care M este declarat sau daca are loc in cadrul unei clase derivate din clasa in care M este declarat si are loc prin tipul clasa derivat. Altfel, daca M este intern accesul este permis daca exista in cadrul programului in care M este declarat. Altfel, daca M este particular accesul este permis daca exista in cadrul tipului in care M este declarat. Altfel, tipul sau elementul este inaccesibil si eroarea timp-colectie are loc.

In exemplul
public c l a s s A { public s t a t i c i n t X; internal s t a t i c in t Y; private s t a t i c i n t Z ; } internal c l a s s B { public s t a t i c i n t X; internal s t a t i c in t Y; private s t a t i c i n t Z ; public c l a s s C { public s t a t i c i n t X; internal s t a t i c in t Y; private s t a t i c i n t Z ; } private c l a s s D { public s t a t i c i n t X; internal s t a t i c in t Y; private s t a t i c i n t Z ; } }

clasele si elementele au urmatoarele domenii de accesibilitate: Domeniul de accesibilitate al lui A si A.X este nelimitat. Domeniul de accesibilitate al lui A.Y, B, B.X, C, B.C.X si B.C.Y este textul program al programului continut. Domeniul de accesibilitate al lui A.Z este textul program al lui A. Domeniul de accesibilitate al lui B.Z si B.D este textul program al lui B, inclusiv textul program al lui B.C si B.D.

2.5. ACCESAREA MEMBRILOR Domeniul de accesibilitate al lui B.C.Z este textul program al lui B.C.

67

Domeniul de accesibilitate al lui B.D.X si B.D.Y este textul program al lui B, inclusiv textul program al lui B.C si B.D. Domeniul de accesibilitate al lui B.D.Z este textul program al lui B.D. Dupa cum arata exemplul, domeniul de accesibilitate al unui element nu este niciodata mai mare decat al unui tip cuprins. De exemplu, desi toate elementele X prezinta accesibilitate declarata publica, toate cu exceptia A.X au domenii de accesibilitate care sunt constranse de o metoda cuprinsa. Toate elementele unei clase de baza, cu exceptia constructorilor de situatie, distrugatorilor si constructorilor statici, sunt precedati de tipuri derivate. Acest lucru include chiar si elemente particulare al unei clase de baza. Totusi domeniul de accesibilitate al unui element particular, include numai textul program al metodei in care elementul este declarat. In exemplul :
class A { int X s t a t i c void F(B d ) { b . x = 1; // ok } } class B: A { s t a t i c void F(B d ) { b . x = 1; // Error , x nu e s t e a c c e s i b i l } }

clasa B primeste elemental particular x de la clasa A. Deoarece elementul este particular, este accesibil doar in cadrul organizatiei-clasa a lui A. Prin urmare, accesul la b.x este permis in metoda A.F , dar esueaza in metoda B.F.

2.5.3

Protejarea accesului pentru membrii instanta

Cand un element de caz protejat in afara textului program al clasei in care este declarat si cand un element de caz protejat intern este accesat in afara textului program al programului in care este declarat, accesul solicita sa aiba loc printr-un caz al tipului clasa derivat in care accesul are loc. Permiteti ca B sa e clasa de baza care declara un element M de caz protejat si permiteti D sa e o clasa care deriva din B. In cadrul organizatie-clasa a lui D, accesul la M poate avea urmatoarele forme: Un nume-tip necalicat sau expresie-primara a formei M. O expresie-primara a formei E.M, precum tipul lui E este D sau o clasa derivata din D. O expresie-primara a formei baza.M.

68

CAPITOLUL 2. CONCEPTE DE BAZA

Ca adaugare la aceste forme de acces, o clasa derivata poate accesa un constructor de situatie protejat al unei clase de baza intr-un initializator-constructor. In exemplul
public c l a s s A { protected i n t x ; s p a t i u s t a t i c F(A a , B b ) { a . x = 1; // ok b . x = 1; // ok } } public c l a s s B : A { s t a t i c void F(A a , B b ) { a . x = 1; // Error , t r e b u i e a c c e s a t p r i n e x e m p l u l lui B b . x = 1; // ok } }

din cadrul lui A, este posibil sa accesam X prin situatiile si ale lui A si ale lui B, pentru ca in ecare caz accesul are loc prin cazul lui A sau o clasa derivata din A. Totusi, in cadrul lui B, nu este posibil sa accesam x prin cazul lui A, pentru ca A nu deriva din B.

2.5.4

Constr angeri de accesabilitate

Mai multe constructii in limbajul C# necesita un tip care sa e cel putin la fel de accesibil ca un element al altui tip. Un tip T se spune ca este la fel de accesibil ca un element sau tip M daca domeniul de accesiblitate al lui T este superset al domenilui de accesibilitate al lui M. Cu alte cuvinte, T este cel putin la fel de accesibil ca M daca T este accesibil in toate contextele in care M este accesibil. Urmatoarele costrangeri de accesibilitate exista: Clasa de baza directa a unei clase tip trebuie sa e cel putin la fel de accesibila ca si clasa tip insasi. Interfetele de baza explicite ale unei interfete tip trebuie sa e cel putin la fel de accesibile ca si tipul interfata insusi. Metoda retur si metodele parametru ale unei metode delegate trebuie sa e cel putin la fel de accesibila ca si metoda delegata insasi. Tipul unei constante trebuie sa e cel putin la fel de accesibil ca si constanta insasi. Tipul unui camp trebuie sa e cel putin la fel de accesibil ca si campul insusi. Metoda retur si metodele parametru ale unei proceduri trebuie sa e cel putin la fel de accesibila ca si metoda insasi.

2.6. SEMNATURI SI SUPRA INCARCARE

69

Tipul unei proprietati trebuie sa e cel putin la fel de accesibil ca si proprietatea insasi. Tipul unui eveniment trebuie sa e cel putin la fel de accesibil ca si evenimentul insusi. Metoda si metodele parametru ale unui calicativ trebuie sa e cel putin la fel de accesibil ca si calicativul insusi. Metoda retur si metodele parametru ale unui administrator trebuie sa e cel putin la fel de accesibilie ca si administratorul insusi. Metodele paramentru alea unui constructor de situatie trebuie sa e cel putin la fel de accesibilie ca si canstructorul insusi. In exemplul
clasa A { . . . } public c l a s s B : A { . . . }

clasa B rezulta dintr-o eroare de timp-colectie deoarece A nu este cel putin la fel de accesibila ca si B. In exemplul :
class A { . . . } public c l a s s B { A F () { . . . } internal A G( ) { . . . } public A H( ) { . . . } }

metoda H in B rezulta intr-o eroare de timp colectie deoarece metoda retur A nu este cel putin la fel de accesibila ca si metoda.

2.6

Semnaturi si supra ncarcare

Metodele, constructorii de situatie, indicii si operatorii sunt caracterizati prin identicatorii lor: Identicatorul unei metode consta in denumirea metodei si tipului sau felului (valoare, referinta sau randament) ecaruia din parametrii exacti, analizati in ordine de la stanga la dreapta. Identicatorul unei metode, specic, nu include tipul retur, nici modicatorul parametru care poate specicat pentru parametrul cel mai corect. Indenticatorul unui indice consta in tipul ecaruia dintre parametriii formali, analizati in ordine de la stanga la dreapta. Indenticatorul unui indice in mod specic nu include tipul element, nici modicatorul parametru care poate specicat pentru parametrul cel mai corect. Indenticatorul unui administrator consta in numele administratorului si in tipul ecaruia dintre parametriii formali analizati in ordine de la stanga la dreapta. Identicatorul unui administrator in mod specic nu include tipul rezultat.

70

CAPITOLUL 2. CONCEPTE DE BAZA

Identicatorii reprezinta mecanismul de functionare pentru supraincarcarea elementelor din clase, structuri si interfete : Supraincarcarea metodelor permite ca o clasa, structura sau interfata sa declare multiple metode cu aceeasi denumire, cu conditia ca identicatorii sunt unici in acea clasa, structura sau interfata. Supraincarcarea constructorilor de situatie permite ca o clasa, structura sau interfata sa declare multipli constructori de situatie cu conditia ca identicatorii sunt unici in acea clasa sau structura. Supraincarcarea indincilor de situatie permite ca o clasa, structura sau interfata sa declare indici multipli cu conditia ca identicatorii sunt unici in acea clasa, structura sau interfata. Supraincarcarea administratorilor de situatie permite ca o clasa sau structura sa declare administratori multipli cu acelasi nume, cu conditia ca indenticatorii lor sunt unici in aceea clasa sau structura. Deci modicatorii parametru out si ref sunt considerati parte a unui identicator, elementele declarate intr-un singur tip nu pot sa difere in indenticator exclusiv prin ref si out . O eroare de timp colectie are loc daca doua elemente sunt declarate in acelasi tip cu identicatorii care vor acceasi daca parametrii din ambele metode cu modicatorii out au fost schimbati cu modicatorii ref . Pentru alte scopuri de potrivire a modicatorilor (ex : ascundere sau depasire) ref si out sunt considerati parte a unui indenticator si nu se potrivesc unul cu celalalt. Nota : aceasta restrictie este pentru a permite programelor C# sa e usor traduse pentru a functiona in Infrastructura Limbaj Universala (CLI), care nu asigura o modalitate sa deneasca metodele care care difera numai in ref si out . Exemplu : urmatorul exemplu arata un set de declaratii metoda supraincarcate impreuna cu identicatorii lor
interface ITest { void F ( ) ; void F( i n t x ) ; void F( r e f i nt x ) ; void F( out i n t x ) ; void F( i n t x , i n t y ) ; i n t F( s t r i n g s ) ; i n t F( i n t x ) ; void F( s t r i n g [ ] a ) ; void F( params s t r i n g [ ] a ) ; }

// // // // // // // // //

F() F( i n t ) F( r e f i n t ) F( o u t i n t ) eroare F( i n t , i n t ) F( s t r i n g ) F( i n t ) eroare F( s t r i n g [ ] ) F( s t r i n g [ ] ) e r o a r e

De retinut ca orice modicator parametru ref si out sunt parte dintr-un indicator. Astfel, F(int), F(ref int) si F(out int) sunt identicatorii unici. Totusi, F(ref int) si F(out int) nu pot declarati in cadrul aceleasi interfete deoarece identicatorii lor numai prin ref si out. De asemenea, de retinut, ca tipul retur si modicatorul parametru nu este parte dintr-un identicator, deci daca nu este posibil sa supraincarcam doar prin tipul retur sau prin includerea sau excluderea modicatorului parametru. Dupa cum reiese, declaratiile metodelor F(int) si F(parametrii serie) indenticate mai sus, rezulta intr-o eroare de timp-colectie.]

2.7. DOMENII DE VIZIBILITATE

71

2.7

Domenii de vizibilitate

Domeniul unei denumiri este regiunea textului program in cadrul caruia este posibil sa se faca referinta la o entitate declarata de denumire fara calicarea denumirii. Domeniile pot incluse si un domeniu intern pot redeclara intelesul denumirii dintr-un scop extern. [ Nota : totusi acest lucu, nu poate inlocui restrictia impusa de aceasta in cadrul unui bloc inclus, nu este posibil sa se declare o variabila locala cu aceeasi denumire ca o variabila locala intr-un bloc inclus]. Denumirea domeniului extern este dupa accea ascunsa in regiunea textului program de domeniul intern si accesul la denumirea externa este posibila doar prin calicarea denumirii. Domeniul unui element namespace numit de o declaratie-element-namespace cu nici o declaratie-namspace inclusa este intregul program text. Domeniul unui element namespace numit de o declaratie-element-namespace din cadrul unei declaratii-namespace al carui denumiri complet calicate este N, organizatia-namespace a ecarei declaratii-namespace a caror nume complet calicat este N sau incepe cu N, urmat de o pauza. Domeniul unei denumiri denite sau importate, printr-o directiva de utilizare extinde peste declaratiile element namespace a unitatii colectie sau organizatie namespace in care directiva de utlizare are loc. O directiva de utilizare poate face zero sau mai multe namespace-uri sau denumiri tip valabile intr-o unitate colectie particulara sau organizatie-namespace, dar care nu contribuie cu oricare elemente noi pentru a sublinia spatiul de declaratie. Cu alte cuvinte, o directiva de utilizare nu este tranzitiva, dar mai degraba afecteaza doar unitatea compilatie sau organizatia-namespace in care are loc. Domeniul unui element numit de o declaratie-element-clasa este organizatiaclasa in care declaratia are loc. In plus, domeniul unui element clasa se extinde la organizatia clasa a acelor clase care sunt incluse in domeniul de accesibilitate ale elementului. Aria de acoperire a unui membru declarat prin declaratia membrilor structurii(18.2) este acea parte a corpului structurii in cadrul careia are loc declarat ia. Aria de acoperire a unui membru declarat prin declarat ia membrilor enumeratiei(21.3) este acea parte a corpului enumerat iei in cadrul careia are loc declarat ia. Aria unui parametru declarat prin declarat ia metodei(17.5) este corpul acelei declarari al metodei (enunt arii metodei). Aria de acoperire a unui parametru declarat intr-o declarat ie indexata(17.8) este declarat ia accesorului 1adeclarat ieiei index. Aria de acoperire a unui parametru declarat intr-o declarat ie a operatorului(17.9) este baza acelei declarat ii

72

CAPITOLUL 2. CONCEPTE DE BAZA Aria de acoperire a unui parametru declarat in cadrul declarat iei operatorului(17.10) este elementul de iniatializare a constructorului si reprezinta un segment de program. Aria de acoperire a unei denumiri declarate printr-un enunt(15.4)este baza in cadrul careia are loc declarat ia. Aria unei variabile locale declarate prindeclarat ia variabilei locale(15.15.1)este baza in cadrul careia are loc declarat ia. Aria de acoperire a unei variabile locale declarate in cadrul unui bloc de comutare al enunt ului comutarii (15.7.2) este acel bloc de comutare. Raza unei variabile locale declarata in cadrul unei pro init ializari din cadrul unui enunt de tip pro(15.08.3)este acel init ializator pro,condit ia de tip pro;iteratorul pro si cont inutul propriu zis al enunt arii de tip pro. Raza unei constante locale declarate in acea declarat ie a constantei locale(15.5.2)este baza in care are loc declarat ia. Este o eroare a timpului de compilare 2 ce se refera la constanta locala si pozitia contextuala care apare/precede elementul de declarare a constantei.

In cadrul ariei de acoperire a unui spat iu-de-nume,clasa,structura sau membrul enumerat iei este posibil sa ne referim la membrul aat intr-o pozitie contextuala care precede declararea acelui membru.[De exemplu:
class A { void F ( ) { i = 1; } int i = 0 ; }

Aici este corect ca F sa se refere/sa faca trimitere la i inainte sa e enunt at. In cadrul ariei de acoperire a unei variabile locale,este o eroare de timp de compilare ce se refera la variabila locala intr-o pozitie contextuala ce precede elementul ce declara variabila locala acestei variabile.[De exemplu:
class A { int i = 0 ; void F ( ) { i = 1; declaratia int i ; i = 2; } void G( ) { int j = ( j = 1) ; }

// Eroarea , u t i l i z a r e a p r e c e d e

// V a l i d

2.7. DOMENII DE VIZIBILITATE


void H( ) { i n t a = 1 , b = ++a ; // V a l i d } }

73

Nota: 1. accesor=accesor(element al metodei accesarii,prin care se revine la valoarea curenta variabilei individuale unui membru.) 2. timp de compilare=in informatica timpul de compilare se refera e la operat iile efectuate de un compilator sau la cerint ele limbajului de programare ce trebuie sa e intrunite de catre codul sursa pentru a compilat cu success. In metoda F de mai sus , prima alocare 1 a lui i, in special ,nu se refera la campul declarat in afara ariei de act iune.Mai degraba se refera la variabila locala si are ca rezultat o eroare de timp de compilare deoarece in mod textual precede declararea variabilei.In metoda G,utilizarea lui j in cadrul initializatorului declarat iei lui j este valida deoarece uzul nu precede declarantul variabilei.In metoda H,un declarant ulterior al variabilei locale se refera in mod corect la o variabila locala declarata de un declarant anterior variabilei locale si codul aceleiasi declaratii al vcariabilei locale. Nota:Regulile referitoare la aria de acoperire a variabilei locale sunt elaborate pentru a garanta faptul ca nt elesul unui nume/denumiri folosit ntr-un context de exprimare este ntotdeauna acela si in cadrul unui bloc/unuitat i de stocare. Daca aria de extindere a unei variabile locale ar urma sa se extinda doar pe baza declararii din nalul unitatii de stocare,atunci in exemplul anterior,prima alocare ar catre o variabila de instant a,iar a doua alocare ar catre variabila locala.(In anumite situatii,dar nu in exemplul anterior,aceasta ar putea duce la o eroare de timp de compilare,daca enunturile segmentului de program ar urma sa e aranjate ulterior.) Sensul unui nume/cuv nt in cadrul unui segment de program poate diferi pe baza contextului in care e utilizat numele. In exemplu:
using System ; c l a s s A {} c l a s s Test { s t a t i c void Main ( ) { s t r i n g A = " hello , world " ; s t r i n g s = A; exprimare Type t = typeof (A) ; C o n s o l e . WriteLine ( s ) ; world C o n s o l e . WriteLine ( t . T o S t r i n g ( ) ) ; } }

// c o n t e x t de // t i p c o n t e x t // s c r i e h e l l o , // s c r i e Tip : A

numele A este utilizat intr-un context de exprimare pentru a se referi la o variabila locala A si intr-un context tip pentru a se referi la clasa A.

74

CAPITOLUL 2. CONCEPTE DE BAZA

2.7.1

Ascunderea numelui

Aria de acoperire a unei entitati este tipic mai mare ca text de programare decat declaratia spatiului acelei entitati.In mod particular ,aria de acoperire a acestei entitati poate include declaratii care sa introduca spat ii pentru alte declarat ii ce cont in entitat i cu acela si nume.Astfel de declaratii fac entitatea originala/initiala sa devina ascunsa.In mod logic,o entitate se spune ca este vizibila atunci cand nu este ascunsa. Ascunderea numelor are loc atunci cand ariile de acoperire se suprapun prin metoda gruparii si cand acestea se suprapun din punct de vedere al originii elementelor pe care le mo stenesc,in comun.Caracteristicile celor doua tipuri de ascundere/camuare sunt descriese in capitolele urmatoare. Camuarea prin metoda ncapsularii Aceasta poate aparea ca rezultat al gruparilor de spat iu-de-numee sau tipuri din cadrul spat iu-de-numeelor,ca rezultat al gruparilor din cadrul claselor sau structurilor,si ca rezultat al unui parametru si al unor declarat ii de variabile locale. In exemplul:
class A { int i = 0 ; void F ( ) { int i = 1 ; } void G( ) { i = 1; } }

din cadrul metodei F,variabila de instanta I este ascunsa de variabila locala I,dar in cadrul metodei G,I se refera tot la variabila de instanta Cand,un nume dintr-o arie de acoperire interioara ascunde un nume dintr-o arie exterioara, ascunde de fapt toate cazurile supraincarcate ale acelui nume. In exemplul
c l a s s Outer { s t a t i c void F( i n t i ) {} s t a t i c void F( s t r i n g s ) {} class Inner { void G( ) { F(1) ; // i n v o c a e x t e r i o r u l . F i n t e r i o r F( " Hello " ) ; // Eroare } s t a t i c void F( long l ) {} } }

2.7. DOMENII DE VIZIBILITATE

75

invocarea lui F(1) nseamna ca F este declarat Interior, deoarece toate aparit iile exterioare ale lui F sunt ascunse de declarat ia interioara.Din acela si motiv,invocarea lui F(Buna) are ca rezultat o eroare de timp de compilare. Camuare prin mo stenire Aceasta are loc atunci cand clasele sau structurile redeclara nume ce au fost mostenite de la clasele de baza. Acest tip de camuare a numelor ia una din urmatoarele forme: o constanta ,un c amp,o proprietate sau un eveniment sau tip introduse intr-o clasa sau structura camueaza toti membrii clasei de baza,sub acelasi nume; o metoda introdusa intr-o clasa sau structura ascunde toti membrii clasei de baza din afara metodei,sub acelasi nume si toate metodele clasei de baza sub aceea si semnatura(numele metodei si numararea parametrului,a modicatorilor si tipurilor). un indexator introdus intr-o clasa sau structura ascunde tot i indexatorii clasei de baza,sub acela si nume (numarul parametrilor si tipurile). Regulile care guverneaza declarat ia operatorului (17.9) fac imposibil ca o clasa derivata sa declare un operator cu aceeasi semnatura ca un operator al unei clase de baza.Astfel , operatorii nu se ascund niciodata unii pe altii. Spre deosebire de ascunderea unui nume dintr-o arie de acoperire exterioara ,ascunderea unui nume accesibil dintr-o arie mostenita/preluata ,face sa e raportat un avertisment. In exemplul:
c l a s s Base { public void F ( ) {} } c l a s s D e r i v e d : Base { public void F ( ) {} }

// a v e r t i s m e n t , // a s c u n d e r e a unui nume p u b l i c

declarat ia lui F in Derivatie face sa se emita un avertisment. Ascunderea unui nume mo stenit n mod special NU este o eroare, ntrucat aceasta ar exclude evolut ia separata a claselor de baza. De exemplu, n situatia de mai sus s-ar putut ntimpla acest lucru , deoarece o revenire ulterioara a Bazei a introdus o metoda F care nu a fost prezentata intr-o versiune timpurie acelei clase. Daca situat ia de mai sus ar fost o eroare, atunci orice schimbare facua clasei de baza intr-o grupare de clase cu versiuni separate ar putea,in mod potent ial,sa faca acele clase derivate sa devina nevalide. Avertismentul datorat ascunderii unui nume poate eliminat prin utilizarea unui nou modicator. Exemplu:
c l a s s Base { public void F ( ) {} }

76
c l a s s D e r i v e d : Base { new public void F ( ) {} }

CAPITOLUL 2. CONCEPTE DE BAZA

Noul modicator indica faptul ca F in Derivat este nou si ca ntr-adevar are menirea sa ascunda numele mostenit. O declarat ie a unui membru nou ascunde un membru mostenit doar in cadrul ariei de acoperire a unui membru nou. Exemplu:
c l a s s Base { public s t a t i c void F ( ) {} } c l a s s D e r i v e d : Base { new private s t a t i c void F ( ) {} } c l a s s MoreDerived : D e r i v e d { s t a t i c void G( ) { F() ; } }

// Ascunde Baza F // doar i n D e r i v a t

// I n v o c a Baza F

In exemplul de mai sus ,declararea lui F in Derivat ascunde acel F care a fost mostenit din Baza ,dar intrucat noul F din Derivat are acces privat, aria sa nu se extinde la SupraDerivat.Astfel aparit ia lui F in SupraDerivat G este valida si va invoca Baza F.

2.8

Nume de spatiu si nume de tip

Cateva secvent e din programul C# necesita ca formula spat iu-de-nume-nume sau tip-nume sa e specicata.Oricare din cele doua forme este scrisa ca unul sau mai mult i identicatori separat i prin semnul .. namespace-name: namespace-or-type-name type-name: namespace-or-type-name namespace-or-type-name: identier namespace-or-type-name . identier Un tip-nume este acel spatiu-de-nume-sau-tip-nume ce se refera la un tip/categorie.Urm and rezolvarea descrisa mai jos,spat iu-de-nume-sau-tip-nume a unui tip-nume trebuie sa se refere la un tip,astfel apare o eroare de timp de compilare.

2.8. NUME DE SPATIU SI NUME DE TIP

77

Un nume-spat iu-de-nume este un spat iu-de-nume-sau-tip-nume ce se refera la un spat iu-de-nume.Urmand rezolvarea de mai jos, spat iu-de-nume-sautip-nume al unui spat iu-de-nume-nume trebuie sa se refere la un spat iu-denume sau desi nou ,apare o eroare de timp de compilare. Semnicatia nume-de-spatiu-sau-tip-nume se determina dupa cum urmeaza: Daca spatiul-de-nume-sau-tip-nume consta intr-un singur identicator: Daca spat iul-de-nume-sau-tip-nume apare in cadrul unei clase sau declaratii a structurii,atunci incepind cu declaratia acelei clase sau structuri,si continuind cu ecare clasa ce se incude sau cu declararea structurii(dac exista) daca un membru cu nume alocat exista,este accesibil si denota un tip,atunci spat iulde-nume-sau-tip-nume se refera la membru. Membrii care nu apartin unui tip (constante, campuri, metode, proprietati, indexatori, operatori, constructori de instanta, destructori si constructori statici) sunt ignorati atunci cand se determina sensul unui spat iu-de-nume-sau-tip-nume. Astfel ,incepind cu spat iul-de-nume in care au loc spat iu-de-nume-sau-tipnume,continuand cu ecare spat iu-de-nume care se include (daca exista), si terminind cu spat iul-de-nume global,sunt evaluati urmatorii pasi pina la localizarea entitatii. Daca un spat iu-de-nume contine un membru cu un nume dat ,atunci spat iul-de-nume-sau-tip-nume se refera la acel membru si,in functie de membru,este clasicat ca tip sau spat iu-de-nume. Astfel daca acestui spat iu-de-nume ii corespunde o declaratie a spat iuluide-nume ce include locatia unde apare spat iu-de-nume-sau-tip-nume, atunci: Daca declaratia spat iului-de-nume contine o directiva ce foloseste nume fals ce asociaza numele dat cu un spat iu-de-nume sau tip important,atunci spat iul-de-nume-sau-tip-numese refera la acel spat iude-nume sau tip importat,atunci spat iul-de-nume-sau-tip-nume se refera la acel spat iu-de-nume sau tip. Altfel,daca acele spat iu-de-nume importate prin directive ce folosesc spat iu-de-nume de declarative contin exact un tip cu 10.nume dat.atunci spat iu-de-nume-sau-tip-nume se refera la acel tip. Altfel ,daca spat iile-de-nume importate prin directive ce folosesc spat iude-nume ale declaratiei contin mai multe tipuri cu nume dat,atunci spat iul-de-nume-sau-tip-nume este ambiguu si apare o eroare. Altfel ,spat iul-de-nume-sau-tip-nume este neterminat si apare o eroare de timp de compilare. Altfel,spat iu-de-nume-sau-tip-nume este de forma N.I.unde N.este un spat iu-de-nume-sau-tip-numece consta in toti identicatorii cu exceptia celui mai potrivit,si I este cel mai potrivit identicator. N este mai intai rezolvat ca spat iu-de-nume- sau-tip-spat iu-de-nume.Daca rezolvarea lui N nu are success,apare o eroare de timp de compilare .Altfel, N.I. se rezolva dupa cum urmeaza:

78

CAPITOLUL 2. CONCEPTE DE BAZA Daca N este spat iu-de-numeual si I este numele unui membru accesibil al spat iu-de-numeului,atunci N.I se refera la acel membru si,in functie de acesta ,e clasicat drept spat iu-de-nume sau tip. Daca N este o clasa sau un tip de structura si I este numele unui tip accesibil in N,atunci N.I se refera la acel tip. Altfel ,N.I. este un spat iu-de-nume-sau-tip-nume invalid si apare o eroare de compilare.

2.8.1

Nume complet calicate

Fiecare spat iu-de-nume sau tip au un nume complet calicat,care identica in mod unic spat iul-de-nume sau tipul dintre toate celelalte.Numele sau spat iulde-nume complet calicat sau tipul N este determinat dupa cum urmeaza: Daca N este un membru al spat iului-de-nume global,numele complet calicat este N. Altfel ,numele complet calicat este S.N.,unde S este numele complet calicat al spat iului-de-nume sau tipul in care w este declarat N. Cu alte cuvinte ,numele complet calicat al lui N este calea completa,ierarhica a identicatorilor care duc la N, incepand cu spat iul-de-nume global.Deoarece ecare membru al spat iului-de-nume sau tip trebuie sa aiba un nume unic,rezulta ca numele complet calicat al unui spat iu-de-nume sau tip este intotdeauna unic. Exemplul de mai jos arata cateva declaratii ale spat iilor-de-nume sau tipurilor cu nume complet calicate asociate lor.
c l a s s A {} namespace X { class B { c l a s s C {} } namespace Y { c l a s s D {} } } namespace X.Y { c l a s s E {} } // A // X // X.B // X.B.C // X.Y // X.Y.D

// X.Y // X.Y. E

2.9

Managementul automat al memoriei

C# implica administrarea memoriei automate,care absolva dezvoltatorii de alocarea manuala si de golirea memoriei ocupate de obiecte.Politicile de administrare a memoriei automate sunt implementate de colectorul de gunoaie. Ciclul de viata al managementului memoriei pentru un obiect este dupa cum urmeaza:

2.9. MANAGEMENTUL AUTOMAT AL MEMORIEI

79

1. Cand obiectul este creat,se aloca memorie pentru el,constructorul ruleaza,si obiectul este considerat viu. 2. Daca obiectul sau orice parte a acestuia nu poate accesat prin nici o metoda,alta decat rularea destructorilor,obiectul este considerat neutilizabil ,si devine eligibil pentru casare.[Nota:Implementarile pot opta sa analizeze codul pentru a determina ce referinte se pot utilize in viitor pentru un obiect.De exemplu ,daca variabila locala este in aria de acoperire este singura referinta existent privind obiectul,dar la variabila locala nu se fac referiri in nicio executie curenta a procedurii,atunci obiectul poate tratat printr-o implementare (dar nu este necesar).sfarsitul notei] 3. Odata obiectul devenit eligibil pentru distrugere,la un tip ulterior nespecicat,destructorii (17.12)(daca exista)sunt rulati.Daca nu exista solicitari explicite pentru mai multe rulari,destructorul este rulat doar odata. 4. data ce ruleaza destructorul pentru un obiect,daca acel obiect sau orice parte din el,nu pot accesate la nici un moment al executiei inclusive rularea destructorilor,atunci acel obiect e considerat inaccesibil si obiectul devine eligibil pentru colectare/stringerea de gunoi. 5. In nal ,la ceva vreme dup ace obiectul devine eligibil pentru stringere,colectorul de gunoaie elibereaza memoria/sterge obiectul din memorie. Gunoierul mentine informatia privind utilizarea obiectului si foloseste aceasta informative pentru a lua decizii de management al memoriei, ca de exemplu unde in memorie sa amplaseze un obiect nou creat,unde sa amplaseze un obiect si cand un obiect nu mai este utilizabil sau inaccesibil. Ca si alte limbaje ce presupun existent unui collector de gunoaie,C# este creat astfel incit acest collector de gunoaie sa poata implementa o gama larga de politici ale managementului memoriei.De exemplu ,C# nu necesita ca destructorii sa ruleze sau ca alte obiecte sa e strinse,imediat ce ele devin eligibile,sau ca destructorii sa ruleze intr-o anumita ordine,sau pe un anumit sir(engl:thread=serie de mesaje ce trateaza acelasi subiect). Comportamentul gunoierului poate controlat ,intr-o anume masura prin metode statice ale sistemului de clasa G.C. Nota: cat timp nu este necesara aceasta specicare/mentiune ,o metoda de strangere poate furnizata pe clasa G.C. ce necesita ca acea colectare/stranger de gunoi sa aiba loc.Urmatoarele exemple presupun existenta unei astfel de metode.Sfarsitul notei Exemplu:Atata timp cat gunoierului I se da o marja mare de decizie asupra momentului colectarii si rularii destructorilor,o implementare in conformitate cu aceasta poate produce un rezultat ce difera de cel indicat de codul urmator. Programul
using System ; class A { A( ) { C o n s o l e . WriteLine ( " Destruct instance of A" ) ; } }

80

CAPITOLUL 2. CONCEPTE DE BAZA

class B { object Ref ; public B( object o ) { Ref = o ; } B( ) { C o n s o l e . WriteLine ( " Destruct instance of B" ) ; } } c l a s s Test { s t a t i c void Main ( ) { B b = new B( new A( ) ) ; b = null ; GC. C o l l e c t ( ) ; GC. W a i t F o r P e n d i n g F i n a l i z e r s ( ) ; } }

creaza o instanta de clasa A si unul de clasa B.Obiectele devin eligibile pentru a stranse la gunoi cand variabilei bI se aloca valoarea null,deoarece dupa aceasta e imposibil ca orice cod de utilizare scris sa le mai acceseze. Rezultatul ar putea sa e: Distrugeti instanta A Distrugeti intsnta B. sau Distrugeti instanta B Distrugeti instanta A deoarece limbajul nu impune limite in ceea ce priveste ordinea in care obiectele sunt stranse la gunoi. In cazurile mai subtile,distinctia intre eligibil pentru a distrus si eligibil pentru a strans la gunoi poate importanta. De exemplu
using System ; class A { A( ) { C o n s o l e . WriteLine ( " Destruct instance of A" ) ; } public void F ( ) { C o n s o l e . WriteLine ( "A.F" ) ; Test . RefA = t h i s ; } } class B {

2.10. ORDINEA DE EXECUTIE


public A Ref ; B( ) { C o n s o l e . WriteLine ( " Destruct instance of B" ) ; Ref . F ( ) ; }

81

} c l a s s Test { public s t a t i c A RefA ; public s t a t i c B RefB ; s t a t i c void Main ( ) { RefB = new B( ) ; RefA = new A( ) ; RefB . Ref = RefA ; RefB = null ; RefA = null ; // A and B s u n t d i p o n i b i l e p e n t r u d i s t r u g e r e GC. C o l l e c t ( ) ; GC. W a i t F o r P e n d i n g F i n a l i z e r s ( ) ; // B e s t e d i s p o n i b i l p e n t r u d i s t r u g e r e , dar A nu e s t e i f ( RefA != null ) C o n s o l e . WriteLine ( " RefA is not null " ) ; } }

In programul de mai sus,daca gunoiul opteaza sa ruleze destructorul lui A inaintea destructorului lui B,atunci rezultatul acestui program poate : Distrugeti instanta A Distrugeti instanta B A.F Ref A nu este null Observati ca desi instanta A nu era in uz,si destructorul lui A a fost rulat,e totusi posibil ca metode din A (in acest caz,F sa e luate de la alt destructor).Observati de asemenea , ca rularea unui destructor poate face ca un obiect sa devina inutilizabil din linia programului principal.In acest caz ,rularea destructorului lui B a facut ca instanta lui A,care nu era anterior in uz,sa devina accesibil din referinta A active. Dupa apelarea Asteptati nalizatorii ce urmeaza sa vina,instanta B este eligibil sa e eliberat din memorie ,dar instanta A ramane in memorie, datorita referintei Ref A. Pentru a evita confuzia si comportamente neasteptate, in general este o idee buna ca destructorii sa realizeze/curatari(stergeri)/doar asupra datelor stocate in propriile campuri ale obiectelor si sa nu intreprinda actiuni asupra obiectelor la care se face referinta sau asupra campurilor statice.

2.10

Ordinea de executie

Executarea trebuie sa aiba loc astfel incat efectele secundare ale ecarui r de executie sa e pastrate (mentinute) la punctele critice de executie.Un efect secundar se deneste ca o scriere sau o citire a unui camp volatile,o scriere a unei

82

CAPITOLUL 2. CONCEPTE DE BAZA

variabile non-volatile,o scriere pe o resursa externa si o generare a unei exceptii.Punctele critice de executare la care trebuie mentinuta ordinea acestor efecte secundare sunt referintele la campurile volatile(17.4.3),enunturile de tip lock (blocare,codare)(15.12) si crearea unui sir si incheierea lui.O implementare este libera sa schimbe ordinea de executare a unui program C# ,daca se supune urmatoarelor obligatii: Dependenta informatiilor (datelor) se mentine pe parcursul unui r de executie.Adica , valoarea ecarei variabile este calculata ca si cum toate enunturile din sir ar executate in ordinea programului original. Regulile ce ordoneaza initializarea sunt mentinute/pastrate (17.4.4. si 17.4.5.). Ordonarea efectelor secundare se pastreaza respectand scrierile si citirile volatile (17.4.3).In plus ,o implementare nu trebuie sa evalueze parti ale unei expresii,daca se poate deduce ca valoarea acelei expresii nu este utilizata si ca nu sunt produse efecte secundare necesare (incluzind orice lucru cauzat de apelarea la o metoda sau de accesarea unui camp volatile).Cand executarea unui programeste intrerupta de evenimente asincrone (cum ar o exceptie produsa de un alt sir),nu se poate garanta ca efectele secundare observabile sunt vizibile in ordinea programului original.

Capitolul 3

Variabile
Variabilele reprezint a locat ii de stocare a datelor. Fiecare variabil a are un tip care determin a ce valori pot stocate n variabil a. C# este un limbaj type-safe si compilatorul C# garanteaz a c a valorile stocate n variabile sunt ntotdeauna de tip corespunz ator. Valoarea unei variabile poate schimbat a prin operat ia de atribuire sau aplicarea operatorilor ++ si . O variabil a trebuie s a e atribuit a (??) nainte ca valoarea ei s a poat a utilizat a. Variabilele pot s a e atribuite sau neatribuite init ial. O variabil a atribuit a init ial este bine denit a si este mereu considerat a atribuit a. O variabil a neatribuit a init ial nu are valoare init ial a. Pentru ca o variabil a neatribuit a init ial s a e considerat a atribuit a ntr-un anumit punct din program trebuie s a existe cel put in o atribuire a acesteia pe ecare cale posibil a prin care execut ia poate s a ajung a n acea locat ie.

3.0.1

Categorii de variabile

C# dene ste c ateva categorii de variabile: statice, de instant a, elemente de matrice, parametrii valoare, parametrii referint a, parametrii de ie sire si variabile locale. In sect iunea urm atoare sunt descrise ecare dintre aceste categorii. In exemplul
class A { public s t a t i c i n t x ; int y ; void F( i n t [ ] v , i n t a , r e f i nt b , out i n t c ) { int i = 1 ; c = a + b++; } }

x este o variabil a, y este o instant a de variabil a, v[0] este un element de matrice, a este un parametru valoare, b este un parametru de referint a, c este un parametru de ie sire si i este o variabil a local a. 83

84

CAPITOLUL 3. VARIABILE

3.0.2

Variabile statice

Un c amp declarat cu modicatorul static se nume ste variabil a static a. O variabil a static a ncepe s a existe naintea execut iei constructorului static (??) al tipului cont inut si nceteaz a s a existe c and nceteaz a s a existe si domeniul cont in ator. Valoarea init ial a a unei variabile statice este o valoare implicit a (??) a tipului variabilei. Din considerente legate de vericarea init ializ arii, o variabil a static a este mereu considerat a init ializat a.

3.0.3

Variabile de instant a

Un c amp declarat f ar a modicatorul static se nume ste variabil a de instant a. Variabile de instant a n clase O variabil a de instant a a unei clase ncepe s a existe c and este creat a o nou a instant a a clasei si nceteaz a s a existe c and nu mai exist a referint e c atre instant a sau este executat destructorul instant ei (dac a exist a). Valoarea init ial a a unei variabile de instant a este valoarea implicit a (??) a tipului variabilei. Din considerente legate de init ializare o variabil a de instant a este considerat a init ializat a. Variabile de instant a n structuri O variabil a de instant a a unei structuri are exact aceea si durat a de viat a ca o variabil a structur a c areia i apart ine. Cu alte cuvinte, c and o variabil a a unei structuri ncepe s a existe sau nu mai exist a, la fel si variabila structur a ncepe s a existe sau nu mai exist a. Starea init ial a a unei variabile de structur a este aceea si cu cea a variabilei structur a c areia i apart ine. C and o variabil a structur a este considerat a init ializat a, la fel, si variabilele de instant a sunt considerate init ializate, iar c and variabila structur a este considerat a neinit ializat a, si variabilele de instant a sunt de asemeni neinit ializate.

3.0.4

Variabile matrice

Elementele unei matrice exist a din momentul n care instant a este creat a, si nceteaz a s a existe c and nu mai exist a referint e c atre matrice. Valoarea ec arui element al unei matrice este valoarea implicit a (??) a tipului elementelor matricei. Din motive legate de vericarea init ializ arii, un element de matrice este considerat mereu init ializat.

3.0.5

Parametrii valoare

Un parametru declarat f ar a modicatorii ref sau out este un parametru valoare.

85 Un parametru valoare exist a din momentul apelului unui membru funct ie (metod a, instant a, constructor sau oparetor) c areia i apart ine parametrul valoare si este init ializat cu valoarea dat a argumentului la apel. Un parametru valoare nceteaz a s a existe c and se revine din apelul membrului funct iei. Din motive legate de vericarea init ializ arii, un parametru este considerat init ializat.

3.0.6

Parametrii referint a

Un parametru declarat cu modicatorul ref este un parametru referint a. Un parametru referint a nu creaz a o nou a locat ie de memorare. Parametrul referint a indic a aceea si locat ie ca variabila prin care s-a transmis argumentul n momentul apel arii membrului funct ie. La fel, valoarea unui parametru referint a este ntotdeauna aceea si cu a variabilei de baz a. Regulile utilizate pentru init ializarea parametrului de referint a sunt urm atoarele: O variabil a trebuie s a e init ializat a nainte de a transmis a ca parametru referint a ntr-un apel de membru funct ie; Intr-un membru funct ie, un parametru referint a este considerat init ializat. Intr-o metod a de instant a, accesor de instant a sau tip structur a, cuv antrul cheie this se comport a exact ca un parametru referint a c atre tipul structur a (??).

3.0.7

Parametrii de ie sire

Un parametru declarat cu modicatorul out este un parametru de ie sire. Un parametru de ie sire nu creaz a o nou a locat ie de memorare. Un parametru de ie sire indic a aceea si locat ie de memorare ca si o variabil a dat a ca argument n apelul membrului funct ie. Astfel, valoarea unui parametru de ie sire este mereu aceea si cu a variabilei de baz a. Regulile de init ializare ale parametrului de ie sire sunt urm atoarele: O variabil a nu trebuie s a e init ializat a nainte de a transmis a ca parametru de ie sire n apelul unei funct ii membru; In momentul apelului membrului funct ie ecare variabil a transmis a ca parametru de ie sire este considerat a init ializat a n momentul apelului; In membrul funct ie un parametru de ie sire este considerat init ializat; Fiecare parametru de ie sire trebuie s a e atribuit nainte ca membrul funct ie s a- si ncheie execut ia. Intr-un constructor de instant a al unui tip structur a, cuv antul cheie this se comport a exact ca un parametru de ie sire al tipului structur a.

3.0.8

Variabile locale

O variabil a local a este declarat a cu ajutorul unei declarat ii de variabil a local a care poate s a apar a ntr-un bloc sau o structur a de tip for, switch sau using.

86

CAPITOLUL 3. VARIABILE

Durata de viat a a unei variabile locale este port iunea de program n a c arei execut ie este garantata a stocarea acesteia. Durata de viat a se extinde asupra blocului sau structurilor de tip for, switch sau using p an a c and acestea se ncheie (indiferent de metoda de terminare). Intrarea ntr-un bloc imbricat sau apelul unei metode suspend a, dar nu ncheie durata de viat a a variabilei locale si a blocului cont in ator. Dac a blocul p arinte al variabilei locale este obt inut recursiv, o nou a instant a a acesteia este creat a de ecare dat a si init ializarea variabilei locale este executat a la ecare apel recursiv. O variabil a local a nu este init ializat a automat si de asemenea nu are valoare default. Pentru vericarea init ializ arii variabila local a este considerat a neatribuit a. O declarat ie de variabil a local a poate include o init ializare de variabil a local a. In acest caz variabila este considerat a atribuit a n tot domeniul ei de existent a, cu exceptia expresiilor prev azute n declararea variabilelor locale. Durata de viat a a variabilelor locale depinde de implementare. De exemplu, un compilator poate determina static c a o variabil a local a a unui bloc este folosit a ntr-o mic a port iune a acesteia. Utiliz and rezultatele acestei analize, compilatorul poate genera cod astfel nc at variabila local a s a aib a o durat a de viat a mai mic a dec at a blocului cont in ator. Zona de memorare referit a printr-o variabil a local a de tip referint a este independent a de durata de viat a a acelei variabile locale de tip referint a. O variabil a local a este declarat a si de o instruct iune foreach sau o clauz a catch dintr-un bloc try. Pentru foreach variabila de iterat ie este o variabil a local a. Pentru clauza catch variabila except ie este o variabil a local a. Cele dou a variabile locale sunt considerate init ializate peste tot domeniul lor de denit ie.

3.1

Valori implicite

Categoriile de variabile init ializate automat cu valorile lor implicite sunt: variabilele statice variabilele de instant a ale instant elor de clas a elementele de matrice Valorile implicite ale variabilelor depind de tipul acestora si sunt determinate dup a cum urmeaz a: pentru o variabil a de tip valoare, valoarea implicit a este aceea si cu valoarea calculat a de constructorul implicit al tipului valoare; pentru o variabil a de tip referint a, valoarea implicit a este null; init ializarea cu valori implicite este realizat a de managerul de memorie sau colectorul de gunoi care init ializeaz a tot i bit ii cu 0 nainte de alocarea propriu-zis a. Din aceast a cauz a referint a null are tot i bit ii 0.

3.2

Variabile cert atribuite

Intr-o propozit ie dat a n codul de execut ie al unui membru funct ie o variabil a este atribuit a dac a compilatorul poate dovedi pentru o analiz a particular a de

3.2. VARIABILE CERT ATRIBUITE

87

ux de instruct iuni (??) c a variabila a fost init ializat a sau a fost executat a o instruct iune de atribuire asupra acesteia. Regulile de atribuire sunt: prin atribuirea init ial a a variabilelor (??); dac a pe toate c aile prin care se poate ajunge ntr-o pozit ie din cod se execut a cel put in o atribuire asupra unei variabile neinit ializate (??); ntr-o atribuire simpl a (??) variabila apare n st anga operandului; ntr-un apel de expresie (??) sau expresie de creare a unui obiect (??) variabila este transmis a ca un parametru de ie sire; o declarat ie de variabil a local a (??) care include init ializarea variabilei. Specicat iile formale din care rezult a regulile de mai sus sunt descrise n 12.3.1, 12.3.2, 12.3.3. Starea de atribut a variabilelor de instant a ale unei variabile de tip structur a sunt urm arite individual si colectiv. Suplimentar, la regulile de mai sus li se aplic a regulile variabilelor de tip structur a si variabilele lor de instant a: o variabil a de instant a este considerat a atribuit a dac a variabila de tip structur a care o cont ine este considerat a atribuit a; o variabil a de tip structur a este considerat a atribuit a dac a ecare variabil a de instant a din ceasta este atribuit a. Starea de atribuit este o cerint a a urm atoarelor contexte: o variabil a trebuie s a e atribuit a n ecare pozit ie n care este necesar a valoarea ei (aceasta asigur a faptul c a nu apar valori nedenite). Aparit ia unei variabile ntr-o expresie este considerat a punctul de obt inere a valorii, cu except ia: variabila este operatorul st ang al unei atribuire simple variabila este transmis a ca parametru de ie sire variabila este de tip structur a si apare n operatorul st ang al unui membru de accesare o variabil a trebuie s a e atribuit a n ecare locat ie n care este utilizat a ca parametru referint a. Aceasta asigur a c a membrul funct iei apelat poate considera tot i parametrii referint a init ializat i; tot i parametrii de ie sire ai unui membru funct ie trebuie s a e atribuit i n ecare pozit ie n care se poate termina execut ia funct iei (prin instruct iunea return sau atingerea sf ar sitului corpului funct iei). Aceasta asigur a c a membrul funct ie nu va returna valori nedenite n parametrii de ie sire si permite compilatorului s a considere c a apelul unui membru funct ie care prime ste o variabil a ca parametru de ie sire este echivalent cu o atribuire pentru acea variabil a; variabila this ntr-un constructor de instant a al unui tip structur a trebuie s a e atribuit a n ecare locat ie unde se poate termina constructorul de instant a

88

CAPITOLUL 3. VARIABILE

3.2.1

Variabile init ializate

Urm atoarele categorii de variabile sunt clasicate ca init ializate: variabilele statice variabilele de instant a ale instant elor de clase variabilele de instant a ale variabilelor structur a init ializate elementele de matrice parametrii valoare parametrii referint a variabilele declarate n clauza catch si n construct iile foreach sau using.

3.2.2

Variabile neinit ializate

Urm atoarele categorii de variabile fac parte din catgeoria variabilelor neinit ializate: variabilele de instant a ale variabilelor structur a neinit ializate; parametrii de ie sire, inclusiv variabile ale instant elor de structur a f ar a constructor de init ializare. variabile locale cu except ia celor declarate n clauze catch, blocuri foreach sau using.

3.2.3

Reguli pentru determinarea st arii de atribuire

Pentru a determina dac a o variabil a este atribuit a sau nu compilatorul utilizeaz a mecanismul descris n aceast a sect iune. El analizeaz a corpul ec arei membru funct ie care cont ine una sau mai multe variabile neinit ializate. Pentru ecare variabil a v neatribuit a, compilatorul determin a starea de atribuire n ecare punct al membrului funct ie: la nceputul ec arei structuri de program; la sf ar situl (??) ec arei structuri de program ; pe ecare transfer al controlului c atre o alt a structur a de program sau la sf ar situl unei structuri de program; la nceputul ec arei expresii; la sf ar situl ec arei expresii. Starea de atribuit a lui v poate : atribuit. Aceasta arat a c a pentru toate c aile posibile de parcurs p an a n punctul curent v are o valoare atribuit a. incert atribuit. Starea unei variabile la sf ar situl unei expresii booleene nu este cu certitudine atribuit a. Aceast a situat ie apare n urm atoarele cazuri:

3.2. VARIABILE CERT ATRIBUITE

89

atribuit dup a evaluarea structurii de program corespunz atoare c aii true. Aceast a stare corespunde situat iei n care v este atribuit dac a expresia evaluat a este adev arat a, dar nu este atribuit a cu certitudine dac a expresia este fals a. atribuit dup a evaluarea structurii de program corespunz atoare c aii false. Aceast a stare corespunde situat iei n care v este atribuit dac a expresia evaluat a este fals a, dar nu este atribuit a cu certitudine dac a expresia este adev arat a. Regulile de mai jos guverneaz a modul n care este evaluat a starea unei variabile n ecare punct din program. Reguli generale pentru instruct iuni v este incert atribuit a la nceputul ec arui membru funct ie. v este atribuit a la nceputul ec arei structuri d eprogram care nu va executat a niciodat a1 . Starea de atribuit a variabilei v la nceputul ec arei structuri de program este determinat a prin vericarea st arii de atribuire a lui v pentru toate salturile de ux de instruct iuni c atre nceputul structurii. Dac a ( si numai dac a) v este atribuit a pe toate c aile de transfer atunci v este atribuit a la nceputul structurii. Mult imea transferurilor de ux este determinat a n acela si mod n care sunt determinate si structurile de program ce pot executate n timpul execut iei programului(??). Starea de atribuit a unei variabile v la sf ar situl unui bloc de program, a unei structuri de program checked, unchecked, if, while, do, for, foreach, lock, using sau switch este determinat a prin vericarea atribuirii variabilei v pe toate c aile de execut ie c atre punctul de sf ar sit. Dac a v este atribuit a pe toate c aile atunci v este atribuit a cu certitudine la sf ar situl blocului sau structurii. Altfel, v este incert atribuit a. Mult imea transferurilor de ux este determinat a n acela si mod n care sunt determinate si structurile de program ce pot executate n timpul execut iei programului(??). Blocuri de instruct iuni, instruct iuni checked si unchecked Starea de atribuit a unei variabile v n timpul transferului de ux c atre prima instruct iune dintr-o list a de instruct iuni (sau sf ar situl listei dac a blocul este gol) este aceea si cu cea a lui v de dinaintea blocului, structurii checked sau unchecked. Instruct iuni de tip expresie Pentru o instruct iune instr format a dintr-o expresie expr: variabila v are aceea si stare la nceputul expresiei expr cu cea de la nceputul instruct iunii instr.
1 unreachable

code

90

CAPITOLUL 3. VARIABILE dac a variabila v este este atribuit a la sf ar situl expresiei expr atunci este atribuit a si la sf ar situl instruct iunii instr. In caz contrar variabila v nu este cert atribuit a la sf ar situl instruct iunii instr.

Declarat ii Dac a instr este o declarat ie f ar a init ializ ari atunci v are aceea si stare la sf ar situl instruct iunii cu cea de la nceputul instruct iunii. Dac a instr este o declarat ie cu init ializ ari atunci starea variabilei v este determinat a dac a ecare variabil a din instruct iunea instr este init ializat a. Instruct iunea if Pentru o instruct iune if notat a instr: if (expr) then-instr else else-instr v are aceea si stare la nceputul expresiei expr cu cea de la nceputul instruct iunii instr. Dac a v este atribuit a n evaluarea expresiei expr atunci ea este atribuit a la sf ar situl evalu arii blocurilor then-instr si else-instr si sau la sf ar situl instruct iunii instr dac a nu a existat clauza else. Dac a v este atribuit a dup a evaluarea expresiei la adev arat atunci ea este atribuit a dac a se execut a blocul then-instr si este incert atribuit a c and se execut a blocul else-instr sau la sf ar situl instruct iunii instr dac a nu a existat clauza else. Dac a v este atribuit a dup a evaluarea expresiei la fals atunci ea este atribuit a dac a se execut a blocul else-instr si este incert atribuit a c and se execut a blocul then-instr. Variabila este sigur atribuit a la sf ar situl instruct iunii instr dac a si numai dac a este cert atribuit a la sf ar situl blocului theninstr. In celelalte cazuri v este considerat a incert atribuit a la sf ar situl blocului then-instr si la sf ar situl blocului else-instr sau la sf ar situl instruct iunii instr dac a nu a existat clauza else. Instruct iunea switch Intr-o instruct iune instr de tip switch controlat a de o expresie expr: starea de cert atribuit a variabilei v la nceputul expresiei expr este identic a cu ce de la nceputul instruct iunii instr starea de cert atribuit a variabilei v la sf ar situl evalu arii expresiei expr se propag a n timpul transferului de control de ux c atre structurile de cod din lista de variante a instruct iunii instr accesibile n timpul rul arii.

3.2. VARIABILE CERT ATRIBUITE Instruct iunea while Pentru o instruct iune while notat a instr si controlat a de o expresie expr: while (expr) while-body

91

v are aceea si stare la nceputul expresiei expr cu cea de la nceputul instruct iunii instr. Dac a v este atribuit a n evaluarea expresiei expr atunci ea este atribuit a la sf ar situl evalu arii blocurilor while-body si la sf ar situl instruct iunii instr. Dac a v este atribuit a dup a evaluarea expresiei la adev arat atunci ea este atribuit a c and controlul uxului este cedat blocului while-body si la sf ar situl instruct iunii instr. Dac a v este atribuit a dup a evaluarea expresiei la fals atunci ea este atribuit a c and uxul de control atinge sf ar situl instruct iunii instr. Instruct iunea do Pentru o instruct iune do notat a instr si controlat a de o expresie expr: do do-body while (expr) v are aceea si stare la nceputul instruct iunii instr cu cea de la nceputul blocului do-body. v are aceea si stare la sf ar situl blocului do-body cu cea de la nceputul evalu arii expresiei expr. v are aceea si stare la sf ar situl expresiei expr cu cea de la sf ar situl instruct iunii instr. Dac a v este atribuit a dup a evaluarea expresiei la fals atunci ea este atribuit a c and uxul de control atinge sf ar situl instruct iunii instr. Instruct iunea for Testarea st arii de atribuit pentru o instruct iune de tip for numit a instr de forma: bf for (for-initializer; for-condition; for-iterator) embedded-statement se face ca pentru forma echivalent a:
{ for i n i t i a l i z e r ; while ( for c o n d i t i o n ) { embeddeds t a t e m e n t ; for i t e r a t o r ; } }

Dac a este omis a condit ia for-condition atunci evaluarea st arii de atribuire se face prin nlocuirea condit iei cu valoarea true n echivalent a de mai sus.

92 Instruct iunile break, continue si goto

CAPITOLUL 3. VARIABILE

Atribuirea variabilei v nu este modicat a de schimbarea controlului de ux datorit a intruct iunilor break, continue, sau goto. Instruct iunea throw Pentru o instruct iune try numit a instr controlat a de o expresie expr de forma; throw expr; starea atribuirii variabilei v la nceputul expresiei expr este aceea si cu starea de la nceputul instruct iunii instr. Instruct iunea return Pentru o instruct iune return numit a instr care cont ine expresia expr de forma; return expr; starea de atribuit a variabilei v la nceputul expresiei expr este aceea si cu cea de la necputul expresiei instr. dac a v este un parametru de ie sire atunci trebuie s a e atribuit: la sf ar situl expresiei expr sau la sf ar situl blocului nnaly al structurii try-catch sau trycatch-nally care ncadreaz a instruct iunea return. Pentru o instruct iune return numit a instr de forma; return ; dac a v este un parametru de ie sire atunci trebuie s a e atribuit: la sf ar situl instruct iunii instr sau la sf ar situl blocului nnaly al structurii try-catch sau trycatch-nally care ncadreaz a instruct iunea return. Specicarea try-catch Pentru o instruct iune try-catch numit a instr de forma;
try tryb l o c k catch ( . . . ) catchb l o c k 1 ... catch ( . . . ) catchb l o c k n

starea de atribuit a variabile v la nceputul blocului try-block este aceea si cu cea de la nceputul instruct iunii instr. starea de atribuit a variabile v la nceputul blocului catch-block-i (pentru ecare i) este aceea si cu cea de la nceputul instruct iunii instr starea de atribuit a variabile v la sf ar situl instruct iunii instr este atribuit dac a ( si numai dac a) v este atribuit at at la sf ar situl blocului try-block c at si al ec arui bloc catch-block-i (pentru ecare i de la 1 la n)).

3.2. VARIABILE CERT ATRIBUITE Specicarea try-finally Pentru o instruct iune try-nally numit a instr de forma; try try-block nally finally-block

93

starea de atribuit a variabile v la nceputul blocului try-block este aceea si cu cea de la nceputul instruct iunii instr. starea de atribuit a variabile v la nceputul blocului nally-block este aceea si cu cea de la nceputul instruct iunii instr starea de atribuit a variabile v la sf ar situl instruct iunii instr este atribuit dac a ( si numai dac a) v este atribuit a la sf ar situl blocului try-block v este atribuit a la sf ar situl blocului nally-block Dac a transferul uxului de control (cum ar o instruct iune goto) este f acut la nceputul blocului try-block n afara blocului try-block atunci variabila v este considerat a atribuit a dac a v este atribuit a la sf ar situl blocului nallyblock. Specicarea try-catch-finally Pentru o instruct iune try-catch-nally numit a instr de forma;
try tryb l o c k catch ( . . . ) ... catch ( . . . ) finally catchb l o c k 1 catchb l o c k n f i n a l l y b l o c k

vericarea st arii de atribuire este realizat a ca si c and o instruct iune try-nally include o instruct iune try-catch:
try { try tryb l o c k catch ( . . . ) catchb l o c k 1 ... catch ( . . . ) catchb l o c k n } f i n a l l y f i n a l l y b l o c k

In exemplul de mai jos este demonstrat cum diferite blocuri try inuent eaz a starea de atribuire:
class A { s t a t i c void F ( ) { int i , j ; try { goto LABEL; // i s i j nu s u n t a t r i b u i t e

94
i = 1; } catch atribuite { i = 3; } finally atribuite { j = 5; } LABEL : ; } }

CAPITOLUL 3. VARIABILE
// i e s t e s i g u r a t r i b u i t // n i c i i s i n i c i j nu s u n t s i g u r

// i e s t e s i g u r a t r i b u i t // n i c i i s i n i c i j nu s u n t s i g u r

// j e s t e s i g u r a t r i b u i t // i s i j sunt sigur a t r i b u i t e // j e s t e s i g u r a t r i b u i t

Instruct iunea foreach Pentru o instruct iune foreach numit a instr de forma; foreach ( type identifier in expr ) embedded-statement starea de atribuit a variabile v la nceputul expresiei expr este aceea si cu cea de la nceputul instruct iunii instr. starea de atribuit a variabile v c and uxul de instruct iuni este transferat blocului embedded-statement sau la sf ar situl instruct iunii instr este aceea si cu cea de la sf ar situl expresiei expr. Instruct iunea using Pentru o instruct iune using numit a instr de forma; using ( resource-acquisition ) embedded-statement starea de atribuit a variabile v la nceputul blocului resource-acquisition este aceea si cu cea de la nceputul instruct iunii instr. starea de atribuit a variabile v c and uxul de instruct iuni este transferat blocului embedded-statement este aceea si cu cea de la sf ar situl expresiei resource-acquisition. Instruct iunea lock Pentru o instruct iune lock numit a instr de forma; lock ( expr ) embedded-statement starea de atribuit a variabile v la nceputul blocului expr este aceea si cu cea de la nceputul instruct iunii instr. starea de atribuit a variabile v c and uxul de instruct iuni este transferat blocului embedded-statement este aceea si cu cea de la sf ar situl expresiei expr.

3.2. VARIABILE CERT ATRIBUITE Reguli generale pentru expresii simple

95

Regulile prezentate n continuare se aplic a urm atoarelor tipuri de expresii: literale ??, nume simple ??, expresii de accesare a membrilor ??, expresii de accesare cu baz a neindexat a ?? si expresiilor pentru determinarea tipurilor ??. starea de atribuit a variabilei v la sf ar situl unei astfel de expresii este aceea si cu cea de la de la nceputul expresiei. Reguli generale pentru expresii cu expresii ncorporeaz a Regulile prezentate n continuare se aplic a urm atoarelor tipuri de expresii: expresii cu paranteze ??, expresii de accesare ??, expresii de accesare cu index ??, expresii de incrementare si decrementare ??, expresii de conversie ??, expresii cu operatori unari +, -, ~, *, expresii cu operatori binari +, -, *, /, %, <<, >>, <, <=, >, >=, ==, !=, is, as, &, |, ^ ??, expresii de atribuire compuse ??, expresii checked si unchecked ??, expresii de creare a delegat ilor si a matricelor ??. Fiecare dintre aceste expresii are una sau mai multe subexpresii ce sunt evaluate necondit ionat ntr-o anumit a ordine. De exemplu, operatorul binar % evalueaz a prima dat a partea st ang a a operatorului si apoi partea dreapt a. Un operator de indexare evalueaz a expresia indexat a si apoi evalueaz a ecare index al expresiilor n ordine, de la st anga la dreapta. De exemplu, n expresia expr subexpresiile expr1 , expr2 , ..., exprn cont inute vor evaluate exact n aceast a ordine: starea de atribuit a variabilei v la nceputul blocului expr1 este aceea si cu cea de la nceputul expresiei expr. starea de atribuit a variabilei v la nceputul blocului expri (i mai mare ca unu) este aceea si cu cea de la nceputul expresiei expri1 starea de atribuit a variabilei v la sf ar situl expresiei expr este aceea si cu cea de la sf ar situl expresiei exprn . Apelul expresiilor si expresii pentru crearea obiectelor Apelul unei expresii expr de forma: primary-expression ( arg1, arg2, ..., argn ) sau a unei expresii expr pentru crearea unui obiect de forma: new type ( arg1, arg2, ... , argn ) n apelul unei expresii starea de atribuit a variabilei v, nainte de primaryexpresion este aceea si cu cea de dinaintea expresiei expr. n apelul unei expresii starea de atribuit a variabilei v, nainte de arg1 este aceea si cu cea de de la nalul expresiei primary-expresion expr. n apelul unei expresii de creare a unui obiect starea de atribuit a variabilei v, nainte de arg1 este aceea si cu starea de dinaintea evalu arii expresiei expr. pentru ecare argument argi, starea de atribuit a variabilei v dup a argi este determinat a de regulile obi snuite pentru expresii f ac and abstract ie de modicatorii ref si out.

96

CAPITOLUL 3. VARIABILE pentru ecare argument argi cu i mai mare ca unu, starea de atribuit a variabilei v nainate argi este aceea si cu starea de dup a evaluarea argi-1. dac a variabila v este transmis a cu modicatorul out (un argument de forma out v) n ecare dintre argumente atunci starea lui out v este atribuit. Altfel, starea lui out v dup a expr este aceea si cu starea lui v dup a argn.

Expresii simple de atribuire Pentru o expresie expr de forma w = expr-rhs: starea de atribuit a variabile v naintea lui w este aceea si cu starea dinaintea expresiei expr. starea de atribuit a variabile v naintea expresiei expr-rhs este aceea si cu starea de dup aw dac a w este accea si cu variabila v atunci starea de atribuit a variabile v dup a expr este atribuit. In celelalte cazuri starea lui v dup a expr este aceea si cu cea de dup a expr-rhs. In exemplul de mai jos
class A { s t a t i c void F( i n t [ ] a r r ) { int x ; a r r [ x = 1 ] = x ; // ok } }

starea de atribuit a variabilei x obt inut a dup a evaluarea expresiei arr[x = 1] din partea st ang a a celei de a doua atribuiri. Expresii && Pentru o expresie expr de forma expr-first && expr-second: starea de atribuit a variabilei v naintea expresiei expr-rst este cea de dinaintea expresiei expr. starea de atribuit a variabilei v naintea expresiei expr-second este de atribuit dac a starea lui v dup a expr-rst este de atribuit sau dac a v este atribuit a pe valoarea true a expresiei expr-rst. In caz contrar este incert atribuit a. starea de atribuit a variabilei v dup a expr este determinat a de : dac a starea variabile v dup a expr-rst este atribuit atrunbci starea lui v dup a expr este atribuit.

3.2. VARIABILE CERT ATRIBUITE

97

altfel, dac a starea variabilei v dup a expr-second este atribuit si dup a expr-rst este atribuit dac a expresia are valoarea fals atunci starea variabilei v dup a expr este atribuit. altfel, dac a starea variabilei v dup a expr-second este atribuit si dup a expr-rst este atribuit dac a expresia are valoarea true atunci starea variabilei v este adev arat dac a expr se n urma evalu arii este adev arat a. altfel, dac a starea variabilei v dup a expr-rst atribuit a dac a expresia este evaluat a ca adev arat a starea variabilei v dup a expr-second atribuit a dac a expresia este evaluat a ca fals a atunci starea lui v dup a expr este atribuit a dac a expresia este evaluat a ca fals a. altfel starea variabilei v este incert atribuit a. In exemplul de mai jos
class A { s t a t i c void F( i n t x , i n t y ) { int i ; i f ( x >= 0 && ( i = y ) >= 0 ) { // i d e f i n i t e l y a s s i g n e d } else { // i n o t d e f i n i t e l y a s s i g n e d } // i n o t d e f i n i t e l y a s s i g n e d } }

variabila i este considerat a atribuit a numai n unul din blocurile instruct iunii if. In metoda F variabila i este atribuit a n primul deoarece ntotdeauna executat a instruct iunea i = y. Variabila i nu este cert atribuit a n al doilea bloc deoarece dac a testul x >= 0 este fals nu mai este evaluat al doilea test si, implicit, variabila i nu este atribuit a. Expresii || Pentru o expresie expr de forma expr-first || expr-second: starea de atribuit a variabilei v naintea expresiei expr-rst este cea de dinaintea expresiei expr. starea de atribuit a variabilei v naintea expresiei expr-second este de atribuit dac a starea lui v dup a expr-rst este de atribuit sau dac a v este atribuit a pe valoarea false a expresiei expr-rst. In caz contrar este incert atribuit a. starea de atribuit a variabilei v dup a expr este determinat a de :

98

CAPITOLUL 3. VARIABILE dac a starea variabile v dup a expr-rst este atribuit atunci starea lui v dup a expr este atribuit. altfel, dac a starea variabilei v dup a expr-second este atribuit si dup a expr-rst este atribuit dac a expresia are valoarea true atunci starea variabilei v dup a expr este atribuit. altfel, dac a starea variabilei v dup a expr-second este atribuit si dup a expr-rst este atribuit dac a expresia are valoarea false atunci starea variabilei v este adev arat dac a expr se n urma evalu arii este adev arat a. altfel, dac a starea variabilei v dup a expr-rst atribuit a dac a expresia este evaluat a ca fals a starea variabilei v dup a expr-second atribuit a dac a expresia este evaluat a ca adev arat a atunci starea lui v dup a expr este atribuit a dac a expresia este evaluat a ca adev arat a. altfel starea variabilei v este incert atribuit a. In codul de mai jos:

class A { s t a t i c void G( i n t x , i n t y ) { int i ; i f ( x >= 0 | | ( i = y ) >= 0 ) { // i nu e s t e s i g u r a t r i b u i t } else { // i e s t e s i g u r a t r i b u i t } // i nu e s t e s i g u r a t r i b u i t } }

variabila i este considerat a atribuit a numai n unul din blocurile instruct iunii if. In metoda G variabila i este atribuit a n primul deoarece ntotdeauna executat a instruct iunea i = y. Variabila i nu este cert atribuit a n al doilea bloc deoarece dac a testul x >= 0 este true nu mai este evaluat al doilea test si, implicit, variabila i nu este atribuit a. Expresii ! Pentru o expresie expr de forma ! expr-operand: starea de atribuit a variabilei v nainte de The denite assignment state of v before expr-operand is the same as the denite assignment state of v before expr. starea de atribuire a variabilei v este determinat a de:

3.2. VARIABILE CERT ATRIBUITE

99

dac a starea de atribuire a variabile v dup a evaluarea expresiie exproperand este atribuit atunci starea dup a evaluarea expresiei expr este atribuit. dac a starea de atribuire a variabile v nu este cert atribuit a atunci starea dup a evaluarea expresiei expr nu este cert atribuit. dac a starea de atribuire a variabile v este atribuit a dac a expr-operand este evaluat a la true starea dup a evaluarea expresiei expr este cert atribuit a dac a expr este evaluat a la true. dac a starea de atribuire a variabile v este atribuit a dac a expr-operand este evaluat a la false starea dup a evaluarea expresiei expr este cert atribuit a dac a expr este evaluat a la false. Expresii ?: Pentru o expresie de forma expr-cond?expr-true:expr-false: starea de atribuire a variabile v nainte de expr-cond este aceea si cu starea de dinaintea evalu arii expresiei expr. starea de atribuire a variabile v nainte evalu arii expresiei expr-true este atribuit a dac a si numai dac a starea lui v dup a evaluarea expresiei exprcond este atribuit a dac a expresia este evaluat a la true. starea de atribuire a variabile v nainte evalu arii expresiei expr-false este atribuit a dac a si numai dac a starea lui v dup a evaluarea expresiei exprcond este atribuit a dac a expresia este evaluat a la false. Expresii de metode anonime Starea de atribut a unui parametru dintr-o metod a anonim a este aceea si cu a unui parametru dintr-o metod a clasic a. Parametrii referint a si valoare sunt init ial atribuit i, iar parametrii de ie sire sunt init ial neatribuit i. Mai mult, parametrii de ie sire trebuie s a e atribuit i nainte de terminarea metodei. Starea de atribuit a unei variabile externe c and controlul uxului este transferat c atre blocul unei metode anonime este aceea si cu cea de dinaintea blocului. Aceast a stare este mo stenit a din contextul n care se a a blocul. Starea de atribuire evolueaz a ca si ntr-un bloc normal. Starea variabilei dup a acest bloc este aceea si cu cea de dinaintea blocului. In exemplul:
delegate bool F i l t e r ( i n t i ) ; void F ( ) { i n t max ; // Error , max i s n o t d e f i n i t e l y a s s i g n e d F i l t e r f = delegate ( i n t n ) { return n < max ; } ; max = 5 ; DoWork( f ) ; }

100

CAPITOLUL 3. VARIABILE

genereaz a o eroare de compilare at ata timp c at variabila max este incert atribuit a n pozit ia n care este declarat a metoda anonim a. In exemplul:
delegate void D( ) ; void F ( ) { int n ; D d = delegate { n = 1 ; } ; d() ; // Error , n i s n o t d e f i n i t e l y a s s i g n e d C o n s o l e . WriteLine ( n ) ; }

este generat a o eroare de compilare deoarece atribuirea variabilei n n declarat ia metodei anonime nu are efect n afara declarat iei. Instruct iunea yield Pentru o instruct iune de tip yield numit a instr de forma: yield return expr ; o variabil a v are la nceputul instruct iunii instr aceea si stare de atribuire ca cea de la nceputul expresiei expr. dac a o variabil a v este atribuit a la sf ar situl expresiei expr ea este atribuit a la sf ar situl instruct iunii instr. altfel, variabila are atribuire incert a la sf ar situl instruct iunii instr. Instruct iunea ?? Pentru o expresie expr de forma: expr-first ?? expr-second starea de atribuire a variabilei v nainte de evaluarea expresiei expr-rst este ce de dinaintea expresiei expr. starea de atribuire a variabilei v nainte de evaluarea expresiei exprsecond este cea de dup a evaluarea expresiei expr-rst. starea de atribuire a variabilei v dup a de evaluarea expresiei expr este cea de dup a evaluarea expresiei expr-rst.

3.3

Variabile referint a

O variabil a referint a este o expresie clasicat a ca variabil a. Ea indic a o locat ie de memorare ce poate accesat a at at pentru citirea c at si pentru modicarea valorii cont inute. variabil a referint a:: expresie In C si C++, o variabil a referint a este cunoscxut a ca valoarea st ang a.

3.4. ATOMICITATEA VARIABILELOR REFERINT A

101

3.4

Atomicitatea variabilelor referint a

Citirea si modicarea valorilor apart in and urm atoarelor tipuri este atomic a: bool, char, byte, sbyte, short, ushort, uint, int, oat si tipurile referint a. Citirea si modifcarea valorilor tipurilor enumerare care au ca tip de baz a unul din tipurile de mai sus este atomic a. Citirea si modicarea valorilor apart in and urm atoarelor tipuri: long, ulong, double si decimal nu este neap arat atomic a. In afara funct iilor din libr aria standard, nu exist a nici o grant ie c a citirea sau modicarea este atomic a (cum ar incrementarea sau decrementarea).

102

CAPITOLUL 3. VARIABILE

Capitolul 4

Clase
4.1 Declararea claselor
class-declaration: attributesopt class-modiersopt partialopt class identier type-parameter-listopt class-baseopt type-parameter-constraints-clausesopt class-body ;opt

4.1.1

Modicatori pentru clase

class-modiers: class-modier class-modiers class-modier class-modier: new public protected internal private abstract sealed static

Clase abstracte
abstract c l a s s A { public abstract void F ( ) ; } abstract c l a s s B : A { public void G( ) {} } class C: B {

103

104
public override void F ( ) { // a c t u a l i m p l e m e n t a t i o n o f F } }

CAPITOLUL 4. CLASE

Clase sigilate Clase statice


using System . D i a g n o s t i c s ; public s t a t i c c l a s s P r e c o n d i t i o n { public sealed c l a s s E x c e p t i o n : System . A p p l i c a t i o n E x c e p t i o n { public E x c e p t i o n ( s t r i n g message ) : base ( message ) {} } [ C o n d i t i o n a l ( " CHECK_PRECONDITIONS " ) ] public s t a t i c void Required ( bool c o n d i t i o n , s t r i n g description ) { i f ( ! condition ) { throw new E x c e p t i o n ( d e s c r i p t i o n ) ; } } }

4.1.2

Specicarea claselor de baz a

class-base: : class-type : interface-type-list : class-type , interface-type-list interface-type-list: interface-type interface-type-list , interface-type

Clase de baz a
c l a s s A {} c l a s s B : A {} c l a s s Extend<V> : V {} // Error , t y p e parameter used as b a s e class c l a s s C<V> : Base<V[] > {} // Ok c l a s s A: B {} c l a s s B : C {} c l a s s C : A {}

4.1. DECLARAREA CLASELOR

105

c l a s s A: B . C {} class B: A { public c l a s s C {} } class A { c l a s s B : A {} } sealed c l a s s A {} c l a s s B : A {} // Error , cannot d e r i v e from a s e a l e d c l a s s

Implementarea interfet elor


p a r t i a l c l a s s C : IA , IB { . . . } p a r t i a l c l a s s C : IC { . . . } p a r t i a l c l a s s C : IA , IB { . . . } p a r t i a l class X { i n t IComparable . CompareTo ( object o ) { . . . } } p a r t i a l c l a s s X: IComparable { ... } c l a s s C<U, V> {} i n t e r f a c e I1 <V> {} c l a s s D: C<string , int > , I1 <string > {} c l a s s E<T> : C<int , T> , I1 <T> {}

4.1.3

Corpul claselor

class-body: { class-member-declarationso pt }

4.1.4

Declarat ii part iale

public p a r t i a l c l a s s Customer { private i n t i d ; private s t r i n g name ; private s t r i n g a d d r e s s ; private L i s t <Order > o r d e r s ;

106
public Customer ( ) { ... }

CAPITOLUL 4. CLASE

} public p a r t i a l c l a s s Customer { public void SubmitOrder ( Order o r d e r S u b m i t t e d ) { o r d e r s . Add( o r d e r S u b m i t t e d ) ; } public bool HasOutstandingOrders ( ) { return o r d e r s . Count > 0 ; } } public c l a s s Customer { private i n t i d ; private s t r i n g name ; private s t r i n g a d d r e s s ; private L i s t <Order > o r d e r s ; public Customer ( ) { ... } public void SubmitOrder ( Order o r d e r S u b m i t t e d ) { o r d e r s . Add( o r d e r S u b m i t t e d ) ; } public bool HasOutstandingOrders ( ) { return o r d e r s . Count > 0 ; } }

4.2

Membrii claselor
class-member-declarations: class-member-declaration class-member-declarations class-member-declaration class-member-declaration: constant-declaration eld-declaration method-declaration property-declaration event-declaration indexer-declaration operator-declaration constructor-declaration nalizer-declaration

4.2. MEMBRII CLASELOR static-constructor-declaration type-declaration

107

p a r t i a l class A { int x ; once p a r t i a l class Inner { int y ; } } p a r t i a l class A { int x ; once p a r t i a l class Inner { int z ; } }

// Error , cannot d e c l a r e x more than // Ok , I n n e r i s a p a r t i a l t y p e

// Error , cannot d e c l a r e x more than // Ok , I n n e r i s a p a r t i a l t y p e

4.2.1

Mo stenirea

c l a s s A<S> { public S f i e l d ; } c l a s s B<T> : A<T[] > { // i n h e r i t e d : p u b l i c T [ ] f i e l d ; public A<T> Meth (T t ) { . . . } } c l a s s C : B<string > { // i n h e r i t e d : p u b l i c s t r i n g [ ] f i e l d ; // i n h e r i t e d : p u b l i c A< s t r i n g > Meth ( s t r i n g t ) ; }

4.2.2 4.2.3 4.2.4 4.2.5

Modicatorul new Modicatoir de acces Tipuri constituente Membrii statici si membrii de instant a

c l a s s Test { int x ;

108

CAPITOLUL 4. CLASE
static int y ; void F ( ) { x = 1 ; // Ok , same as t h i s . x = 1 y = 1 ; // Ok , same as Test . y = 1 } s t a t i c void G( ) { x = 1 ; // Error , cannot a c c e s s t h i s . x y = 1 ; // Ok , same as Test . y = 1 } s t a t i c void Main ( ) { Test t = new Test ( ) ; t . x = 1; // Ok t . y = 1; // Error , cannot a c c e s s s t a t i c member through instance Test . x = 1 ; // Error , cannot a c c e s s i n s t a n c e member through type Test . y = 1 ; // Ok }

4.2.6

Tipuri imbricate

using System ; class A { class B { s t a t i c void F ( ) { C o n s o l e . WriteLine ( "A.B.F" ) ; } } }

Membrii cu nume complet calicat Declarat ii de accesibilitate


public c l a s s L i s t { // P r i v a t e d a t a s t r u c t u r e private c l a s s Node { public object Data ; public Node Next ; public Node ( object data , Node next ) { t h i s . Data = data ; t h i s . Next = next ;

4.2. MEMBRII CLASELOR


} } private Node f i r s t = null ; private Node l a s t = null ; // P u b l i c i n t e r f a c e public void AddToFront ( object o ) { . . . } public void AddToBack ( object o ) { . . . } public object RemoveFromFront ( ) { . . . } public object AddToFront ( ) { . . . } public i n t Count { g e t { . . . } } }

109

Ascunderea tipurilor imbricate


using System ; c l a s s Base { public s t a t i c void M( ) { C o n s o l e . WriteLine ( " Base .M" ) ; } } c l a s s D e r i v e d : Base { new public c l a s s M { public s t a t i c void F ( ) { C o n s o l e . WriteLine ( " Derived .M.F" ) ; } } } c l a s s Test { s t a t i c void Main ( ) { D e r i v e d .M. F ( ) ; } }

Accesorul this
using System ; class C { int i = 123; public void F ( ) { Nested n = new Nested ( t h i s ) ; n .G( ) ; }

110
public c l a s s Nested { C this c ; public Nested (C c ) { this c = c ; } public void G( ) { C o n s o l e . WriteLine ( t h i s c . i ) ; } } } c l a s s Test { s t a t i c void Main ( ) { C c = new C( ) ; c .F() ; } }

CAPITOLUL 4. CLASE

Accesarea membrilor privat i si protejat i ai tipurilor cont inute


using System ; class C { private s t a t i c void F ( ) { C o n s o l e . WriteLine ( "C.F" ) ; } public c l a s s Nested { public s t a t i c void G( ) { F() ; } } } c l a s s Test { s t a t i c void Main ( ) { C . Nested .G( ) ; } } using System ; c l a s s Base { protected void F ( ) {

4.2. MEMBRII CLASELOR


C o n s o l e . WriteLine ( " Base .F" ) ; } } c l a s s D e r i v e d : Base { public c l a s s Nested { public void G( ) { D e r i v e d d = new D e r i v e d ( ) ; d . F ( ) ; // ok } } } c l a s s Test { s t a t i c void Main ( ) { D e r i v e d . Nested n = new D e r i v e d . Nested ( ) ; n .G( ) ; } }

111

4.2.7

Nume de membrii rezervate

Nume de membrii rezervate pentru propriet a ti


T get P ( ) ; void s e t P (T v a l u e ) ; using System ; class A { public i n t P { g e t { return 1 2 3 ; } } } class B: A { new public i n t g e t P ( ) { return 4 5 6 ; } new public void s e t P ( i n t v a l u e ) { } } c l a s s Test { s t a t i c void Main ( ) { B b = new B( ) ;

112
A a = b; C o n s o l e . WriteLine ( a . P) ; C o n s o l e . WriteLine ( b . P) ; C o n s o l e . WriteLine ( b . g e t P ( ) ) ; } } 123 123 456

CAPITOLUL 4. CLASE

Nume de membrii rezervate pentru evenimente Nume de membrii rezervate pentru indexatori Nume de membrii rezervate pentru nalizatori

4.3

Constante
constant-declaration: attributesopt constant-modiersopt const type constant-declarators; constant-modiers: constant-modier constant-modiers constant-modier constant-modier: new public protected internal private constant-declarators: constant-declarator constant-declarators , constant-declarator constant-declarator: identier = constant-expression

class A { public const double X = 1 . 0 , Y = 2 . 0 , Z = 3 . 0 ; } class A { public const double X = 1 . 0 ; public const double Y = 2 . 0 ; public const double Z = 3 . 0 ; }

4.4. CAMPURI

113

class A { public const i n t X = B . Z + 1 ; public const i n t Y = 1 0 ; } class B { public const i n t Z = A.Y + 1 ; }

4.4

C ampuri
eld-declaration: attributesopt eld-modiersopt type variable-declarators ; eld-modiers: eld-modier eld-modiers eld-modier eld-modier: new public protected internal private static readonly volatile variable-declarators: variable-declarator variable-declarators , variable-declarator variable-declarator: identier identier = variable-initializer variable-initializer: expression array-initializer

class A { public s t a t i c i n t X = 1 , Y, Z = 1 0 0 ; } class A { public s t a t i c i n t X = 1 ; public s t a t i c i n t Y; public s t a t i c i n t Z = 1 0 0 ; }

114

CAPITOLUL 4. CLASE

4.4.1 4.4.2

C ampuri statice si c ampuri de instant a C ampuri read-only

Utilizarea c ampurilor statice read-only n locul constantelor


public c l a s s C o l o r { public s t a t i c readonly C o l o r Black = new C o l o r ( 0 , 0 , 0 ) ; public s t a t i c readonly C o l o r White = new C o l o r ( 2 5 5 , 2 5 5 , 255) ; public s t a t i c readonly C o l o r Red = new C o l o r ( 2 5 5 , 0 , 0 ) ; public s t a t i c readonly C o l o r Green = new C o l o r ( 0 , 2 5 5 , 0 ) ; public s t a t i c readonly C o l o r Blue = new C o l o r ( 0 , 0 , 2 5 5 ) ; private byte red , green , b l u e ; public C o l o r ( byte r , byte g , byte b ) { red = r ; green = g ; blue = b ; } }

Versionarea constantelor si a c ampurilor statice read-only


namespace Program1 { public c l a s s U t i l s { public s t a t i c readonly i n t X = 1 ; } } using System ; namespace Program2 { c l a s s Test { s t a t i c void Main ( ) { C o n s o l e . WriteLine ( Program1 . U t i l s .X) ; } } }

4.4.3

C ampuri volatile

using System ; using System . Threading ; c l a s s Test {

4.4. CAMPURI

115

public s t a t i c i n t r e s u l t ; public s t a t i c v o l a t i l e bool f i n i s h e d ; s t a t i c void Thread2 ( ) { r e s u l t = 143; f i n i s h e d = true ; } s t a t i c void Main ( ) { finished = false ; // Run Thread2 ( ) i n a new t h r e a d new Thread ( new T h r e a d S t a r t ( Thread2 ) ) . S t a r t ( ) ; // Wait f o r Thread2 t o s i g n a l t h a t i t has a r e s u l t by setting // f i n i s h e d t o t r u e . for ( ; ; ) { if ( finished ) { C o n s o l e . WriteLine ( " result = {0} " , r e s u l t ) ; return ; } } } } r e s u l t = 143

4.4.4

Init ializarea c ampurilor

using System ; c l a s s Test { s t a t i c bool b ; int i ; s t a t i c void Main ( ) { Test t = new Test ( ) ; C o n s o l e . WriteLine ( "b = {0} , i = {1} " , b , t . i ) ; } } b = False , i = 0

4.4.5

Init ializarea variabilelor

using System ; c l a s s Test { s t a t i c double x = Math . S q r t ( 2 . 0 ) ;

116

CAPITOLUL 4. CLASE
int i = 100; s t r i n g s = " Hello " ; s t a t i c void Main ( ) { Test a = new Test ( ) ; C o n s o l e . WriteLine ( "x = {0} , i = {1} , s = {2} " , x , a . i , a.s); }

} x = 1.4142135623731 , i = 100 , s = Hello using System ; c l a s s Test { static int a = b + 1 ; static int b = a + 1 ; s t a t i c void Main ( ) { C o n s o l e . WriteLine ( "a = {0} , b = {1} " , a , b ) ; } } a = 1, b = 2

Init ializarea c ampurilor statice


using System ; c l a s s Test { s t a t i c void Main ( ) { C o n s o l e . WriteLine ( " {0} {1} " , B . Y, A.X) ; } public s t a t i c i n t f ( s t r i n g s ) { C o n s o l e . WriteLine ( s ) ; return 1 ; } } class A { public s t a t i c i n t X = Test . f ( " Init A" ) ; } class B { public s t a t i c i n t Y = Test . f ( " Init B" ) ; } Init A Init B 1 1

4.5. METODE

117

Init B Init A 1 1 using System ; c l a s s Test { s t a t i c void Main ( ) { C o n s o l e . WriteLine ( " {0} {1} " , B . Y, A.X) ; } public s t a t i c i n t f ( s t r i n g s ) { C o n s o l e . WriteLine ( s ) ; return 1 ; } } class A { s t a t i c A( ) {} public s t a t i c i n t X = Test . f ( " Init A" ) ; } class B { s t a t i c B( ) {} public s t a t i c i n t Y = Test . f ( " Init B" ) ; } Init B Init A 1 1

Init ializarea c ampurilor de instant a


class A { int x = 1 ; i n t y = x + 1 ; // Error , r e f e r e n c e t o i n s t a n c e member o f this }

4.5

Metode
method-declaration: method-header method-body method-header: attributesopt method-modiersopt return-type member-name type-parameter-listopt ( formal-parameter-listopt ) type-parameter-constraints-clausesopt method-modiers:

118 method-modier method-modiers method-modier method-modier: new public protected internal private static virtual sealed override abstract extern return-type: type void member-name: identier interface-type . identier method-body: block ;

CAPITOLUL 4. CLASE

4.5.1

Parametrii metodelor

formal-parameter-list: xed-parameters xed-parameters , parameter-array parameter-array xed-parameters: xed-parameter xed-parameters , xed-parameter xed-parameter: attributesopt parameter-modieropt type identier parameter-modier: ref out parameter-array: attributesopt params array-type identier

Parametrii valoare Parametrii referint a


using System ; c l a s s Test {

4.5. METODE
s t a t i c void Swap ( r e f in t x , r e f in t y ) { i n t temp = x ; x = y; y = temp ; } s t a t i c void Main ( ) { int i = 1 , j = 2 ; Swap ( r e f i , r e f j ) ; C o n s o l e . WriteLine ( "i = {0} , j = {1} " , i , j ) ; } } i = 2, j = 1 class A { string s ; void F( r e f s t r i n g a , r e f s t r i n g b ) { s = " One " ; a = " Two " ; b = " Three " ; } void G( ) { F( r e f s , r e f s ) ; } }

119

Parametrii de ie sire
using System ; c l a s s Test { s t a t i c void S p l i t P a t h ( s t r i n g path , out s t r i n g d i r , out s t r i n g name ) { i n t i = path . Length ; while ( i > 0 ) { char ch = path [ i 1 ] ; i f ( ch == \ \ | | ch == / | | ch == : ) break ; i ; } d i r = path . S u b s t r i n g ( 0 , i ) ; name = path . S u b s t r i n g ( i ) ; } s t a t i c void Main ( ) { s t r i n g d i r , name ;

120

CAPITOLUL 4. CLASE
S p l i t P a t h (@"c :\ Windows \ System \ hello . txt " , out d i r , out name ) ; C o n s o l e . WriteLine ( d i r ) ; C o n s o l e . WriteLine ( name ) ; }

} c : \ Windows \ System \ hello . txt

Parametrii de tip matrice


using System ; c l a s s Test { s t a t i c void F( params i n t [ ] a r g s ) { C o n s o l e . Write ( " Array contains {0} elements :" , a r g s . Length ) ; foreach ( i n t i in a r g s ) C o n s o l e . Write ( " {0} " , i ) ; C o n s o l e . WriteLine ( ) ; } s t a t i c void Main ( ) { int [ ] a r r = {1 , 2 , 3 } ; F( a r r ) ; F( 1 0 , 2 0 , 3 0 , 4 0 ) ; F() ; } } Array c o n t a i n s 3 e l e m e n t s : 1 2 3 Array c o n t a i n s 4 e l e m e n t s : 10 20 30 40 Array c o n t a i n s 0 e l e m e n t s : F( new i n t [ ] { 1 0 , 2 0 , 3 0 , 4 0 } ) ; F( new i n t [ ] { } ) ; using System ; c l a s s Test { s t a t i c void F( params object [ ] a ) { C o n s o l e . WriteLine ( "F( object []) " ) ; } s t a t i c void F ( ) { C o n s o l e . WriteLine ( "F () " ) ; } s t a t i c void F( object a0 , object a1 )

4.5. METODE
{ C o n s o l e . WriteLine ( "F( object , object )" ) ; } s t a t i c void Main ( ) { F() ; F(1) ; F(1 , 2) ; F(1 , 2 , 3) ; F(1 , 2 , 3 , 4) ; } } F() ; F( object [ ] ) ; F( object , object ) ; F( object [ ] ) ; F( object [ ] ) ; using System ; c l a s s Test { s t a t i c void F( params object [ ] a r g s ) { foreach ( object o in a r g s ) { C o n s o l e . Write ( o . GetType ( ) . FullName ) ; C o n s o l e . Write ( " " ) ; } C o n s o l e . WriteLine ( ) ; } s t a t i c void Main ( ) { object [ ] a = { 1 , " Hello " , 1 2 3 . 4 5 6 } ; object o = a ; F( a ) ; F ( ( object ) a ) ; F( o ) ; F ( ( object [ ] ) o ) ; } } System . I n t 3 2 System . S t r i n g System . Double System . O bjec t [ ] System . O bjec t [ ] System . I n t 3 2 System . S t r i n g System . Double

121

4.5.2 4.5.3

Metode statice si metode de instant a Metode virtuale

122

CAPITOLUL 4. CLASE

using System ; class A { public void F ( ) { C o n s o l e . WriteLine ( "A.F" ) ; } public v i r t u a l void G( ) { C o n s o l e . WriteLine ( "A.G" ) ; } } class B: A { new public void F ( ) { C o n s o l e . WriteLine ( "B.F" ) ; } public override void G( ) { C o n s o l e . WriteLine ( "B.G" ) ; } } c l a s s Test { s t a t i c void Main ( ) { B b = new B( ) ; A a = b; a .F() ; b .F() ; a .G( ) ; b .G( ) ; } } A. F B.F B .G B .G using System ; class A { public v i r t u a l void F ( ) { C o n s o l e . WriteLine ( "A.F" ) ; } } class B: A { public override void F ( ) { C o n s o l e . WriteLine ( "B.F" ) ; } } class C: B { new public v i r t u a l void F ( ) { C o n s o l e . WriteLine ( "C.F" ) ; } } c l a s s D: C { public override void F ( ) { C o n s o l e . WriteLine ( "D.F" ) ; } } c l a s s Test { s t a t i c void Main ( ) { D d = new D( ) ; A a = d; B b = d;

4.5. METODE
C c = d; a .F() ; b .F() ; c .F() ; d .F() ; } } B.F B.F D. F D. F

123

4.5.4

Suprascrierea metodelor

class A { int x ; public v i r t u a l void P r i n t F i e l d s ( ) { C o n s o l e . WriteLine ( "x = {0} " , x ) ; } } class B: A { int y ; public override void P r i n t F i e l d s ( ) { base . P r i n t F i e l d s ( ) ; C o n s o l e . WriteLine ( "y = {0} " , y ) ; } } class A { public v i r t u a l void F ( ) {} } class B: A { public v i r t u a l void F ( ) {} // Warning , h i d i n g i n h e r i t e d F () } class A { public v i r t u a l void F ( ) {} } class B: A { new private void F ( ) {} // Hides A. F w i t h i n B }

124

CAPITOLUL 4. CLASE

class C: B { public override void F ( ) {} // Ok , o v e r r i d e s A. F }

4.5.5

Metode sigilate

using System ; class A { public v i r t u a l void F ( ) { C o n s o l e . WriteLine ( "A.F" ) ; } public v i r t u a l void G( ) { C o n s o l e . WriteLine ( "A.G" ) ; } } class B: A { public sealed override void F ( ) { C o n s o l e . WriteLine ( "B.F" ) ; } public override void G( ) { C o n s o l e . WriteLine ( "B.G" ) ; } } class C: B { public override void G( ) { C o n s o l e . WriteLine ( "C.G" ) ; } }

4.5.6

Metode abstracte

public abstract c l a s s Shape { public abstract void P a i n t ( G r a p h i c s g , R e c t a n g l e r ) ; } public c l a s s E l l i p s e : Shape { public override void P a i n t ( G r a p h i c s g , R e c t a n g l e r ) { g . DrawEllipse ( r ) ; } }

4.5. METODE
public c l a s s Box : Shape { public override void P a i n t ( G r a p h i c s g , R e c t a n g l e r ) { g . DrawRect ( r ) ; } } abstract c l a s s A { public abstract void F ( ) ; } class B: A { public override void F ( ) { base . F ( ) ; // Error , b a s e . F i s a b s t r a c t } } using System ; class A { public v i r t u a l void F ( ) { C o n s o l e . WriteLine ( "A.F" ) ; } } abstract c l a s s B : A { public abstract override void F ( ) ; } class C: B { public override void F ( ) { C o n s o l e . WriteLine ( "C.F" ) ; } }

125

4.5.7

Metode externe

using System . Text ; using System . S e c u r i t y . P e r m i s s i o n s ; using System . Runtime . I n t e r o p S e r v i c e s ; c l a s s Path { [ D l l I m p o r t ( " kernel32 " , S e t L a s t E r r o r=true ) ] s t a t i c extern bool C r e a t e D i r e c t o r y ( s t r i n g name , S e c u r i t y A t t r i b u t e sa ) ; [ D l l I m p o r t ( " kernel32 " , S e t L a s t E r r o r=true ) ] s t a t i c extern bool RemoveDirectory ( s t r i n g name ) ;

126

CAPITOLUL 4. CLASE
[ D l l I m p o r t ( " kernel32 " , S e t L a s t E r r o r=true ) ] s t a t i c extern i n t G e t C u r r e n t D i r e c t o r y ( i n t b u f S i z e , S t r i n g B u i l d e r buf ) ; [ D l l I m p o r t ( " kernel32 " , S e t L a s t E r r o r=true ) ] s t a t i c extern bool S e t C u r r e n t D i r e c t o r y ( s t r i n g name ) ;

4.5.8

Corpul metodelor

class A { public i n t F ( ) {} // Error , r e t u r n v a l u e r e q u i r e d public i n t G( ) { return 1 ; } public i n t H( bool b ) { i f (b) { return 1 ; } else { return 0 ; } } }

4.5.9

Supra nc arcarea metodelor

4.6

Propriet a ti
property-declaration: attributesopt property-modiersopt type member-name accessor-declarations property-modiers: property-modier property-modiers property-modier property-modier: new public protected internal private static virtual sealed override abstract extern

I 4.6. PROPRIETAT

127

4.6.1 4.6.2

Propriet a ti statice si de instant a Accesori

accessor-declarations: get-accessor-declaration set-accessor-declarationopt set-accessor-declaration get-accessor-declarationopt get-accessor-declaration: attributesopt accessor-modieropt get accessor-body set-accessor-declaration: attributesopt accessor-modieropt set accessor-body accessor-modier: protected internal private protected internal internal protected accessor-body: block ;

public c l a s s Button : C o n t r o l { private s t r i n g c a p t i o n ; public s t r i n g Caption { g e t { return c a p t i o n ; } set { i f ( c a p t i o n != v a l u e ) { caption = value ; Repaint ( ) ; } } } public override void P a i n t ( G r a p h i c s g , R e c t a n g l e r ) { // P a i n t i n g code g o e s h e r e } } Button okButton = new Button ( ) ; okButton . Caption = " OK " ; // I n v o k e s s e t a c c e s s o r s t r i n g s = okButton . Caption ; // I n v o k e s g e t a c c e s s o r class A {

128

CAPITOLUL 4. CLASE
private s t r i n g name ; public s t r i n g Name { // Error , d u p l i c a t e member name g e t { return name ; } } public s t r i n g Name { // Error , d u p l i c a t e member name s e t { name = v a l u e ; } }

} class A { public i n t P { set { . . . } } } class B: A { new public i n t P { get { . . . } } } B b = new B( ) ; b . P = 1 ; // Error , B. P i s read o n l y ( (A) b ) . P = 1 ; // Ok , r e f e r e n c e t o A. P class Label { private i n t x , y ; private s t r i n g c a p t i o n ; public L a b e l ( i n t x , i n t y , s t r i n g c a p t i o n ) { this . x = x ; this . y = y ; this . caption = caption ; } public i n t X { g e t { return x ; } } public i n t Y { g e t { return y ; } } public P o i n t L o c a t i o n { g e t { return new P o i n t ( x , y ) ; } } public s t r i n g Caption

I 4.6. PROPRIETAT
{ g e t { return c a p t i o n ; } } } class Label { private P o i n t l o c a t i o n ; private s t r i n g c a p t i o n ; public L a b e l ( i n t x , i n t y , s t r i n g c a p t i o n ) { t h i s . l o c a t i o n = new P o i n t ( x , y ) ; this . caption = caption ; } public i n t X { g e t { return l o c a t i o n . x ; } } public i n t Y { g e t { return l o c a t i o n . y ; } } public P o i n t L o c a t i o n { g e t { return l o c a t i o n ; } } public s t r i n g Caption { g e t { return c a p t i o n ; } } } c l a s s Counter { private i n t next ; public i n t Next { g e t { return next++; } } } using System . IO ; public c l a s s C o n s o l e { private s t a t i c TextReader r e a d e r ; private s t a t i c TextWriter w r i t e r ; private s t a t i c TextWriter e r r o r ; public s t a t i c TextReader In { get { i f ( r e a d e r == null ) {

129

130

CAPITOLUL 4. CLASE
r e a d e r = new StreamReader ( C o n s o l e . OpenStandardInput ( ) ) ; } return r e a d e r ; } } public s t a t i c TextWriter Out { get { i f ( w r i t e r == null ) { w r i t e r = new StreamWriter ( C o n s o l e . OpenStandardOutput ( ) ) ; } return w r i t e r ; } } public s t a t i c TextWriter E r r o r { get { i f ( e r r o r == null ) { e r r o r = new StreamWriter ( C o n s o l e . OpenStandardError ( ) ) ; } return e r r o r ; } } ...

} class A { public s t r i n g Text { g e t { return " hello " ; } set { } } public i n t Count { g e t { return 5 ; } set { } } } class B: A { private s t r i n g t e x t = " goodbye " ; private i n t count = 0 ; new public s t r i n g Text { g e t { return t e x t ; } protected s e t { t e x t = v a l u e ; }

I 4.6. PROPRIETAT
} new protected i n t Count { g e t { return count ; } s e t { count = v a l u e ; } } } class M { s t a t i c void Main ( ) { B b = new B( ) ; b . Count = 1 2 ; // C a l l s A. Count s e t a c c e s s o r i n t i = b . Count ; // C a l l s A. Count g e t a c c e s s o r b . Text = " howdy " ; // Error , B. Text s e t a c c e s s o r n o t accessible s t r i n g s = b . Text ; // C a l l s B. Text g e t a c c e s s o r } }

131

public i n t e r f a c e I { s t r i n g Prop { g e t ; } } public c l a s s C : I { public s t r i n g Prop { g e t { return " April " ; } // S h a l l n o t have a m o d i f i e r here internal s e t { . . .} // Ok , b e c a u s e I . Prop has no s e t accessor } }

4.6.3

Accesori virtuali, sigilat i, suprascri si, supra nc arcat i

public c l a s s B { public v i r t u a l i n t P { protected s e t { . . . } get { . . . } } public v i r t u a l i n t Q { private s e t { . . . } // n o t v i r t u a l get { . . . } } } public c l a s s D: B {

132

CAPITOLUL 4. CLASE
public override i n t P { protected s e t { . . . } // Must s p e c i f y p r o t e c t e d h e r e g e t { . . . } // Must n o t have a m o d i f i e r h e r e } public override i n t Q { private s e t { . . . } // Error : i n h e r i t e d s e t i s n o t accessible g e t { . . . } // Must n o t have a m o d i f i e r h e r e }

} abstract c l a s s A { int y ; public v i r t u a l i n t X { g e t { return 0 ; } } public v i r t u a l i n t Y { g e t { return y ; } set { y = value ; } } public abstract i n t Z { g e t ; s e t ; } } class B: A { int z ; public override i n t X { g e t { return base .X + 1 ; } } public override i n t Y { s e t { base .Y = v a l u e < 0? 0 : v a l u e ; } } public override i n t Z { g e t { return z ; } set { z = value ; } } }

4.7

Evenimente
event-declaration: attributesopt event-modiersopt event type variable-declarators ; attributesopt event-modiersopt event type member-name

4.7. EVENIMENTE event-accessor-declarations event-modiers: event-modier event-modiers event-modier event-modier: new public protected internal private static virtual sealed override abstract extern event-accessor-declarations: add-accessor-declaration remove-accessor-declaration remove-accessor-declaration add-accessor-declaration add-accessor-declaration: attributesopt add block remove-accessor-declaration: attributesopt remove block

133

public delegate void EventHandler ( object s e n d e r , EventArgs e ) ; public c l a s s Button : C o n t r o l { public event EventHandler C l i c k ; } public c l a s s L o g i n D i a l o g : Form { Button OkButton ; Button CancelButton ; public L o g i n D i a l o g ( ) { OkButton = new Button ( . . .) ; OkButton . C l i c k += OkButtonClick ; CancelButton = new Button ( . . . ) ; CancelButton . C l i c k += C a n c e l B u t t o n C l i c k ; } void OkButtonClick ( object s e n d e r , EventArgs e ) { // Handle OkButton . C l i c k e v e n t } void C a n c e l B u t t o n C l i c k ( object s e n d e r , EventArgs e ) { // Handle CancelButton . C l i c k e v e n t } }

134

CAPITOLUL 4. CLASE

4.7.1

Evenimente de tip c amp

public delegate void EventHandler ( object s e n d e r , EventArgs e ) ; public c l a s s Button : C o n t r o l { public event EventHandler C l i c k ; protected void OnClick ( EventArgs e ) { EventHandler t o R a i s e = C l i c k ; i f ( t o R a i s e != null ) t o R a i s e ( this , e ) ; } public void R e s e t ( ) { C l i c k = null ; } } b . C l i c k += new EventHandler ( . . . ) ; b . C l i c k = new EventHandler ( . . . ) ; class X { public event D Ev1 ; public event D Ev2 ; } class X { public event D Ev1 { add { lock ( t h i s ) } remove { lock ( t h i s ) } } public event D Ev2 { add { lock ( t h i s ) } remove { lock ( t h i s ) } }

ev1 =

ev1 + value ; }

ev1 =

ev1 value ; }

ev2 =

ev2 + value ; }

ev2 =

ev2 value ; }

4.7. EVENIMENTE
private D private D } class X { public event D Ev1 { add { lock ( k e y ) { ev1 = ev1 } remove { lock ( k e y ) { ev1 = ev1 } } public event D Ev2 { add { lock ( k e y ) { ev2 = ev2 } remove { lock ( k e y ) { ev2 = ev2 } } private D e v 1 ; // f i e l d t o h o l d a private D e v 2 ; // f i e l d t o h o l d a private readonly object k e y = new } class X { public s t a t i c event D Ev1 ; public s t a t i c event D Ev2 ; } class X { public s t a t i c event D Ev1 { add { lock ( typeof (X) ) { } remove { lock ( typeof (X) ) { } } public s t a t i c event D Ev2 e v 1 ; // f i e l d t o h o l d a d e l e g a t e e v 2 ; // f i e l d t o h o l d a d e l e g a t e

135

+ value ; }

value ; }

+ value ; }

value ; }

delegate delegate object ( ) ;

ev1 =

ev1 + value ; }

ev1 =

ev1 value ; }

136
{ add { lock ( typeof (X) ) { } remove { lock ( typeof (X) ) { } } private s t a t i c D private s t a t i c D } ev2 =

CAPITOLUL 4. CLASE

ev2 + value ; }

ev2 =

ev2 value ; }

e v 1 ; // f i e l d t o h o l d a d e l e g a t e e v 2 ; // f i e l d t o h o l d a d e l e g a t e

class X { public s t a t i c event D Ev1 { add { lock ( k e y ) { ev1 = ev1 + value ; } } remove { lock ( k e y ) { ev1 = ev1 value ; } } } public s t a t i c event D Ev2 { add { lock ( k e y ) { ev2 = ev2 + value ; } } remove { lock ( k e y ) { ev2 = ev2 value ; } } } private s t a t i c D e v 1 ; // f i e l d t o h o l d a d e l e g a t e private s t a t i c D e v 2 ; // f i e l d t o h o l d a d e l e g a t e private s t a t i c readonly object k e y = new object ( ) ; }

4.7.2

Declan sarea evenimentelor

c l a s s C o n t r o l : Component { // Unique k e y s f o r e v e n t s s t a t i c readonly object mouseDownEventKey = new object ( ) ; s t a t i c readonly object mouseUpEventKey = new object ( ) ; // Return e v e n t h a n d l e r a s s o c i a t e d w i t h k e y protected D e l e g a t e GetEventHandler ( object key ) { . . . }

4.8. INDEXATORI

137

// Add e v e n t h a n d l e r a s s o c i a t e d w i t h k e y protected void AddEventHandler ( object key , D e l e g a t e handler ) { . . . } // Remove e v e n t h a n d l e r a s s o c i a t e d w i t h k e y protected void RemoveEventHandler ( object key , D e l e g a t e handler ) { . . . } // MouseDown e v e n t public event MouseEventHandler MouseDown { add { AddEventHandler ( mouseDownEventKey , v a l u e ) ; } remove { RemoveEventHandler ( mouseDownEventKey , v a l u e ) ; } } // MouseUp e v e n t public event MouseEventHandler MouseUp { add { AddEventHandler ( mouseUpEventKey , v a l u e ) ; } remove { RemoveEventHandler ( mouseUpEventKey , v a l u e ) ; } } // I n v o k e t h e MouseUp e v e n t protected void OnMouseUp ( MouseEventArgs a r g s ) { MouseEventHandler h a n d l e r ; h a n d l e r = ( MouseEventHandler ) GetEventHandler ( mouseUpEventKey ) ; i f ( h a n d l e r != null ) h a n d l e r ( this , a r g s ) ; } }

4.7.3 4.7.4

Evenimente statice si de instant a Declan satori virtuali, sigilat i, suprascri si sau abstract i

4.8

Indexatori
indexer-declaration: attributesopt indexer-modiersopt indexer-declarator { accessor-declarations } indexer-modiers: indexer-modier indexer-modiers indexer-modier indexer-modier: new public protected internal private virtual sealed override abstract

138

CAPITOLUL 4. CLASE extern indexer-declarator: type this [ formal-parameter-list ] type interface-type . this [ formal-parameter-list ]

using System ; c l a s s BitArray { int [ ] b i t s ; int length ; public BitArray ( i n t l e n g t h ) { i f ( l e n g t h < 0 ) throw new ArgumentException ( ) ; b i t s = new i n t [ ( ( l e n g t h 1 ) >> 5 ) + 1 ] ; this . length = length ; } public i n t Length { g e t { return l e n g t h ; } } public bool t h i s [ i n t i n d e x ] { get { i f ( i n d e x < 0 | | i n d e x >= l e n g t h ) { throw new IndexOutOfRangeException ( ) ; } return ( b i t s [ i n d e x >> 5 ] & 1 << i n d e x ) != 0 ; } set { i f ( i n d e x < 0 | | i n d e x >= l e n g t h ) { throw new IndexOutOfRangeException ( ) ; } i f ( value ) { b i t s [ i n d e x >> 5 ] | = 1 << i n d e x ; } else { b i t s [ i n d e x >> 5 ] &= ( 1 << i n d e x ) ; } } } } c l a s s CountPrimes { s t a t i c i n t Count ( i n t max) {

4.8. INDEXATORI

139

BitArray f l a g s = new BitArray (max + 1 ) ; i n t count = 0 ; f o r ( i n t i = 2 ; i <= max ; i ++) { if (! flags [ i ]) { f o r ( i n t j = i 2 ; j <= max ; j += i ) f l a g s [ j ] = true ; count++; } } return count ; } s t a t i c void Main ( s t r i n g [ ] a r g s ) { i n t max = i n t . Pa r s e ( a r g s [ 0 ] ) ; i n t count = Count (max) ; C o n s o l e . WriteLine ( " Found {0} primes between 2 and {1} " , count , max) ; } } using System ; c l a s s Grid { const i n t NumRows = 2 6 ; const i n t NumCols = 1 0 ; i n t [ , ] c e l l s = new i n t [ NumRows, NumCols ] ; public i n t t h i s [ char c , i n t colm ] { get { c = Char . ToUpper ( c ) ; i f ( c < A | | c > Z ) { throw new ArgumentException ( ) ; } i f ( colm < 0 | | colm >= NumCols ) { throw new IndexOutOfRangeException ( ) ; } return c e l l s [ c A , colm ] ; } set { c = Char . ToUpper ( c ) ; i f ( c < A | | c > Z ) { throw new ArgumentException ( ) ; } i f ( colm < 0 | | colm >= NumCols ) { throw new IndexOutOfRangeException ( ) ; }

140
c e l l s [ c A , colm ] = v a l u e ; } } }

CAPITOLUL 4. CLASE

4.8.1

Supra nc arcarea indexatorilor

4.9

Operatori
operator-declaration: attributesopt operator-modiers opertor-declarator operator-body operator-modiers: operator-modier operator-modiers operator-modier operator-modier: public static extern operator-declarator: unary-operator-declarator binary-operator-declarator conversion-operator-declarator unary-operator-declarator: type operator overloadable-unary-operator ( type identier ) overloadable-unary-operator: one of + - ! ++ -- true false binary-operator-declarator: type operator overloadable-binary-operator ( type identier , type identier ) overloadable-binary-operator: one of + - * / % & | ^ << right-shift == != > < >= <= conversion-operator-declarator: implicit operator type ( type identier ) explicit operator type ( type identier ) operator-body: block ;

4.9.1

Operatori unari

public c l a s s I n t V e c t o r { public i n t Length { . . . } property public i n t t h i s [ i n t i n d e x ] { . . . } indexer

// read o n l y // read w r i t e

4.10. CONSTRUCTORII DE INSTANT A


public I n t V e c t o r ( i n t v e c t o r L e n g t h ) { . . . } public s t a t i c I n t V e c t o r operator++(I n t V e c t o r i v ) { I n t V e c t o r temp = new I n t V e c t o r ( i v . Length ) ; f o r ( i n t i = 0 ; i < i v . Length ; ++i ) temp [ i ] = i v [ i ] + 1 ; return temp ; } } c l a s s Test { s t a t i c void Main ( ) { I n t V e c t o r i v 1 = new I n t V e c t o r ( 4 ) ; // v e c t o r o f 4 x0 IntVector iv2 ; i v 2 = i v 1 ++; // i v 2 c o n t a i n s 4 x0 , i v 1 c o n t a i n s 4 x1 i v 2 = ++i v 1 ; // i v 2 c o n t a i n s 4 x2 , i v 1 c o n t a i n s 4 x2 } }

141

4.9.2 4.9.3

Operatori binari Operatori pentru conversie

using System ; public struct D i g i t { byte v a l u e ; public D i g i t ( i n t v a l u e ) { i f ( v a l u e < 0 | | v a l u e > 9 ) throw new ArgumentException ( ) ; this . value = value ; } public s t a t i c i m p l i c i t operator byte ( D i g i t d ) { return d . v a l u e ; } public s t a t i c e x p l i c i t operator D i g i t ( i n t n ) { return new D i g i t ( n ) ; } }

4.10

Constructorii de instant a

constructor-declaration: attributesopt constructor-modiersopt constructor-declarator constructor-body constructor-modiers: constructor-modier constructor-modiers constructor-modier

142

CAPITOLUL 4. CLASE constructor-modier: public protected internal private extern constructor-declarator: identier ( formal-parameter-listopt ) constructor-initializeropt constructor-initializer: : base ( argument-listopt ) : this ( argument-listopt ) constructor-body: block ;

4.10.1

Init ializtorii constructorilor


{...} {...}

C( . . . ) C( . . . )

class A { public A( i n t x , i n t y ) {} } class B: A { public B( i n t x , i n t y ) : base ( x + y , x y ) {} }

4.10.2 4.10.3

Init ializarea variabilelor de instant a Execut ia constructorului

using System ; class A { public A( ) { PrintFields () ; } public v i r t u a l void P r i n t F i e l d s ( ) {} } class B: A { int x = 1 ; int y ; public B( ) {

4.10. CONSTRUCTORII DE INSTANT A


y = 1; } public override void P r i n t F i e l d s ( ) { C o n s o l e . WriteLine ( "x = {0} , y = {1} " , x , y ) ; } } x = 1, y = 0 using System . C o l l e c t i o n s ; class A { i n t x = 1 , y = 1, count ; public A( ) { count = 0 ; } public A( i n t n ) { count = n ; } } class B: A { double s q r t 2 = Math . S q r t ( 2 . 0 ) ; A r r a y L i s t i t e m s = new A r r a y L i s t ( 1 0 0 ) ; i n t max ; public B( ) : t h i s ( 1 0 0 ) { i t e m s . Add( " default " ) ; } public B( i n t n ) : base ( n 1 ) { max = n ; } } using System . C o l l e c t i o n s ; class A { i n t x , y , count ; public A( ) { x = 1 ; // V a r i a b l e y = 1; // V a r i a b l e object ( ) ; // I n v o k e count = 0 ; } public A( i n t n ) { x = 1 ; // V a r i a b l e y = 1; // V a r i a b l e

143

initializer initializer object () constructor

initializer initializer

144

CAPITOLUL 4. CLASE
object ( ) ; // I n v o k e o b j e c t ( ) c o n s t r u c t o r count = n ;

} } class B: A { double s q r t 2 ; ArrayList items ; i n t max ; public B( ) : t h i s ( 1 0 0 ) { B( 1 0 0 ) ; // I n v o k e B( i n t ) c o n s t r u c t o r i t e m s . Add( " default " ) ; } public B( i n t n ) : base ( n 1 ) { s q r t 2 = Math . S q r t ( 2 . 0 ) ; // V a r i a b l e i n i t i a l i z e r i t e m s = new A r r a y L i s t ( 1 0 0 ) ; // V a r i a b l e i n i t i a l i z e r A( n 1 ) ; // I n v o k e A( i n t ) c o n s t r u c t o r max = n ; } }

4.10.4

Constructori implicit i

protected C( ) : base ( ) {} public C( ) : base ( ) {} c l a s s Message { object s e n d e r ; string t e x t ; } c l a s s Message { object s e n d e r ; string t e x t ; public Message ( ) : base ( ) {} }

4.10.5

Constructori privat i

public c l a s s C o l o r { private byte v a l ; private C o l o r ( byte v a l ) { t h i s . v a l = v a l ; } public s t a t i c readonly C o l o r Red = new C o l o r ( 0 ) ; public s t a t i c readonly C o l o r Green = new C o l o r ( 1 ) ;

4.11. CONSTRUCTORI STATICI


public s t a t i c readonly C o l o r Blue = new C o l o r ( 2 ) ; }

145

4.10.6

Parametrii opt ionali ai constructorului de instant a

c l a s s Text { public public public { // } }

Text ( ) : t h i s ( 0 , 0 , null ) {} Text ( i n t x , i n t y ) : t h i s ( x , y , null ) {} Text ( i n t x , i n t y , s t r i n g s ) Actual constructor implementation

Text t 1 = new Text ( ) ; // Same as Text ( 0 , 0 , n u l l ) Text t 2 = new Text ( 5 , 1 0 ) ; // Same as Text ( 5 , 10 , n u l l ) Text t 3 = new Text ( 5 , 2 0 , " Hello " ) ;

4.11

Constructori statici

static-constructor-declaration: attributesopt static-constructor-modiers identier ( ) static-constructor-body static-constructor-modiers: externopt static static externopt static-constructor-body: block ;

using System ; c l a s s Test { s t a t i c void Main ( ) { A. F ( ) ; B.F( ) ; } } class A { s t a t i c A( ) { C o n s o l e . WriteLine ( " Init A" ) ; } public s t a t i c void F ( ) { C o n s o l e . WriteLine ( "A.F" ) ;

146
} } class B { s t a t i c B( ) { C o n s o l e . WriteLine ( " Init B" ) ; } public s t a t i c void F ( ) { C o n s o l e . WriteLine ( "B.F" ) ; } } Init A A. F Init B B.F

CAPITOLUL 4. CLASE

using System ; class A { public s t a t i c i n t X; s t a t i c A( ) { X = B .Y + 1 ; } } class B { public s t a t i c i n t Y = A.X + 1 ; s t a t i c B( ) {} s t a t i c void Main ( ) { C o n s o l e . WriteLine ( "X = {0} , Y = {1} " , A. X, B .Y) ; } } X = 1, Y = 2

4.12

Destructori

nalizer-declaration: attributesopt externopt identier ( ) nalizer-body nalizer-body: block ;

using System ; class A { A( )

4.12. DESTRUCTORI
{ C o n s o l e . WriteLine ( "A s finalizer " ) ; } } class B: A { B( ) { C o n s o l e . WriteLine ( "B s finalizer " ) ; } } c l a s s Test { s t a t i c void Main ( ) { B b = new B( ) ; b = null ; GC. C o l l e c t ( ) ; GC. W a i t F o r P e n d i n g F i n a l i z e r s ( ) ; } } Bs f i n a l i z e r As f i n a l i z e r class A { protected override void F i n a l i z e ( ) {} // e r r o r public void F ( ) { t h i s . F i n a l i z e ( ) ; // e r r o r } } class A { void F i n a l i z e ( ) {} // p e r m i t t e d }

147

148

CAPITOLUL 4. CLASE

Capitolul 5

Iteratori
Un iterator nseamn a o implementare a unei funct ii membru al c arui tip returnat este o inetrfat a enumerator sau o interfat a enumerabil a. Membrul funct iei returneaz a secvent a de valori ordonat a cu ajutorul iteratorului. De exemplu, implementarea clasei Stack<T> este metoda GetEnumerator, care utilizeaz a un iterator. Iteratorul enumer a elementele din stiv a de sus n jos.
using System . C o l l e c t i o n s . G e n e r i c ; public c l a s s Stack <T> : IEnumerable <T> { T [ ] items ; i n t count ; public void Push (T data ) { . . . } public T Pop ( ) { . . . } public IEnumerator <T> GetEnumerator ( ) { f o r ( i n t i = count 1 ; i >= 0 ; i ) { y i e l d return i t e m s [ i ] ; } } }

Iteratorii sunt implementat i utiliz and instruct iunea yield, care poate utilizat a numai n metode al c aror tip returnat este o interfat a enumerator. prezent a metodei GetEnumerator face Stack<T>, un tip enumerabil, permit and instant elor clasei Stack<T> s a e utilizate n instruct iuni foreach. In exemplul de mai jos sunt ad augate valorile 0 si 9 pe o stiv a de numere ntregi si apoi este folosit a o bucl a foreach pentru a sarea valorilor de sus n jos.
using System ; c l a s s Test { s t a t i c void Main ( ) { Stack <int > s = new Stack <int > () ; f o r ( i n t i = 0 ; i < 1 0 ; i ++) s . Push ( i ) ; foreach ( i n t i in s ) C o n s o l e . Write ( " {0} " , i ) ; C o n s o l e . WriteLine ( ) ;

149

150
} }

CAPITOLUL 5. ITERATORI

Rezultatul rul arii este:


9 8 7 6 5 4 3 2 1 0

5.1

Blocuri iteratoare

Un bloc de iterat ie este un bloc care returneaz a secvent e de valori ordonate. Un bloc de iterat ie este diferit de un bloc normal de instruct iuni prin prezent a instruct iunii yield: instruct iunea yield return aduce urm atoarea valoare din iterat ie; instruct iunea yield break indic a faptul c a iterat ia s-a terminat. Un bloc iterator poate utilizat ca un cod de metod a, ca un corp de operator sau ca un corp de accesare, at ata timp c at tipul returnat corespunz and membrului funct ie este o ineterfat a enumerator sau este o interfat a enumerabil a. Blocul unui iterator nu este un element distinct al gramaticii n C#. Exist a c ateva restrict ii cu efecte majore asupra semanticii declarat iei membrului funct ie. Oricum, gramatica este organizat a n blocuri. C and este implementat a o funct ie ntr-un membru funct ie un bloc iterator nu este permis a utilizarea parametrilor cu modicatorii ref si out. Apare o eroare de compilare dac a este utilizat a instruct iunea return n interiorul unui bloc iterator. Este permis a numai secvent a yield return. Blocurile iteratoare nu pot cont ine cod nesigur. Un bloc iterator ntotdeauna dene ste un context sigur, chiar dac a n declarat ia este inclus a ntr-un context nesigur.

5.1.1

Interfet e de enumerare

O interfat a enumerator este o interfat a non-generic a de tipul System.Collections.IEnumerator si toate instant ele interfet ei generice System.Collections.Generic.IEnumerator<T>. Pentru u surint a, aceste interfet e vor specicate n document ca ind IEnumerator si IEnumerator<T>.

5.1.2

Interfet e enumeratoare

O interfat a enumerabil a este o inetrfat a non generic a numit a System.Collections.IEnumerable si toate instant ele interfet ei generice System.Collections.Generic.IEnumerable<T>. Pentru u surint a, acestea vor numite n continuare IEnumerable si IEnumerable<T>.

5.1.3

Tipul yield

Un bloc iterator produce o secvent a de valori de acela si tip. Tipul returnat se nume ste tip yield sau tip produs al blocului iterator. Tipul yield al unui bloc iterator este utilizat pentru implementarea unui membru funct ie care returneaz a o interfat a IEnumerator sau IEnumerable. In acest caz tipul este obiect.

5.2. OBIECTE ENUMERATOARE

151

Tipul yield folosit ntr-un bloc iterator utilizat pentru implementarea unui membru funct ie care returneaz a IEnumerator<T> sau IEnumerable<T> este T.

5.1.4

Accesorul this

In interiorul unui bloc iterator al unui membru instant a al unei clase expresia this este clasicat a ca valoare. Tipul valorii este clasa n care acesta apare si valoarea este o referint a la obiectul al c arui membru a fost invocat. In interiorul unui bloc iterator al unui membru al unei instant e de tip structur a expresia this este clasicat a ca o variabil a. Tipul variabilei este tipul structurii n care apare. Variabila reprezint a o copie a structurii al c arei membru a fost invocat. Variabila this ntr-un bloc iterator al unui membru instant a al unei structuri este identic a cu parametrul valoare al tipului structurii. Acesta este diferit a fat a de cea existent a n membrii funct ie neiteratori.

5.2

Obiecte enumeratoare

C and un membru funct ie care returneaz a o interfat a enumerator este implementat a utiliz and un bloc iterator, evocarea membrului funct ie nu implic a execut ia imediat a a codului din blocul iterator. De fapt, un obiect enumerator este creat si r asturnat. Acest obiect ncapsuleaz a codul specic blocului iterator si execut ia codului n bloc apare doar c and este apelat a metoda MoveNext a blocului iterator. Un obiect enumerator are urm atoarele caracteristici: El implementeaz a IEnumerator si IEnumerator<T>, unde T este c ampul ntors de blocul iterator. El implementez a System.IDisposable. Este init ializat a o copie a valorilor argumentelor dac a exist a si valoarea instant a este transmis a c atre funct ia membru. Exist a patru st ari potent iale: before, running, suspended si after si starea init ial a este before. Un obiect enumerator este n mod normal o instant a a unei clase enumerator generat a de compilator, care ncapsuleaz a codul blocului iterator si implementeaz a interfat a enumeratoare, dar este posibil a si crearea altor metode la implementare. Dac a un tip enumeratoeste generat de compilator, acea clas a este inclus a direct sau indirect n tipul care cont ine mmbrul funct ie. El este prev azut cu acces privat si are un nume rezervat utilizat de c atre compilator. Un obiect enumerator poate implementa mai multe interfet e, a sa cum este specicat n continuare. Urm atoarea subclauz a descrie comportamentul exact al metodelor MoveNext, Current si Dispose ale implemet arii interfet elor IEnumerable si IEnumerable<T> prev azute ntr-un obiect enumerator. Obiectele enumeratoare nu suport a metoda IEnumerator.Reset. Apelarea acestei metode cauzeaz a o except ie System.NotSupportedException.

152

CAPITOLUL 5. ITERATORI

5.2.1

Metoda MoveNext

Metoda MoveNext ncapsuleaz a codul unui bloc iterator ntr-un obiect enumerator. Apelarea metodei MoveNext executa codul din blocul iterator si seteaz a proprietatea Current a obiectului enumerator n mod corespunz ator. Act iunile executate de metoda MoveNext depind de obiectul enumerator atunci c and este apelat a. Dac a starea obiectului enumerator este before, invocarea metodei MoveNext conduce la: Schimbarea st arii n running. Init ializarea parametrilor inclusiv this ai blocului iterator la valorile argumentelor si valorile instant elor salvate c and obiectul enumerator a fost init ializat. Executarea blocului iterator de la nceput p an a c and execut ia este ntrerupt a, a sa cum este descris mai jos. Dac a starea obiectului enumerator este running, rezultatul invoc arii metodei MoveNext este incert Dac a starea obiectului enumerator este suspended, rezultatul invoc arii metodei MoveNext implic a: Schmbarea st arii n rulare Restaurarea valorilor tuturor variabilelor locale si parametrilor, inclusiv al lui this la valorile salvate c and execut ia blocului iterator a fost suspendat a. Cont inutul unor obiecte referite de variabile poate s a e schimbat de la apelul anterior al funct iei MoveNext S a continue execut ia de la blocul iterator imediat urm ator instruct iunii yield return care a cauzat suspendarea execut iei si se continu a p an a c and execut ia este ntrerupt a, a sa cum este descris mai jos. Dac a starea obiectului enumerator este after, invocarea metodei MoveNext returneaz a fals. C and MoveNext se execut a ntr-un bloc iterator, execut ia poate ntrerupt a n patru feluri: de o instruct iune yield return, de o instruct iune yield break, de atingerea sf ar sitului unui bloc iterator sau de o except ie lansat a din blocul iterator si propagat a n afara acestuia. C and o instruct iune yield return este nt alnit a Expresia dat a n instruct iuni este evaluat a, convertit a n mod implicit la tipul yield si asignat a propriet a tii current a obiectului enumerato Execut ia blocului iterator este suspendat a, valorile tuturor variabilelor si parametrilor, inclusiv this sunt salvate, a sa cum sunt n pozit ia n care a fost nt alnit a instruct iunea yield return. Dac a aceast a instruct iune este n interiorul unui bloc try, blocul nally asociat nu este executat de aceast a dat a. Starea obiectului enumerator este schimbat a la suspendat

5.2. OBIECTE ENUMERATOARE

153

Metoda MoveNext returneaz a true c atre apelant, indic and c a s-a efectuat cu succes iterat ia si s-a avansat la noua valoare C and un bloc yield break este nt alnit: Dac a blocul yield break este n interiorul unui bloc try, blocul nally asociat este executat. Starea obiectului enumerator este schimbat a la after. Metoda MoveNext returneaz a fals c atre apelant, indic and faptul c a iterat ia nu a fost complet a. C and este nt alnit a la sf ar situl corpului iteratorului: Starea obiectului este schimbat a la after Metoda MoveNext returneaz a fals c atre apelant, indic and faptul c a operat ia nu a fost complet a. C and o except ie este nt alnit a si propagat a n afara blocului iterator, atunci: Blocul nally cel mai apropiat n corpul iteratorului va executat de propagarea except iei. Starea obiectului enumerator sem schimb a n after. Se continu a propagarea except iei c atre apelantul metodei MoveNext.

5.2.2

Proprietatea Current

Proprietatea curent a a obiectului enumerator este afectat a de instruct iunea yield return din blocul iterator. C and un obiect enumerare este trecut n trarea suspendat valoarea propriet a tii current este valoarea setat a de apelul MoveNext precedent. C and un obiect enumeratpr este n st arile before, running, sau after rezultatul acces arii propriet a tii current nu este sigur. Pentru un bloc iterator cu un alt tip returnat n afar a de tipul obiect, rezultatul acces arii lui curent prin intermediul interfet ei IEnumerable a obiectului enumerator corespunde acces arii propriet a tii current prin intermediul interfet ei IEnumerator<T> a obiectului enumertor si este f asut a conversia c atre tipul object

5.2.3

Metoda Dispose

Metoda Dispose este utilizat a pentru stergerea iteratorului prin aducerea obiectului iterator n starea after. Dac a starea obiectului enumerator este before, apelul metrodei Dispose schimb a starea la after Dac a starea obiectului enumerator este running, rezultatul apel arii metodei Dispose este incert.

154

CAPITOLUL 5. ITERATORI Dac a starea obiectului enumerator este suspendat, apelul metodei Dispose are urm atoarele efecte: Schimb a starea n rulare. Execut a toate blocurile de nalizare ca si c and ar executat a instruct iunea yield return n locul instruct iunii yield break. Aceasta conduce la o except ie emis a din bloc si propagat a n afara corpului iteratorului, starea obiectului enumerator este setat a la after si except ia este propagat a c atre apelantul metodei Dispose Se schimb a starea la after. Dac a starea obiectului enumerator este after apelul metodei Dispose nu are efect.

5.2.4

Obiecte enumerabile

C and un membru funct ie returneaz a o interfat a enumerabil a, tipul este implementat utiliz and un bloc iterator care apeleaz a o funct ie membru ce nu apeleaz a imediat codul din interiorul blocului iterator. Metoda GetEnumerator a obiectului enumerabil returneaz a un obiect enumerator care ncapsuleaz a codul specic blocului iterator si execut ia codului n iterator apare doar atunci c and este apelat a metoda MoveNext. Un obiect enumerabil are urm atoarele caracteristici: El implementeaz a interfet ele IEnumerable si IEnumerable<T>, unde T este c ampul returnat de blocul iterator. El este init ializat cu o copie a valorilor argument dac a acestea exist a si instant a valorii este transmis a c atre funct ia membru. Un obiect enumerabil este o instant a a unei clase enumerabile generat a de compilator care ncapsuleat a codul blocului iterator si implementeaz a interfat a enumerabil a, dar pot implementate si alte metode al aturi de aceasta. Dac ao clas a enumerabil este generat a de compilator, acea clas a poate inclus a direct sau indirect n clasa care cont ine funct ia membru si care are acces privat si are num ar rezervat utilizat de c atre compilator. Un obiect enumerabil poate implementa mai multe interfet e a sa cum a fost prezentat mai sus. In particular un obiect enumerabil poate implementat printr-o interfat a IEnumerator sau IEnumerator<T> care poate servi at at ca interfat a enumerable, c at si ca iterator. In acest tip de implementare prima dat a este invocat a metoda IEnumerator a obiectului enumerable, si apoi este returnat obiectul enumerable propriu-zis. Apelurile ulterioare ale metodei GetEnumerator al obiectului enumerable. De asemenea, ecare obiect returnat are propriile lui st ari, si schimb arile uneia dintre ele nu le afecteaz a pe celelalte.

5.3

Metoda GetEnumerator

Un obiect enumerabil pune la dispozit ie implent arile metodei GetEnumerator si a interfet elor IEnumerable si IEnumerable<T>. Dou a metode GetEnumerator partajeaz a n comun implementarea si returneaz a un obiect enumerator disponibil. Obiectul enumerator este init ializat cu valorile argumentului si valorile de instant a sunt salvate c and obiectul enumerabil a fost init iializat.

5.3. METODA GETENUMERATOR

155

5.3.1

Exemple de implementare

Implementarea clasei Stack<T> prezentat a n continuare utilizeaz a metoda GetEnumerator ca iterator. Iteratorul enumereaz a elementele din stiv a de sus n jos.
using System ; using System . C o l l e c t i o n s ; using System . C o l l e c t i o n s . G e n e r i c ; c l a s s Stack <T> : IEnumerable <T> { T [ ] items ; i n t count ; public void Push (T item ) { i f ( i t e m s == null ) { i t e m s = new T [ 4 ] ; } e l s e i f ( i t e m s . Length == count ) { T [ ] newItems = new T [ count 2 ] ; Array . Copy ( items , 0 , newItems , 0 , count ) ; i t e m s = newItems ; } i t e m s [ count++] = item ; } public T Pop ( ) { T r e s u l t = i t e m s [ count ] ; i t e m s [ count ] = default (T) ; return r e s u l t ; } public IEnumerator <T> GetEnumerator ( ) { f o r ( i n t i = count 1 ; i >= 0 ; i ) y i e l d return items [ i ] ; } }

Metoda GetEnumerator poate translatat a ntr-o instant a a unui enumerator generat de compilator, care ncapsuleaz a codul blocului iterator a sa cum este prezentat n continuare.
c l a s s Stack <T> : IEnumerable <T> { ... public IEnumerator <T> GetEnumerator ( ) { return new Enumerator1 ( t h i s ) ; } class Enumerator1 : IEnumerator <T> , IEnumerator { int state ; T current ;

156

CAPITOLUL 5. ITERATORI
Stack <T> this ; int i ; public Enumerator1 ( Stack <T> this ) { this . t h i s = this ; } public T Current { g e t { return current ; } } object IEnumerator . Current { g e t { return current ; } } public bool MoveNext ( ) { switch ( s t a t e ) { case 1 : goto state1 ; case 2 : goto state2 ; } i = t h i s . count 1 ; loop : i f ( i < 0 ) goto state2 ; current = t h i s . items [ i ] ; state = 1; return true ; state1 : i ; goto loop ; state2 : state = 2; return f a l s e ; } public void D i s p o s e ( ) { state = 2; } void IEnumerator . R e s e t ( ) { throw new NotSupportedException ( ) ; } }

In descrierea de mai sus codul din blocul iterator este transformat ntr-o ma sin a de st ari si plasat n metoda MoveNext a clasei enumerator. Mai mult, variabila i este transformat a ntr-un c amp al obiectului enumerator, care poate s a existe si peste invocarea apel and metoda MoveNext. Urm atorul exemplu tip are ste un tabel simplu cu mult imi de numere ntregi de la 1 la 10. Metoda FromTo di exemplu returneaz a un obiect enumerabil utiliz and n implementare un iterator.
using System ;

5.3. METODA GETENUMERATOR


using System . C o l l e c t i o n s . G e n e r i c ; c l a s s Test { s t a t i c IEnumerable <int > FromTo ( i n t from , i n t t o ) { while ( from <= t o ) y i e l d return from++; } s t a t i c void Main ( ) { IEnumerable <int > e = FromTo ( 1 , 1 0 ) ; foreach ( i n t x in e ) { foreach ( i n t y in e ) { C o n s o l e . Write ( " {0 ,3} " , x y ) ; } C o n s o l e . WriteLine ( ) ; } } }

157

Metoda FromTo poate translatat a ntr-o instant a de clase enumerabile generat a de compilator care ncapsuleaz a codul unui bloc iterator a sa cum este prezentat n continuare.
using System ; using System . Threading ; using System . C o l l e c t i o n s ; using System . C o l l e c t i o n s . G e n e r i c ; c l a s s Test { ... s t a t i c IEnumerable <int > FromTo ( i n t from , i n t t o ) { return new Enumerable1 ( from , t o ) ; } class Enumerable1 : IEnumerable <int > , IEnumerable , IEnumerator <int > , IEnumerator { int state ; int current ; int from ; i n t from ; int to ; int i ; public Enumerable1 ( i n t from , int to ) { this . from = from ; this . to = to ; } public IEnumerator <int > GetEnumerator ( ) { Enumerable1 r e s u l t = t h i s ;

158

CAPITOLUL 5. ITERATORI
i f ( I n t e r l o c k e d . CompareExchange ( r e f s t a t e , 1 , 0) != 0 ) { r e s u l t = new Enumerable1 ( f r o m , t o ) ; result . state = 1; } r e s u l t . from = r e s u l t . f r o m ; return r e s u l t ; } IEnumerator IEnumerable . GetEnumerator ( ) { return ( IEnumerator ) GetEnumerator ( ) ; } public i n t Current { g e t { return current ; } } object IEnumerator . Current { g e t { return current ; } } public bool MoveNext ( ) { switch ( s t a t e ) { case 1 : i f ( from > t o ) goto case 2 ; c u r r e n t = from++; state = 1; return true ; case 2 : state = 2; return f a l s e ; default : throw new I n v a l i d O p e r a t i o n E x c e p t i o n ( ) ; } } public void D i s p o s e ( ) { state = 2; } void IEnumerator . R e s e t ( ) { throw new NotSupportedException ( ) ; } }

Clasa enumerable implementeaz a ambele interfet e, at at enumerabil a c at si enumerator, permit andu-i acestuia s a serveasc a at at ca enumerator, c at si ca structur a enumerabil a. Prima dat a c and este apelat a metoda GetEnumerator este returnat obiectul enumerabil. Apelurile ulterioare ale metodei GetEnumerator, dac a exist a, returneaz a o copie a obiectului enumerabil. De aceea ecare enumerator r asturnat are propriile lui st ari si schimb arile unuia nu-l afecteaz a

5.3. METODA GETENUMERATOR

159

pe cel alalt. Metoda Interlocked.CompareExchange este utilizat a pentru a sigur a operarea pe thread-uri. Parametrii from si to sunt transformat i n c ampuri ale clasei enumerabile. Deoarece from este modicat n blocul iterator un c amp from este introdus pentru a ret ine valoarea init ial a dat a de from n ecare enumerator. Metoda MoveNext creaz a except ii n InvalidOperationException dac a este apelat a c and state este 0. Aceasta asigur a protect ia atunci c and obiectul enumerabil este utilizat ca obiect enumerator f ar a apelul funct iei GetEnumerator. Urm atorul exemplu implementeaz a o clas a simpl a de tip arbore. Clasa Tree<T> implementeaz a metoda GetEnumerator utiliz and un iterator. Iteratorul enumer a elementele arborelui n ordinea inx.
using System ; using System . C o l l e c t i o n s . G e n e r i c ; c l a s s Tree <T> : IEnumerable <T> { T value ; Tree <T> l e f t ; Tree <T> r i g h t ; public Tree (T v a l u e , Tree <T> l e f t , Tree <T> r i g h t ) { this . value = value ; this . l e f t = l e f t ; this . r i g h t = r i g h t ; } public IEnumerator <T> GetEnumerator ( ) { i f ( l e f t != null ) foreach (T x in l e f t ) y i e l d return x ; y i e l d return v a l u e ; i f ( r i g h t != null ) foreach (T x in r i g h t ) y i e l d return x; } } c l a s s Program { s t a t i c Tree <T> MakeTree<T>(T [ ] items , i n t l e f t , i n t r i g h t ) { i f ( l e f t > r i g h t ) return null ; int i = ( l e f t + r i g h t ) / 2 ; return new Tree <T>( i t e m s [ i ] , MakeTree ( items , l e f t , i 1 ) , MakeTree ( items , i + 1 , r i g h t ) ) ; } s t a t i c Tree <T> MakeTree<T>(params T [ ] i t e m s ) { return MakeTree ( items , 0 , i t e m s . Length 1 ) ; } // The o u t p u t o f t h e program i s : // 1 2 3 4 5 6 7 8 9 // Mon Tue Wed Thu F r i S a t Sun // s t a t i c void Main ( )

160
{

CAPITOLUL 5. ITERATORI

Tree <int > i n t s = MakeTree ( 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ) ; foreach ( i n t i in i n t s ) C o n s o l e . Write ( " {0} " , i ) ; C o n s o l e . WriteLine ( ) ; Tree <string > s t r i n g s = MakeTree ( " Mon " , " Tue " , " Wed " , " Thu " , " Fri " , " Sat " , " Sun " ) ; foreach ( s t r i n g s in s t r i n g s ) C o n s o l e . Write ( " {0} " , s ) ; C o n s o l e . WriteLine ( ) ; } }

Metoda GetEnumerator poate transformat a ntr-o clasa enumerator generat a de compilator, care ncapsuleaz a codul blocului iterator a sa cum este ar atat n exemplul de mai jos.
c l a s s Tree <T> : IEnumerable <T> { ... public IEnumerator <T> GetEnumerator ( ) { return new Enumerator1 ( t h i s ) ; } sealed c l a s s Enumerator1 : IEnumerator <T> , IEnumerator { Node<T> this ; IEnumerator <T> left , right ; int state ; T current ; public Enumerator1 ( Node<T> t h i s ) { this . t h i s = this ; } public T Current { g e t { return current ; } } public bool MoveNext ( ) { try { switch ( s t a t e ) { case 0 : s t a t e = 1; i f ( t h i s . l e f t == null ) goto yield value ; left = t h i s . l e f t . GetEnumerator ( ) ; goto case 1 ; case 1 : s t a t e = 2; if (! l e f t . MoveNext ( ) ) goto left dispose ; current = l e f t . Current ; state = 1; return true ; left dispose : s t a t e = 1; l e f t . Dispose ( ) ; yield value :

5.3. METODA GETENUMERATOR

161

current = t h i s . value ; state = 2; return true ; case 2 : s t a t e = 1; i f ( t h i s . r i g h t == null ) goto end ; right = t h i s . r i g h t . GetEnumerator ( ) ; goto case 3 ; case 3 : s t a t e = 3; i f ( ! r i g h t . MoveNext ( ) ) goto right dispose ; current = r i g h t . Current ; state = 3; return true ; right dispose : s t a t e = 1; r i g h t . Dispose ( ) ; end : state = 4; break ; } } finally { i f ( s t a t e < 0) Dispose ( ) ; } return f a l s e ; } public void D i s p o s e ( ) { try { switch ( s t a t e ) { case 1 : case 2: l e f t . Dispose ( ) ; break ; case 3 : case 3: r i g h t . Dispose ( ) ; break ; } } finally { state = 4; } } object IEnumerator . Current { g e t { return Current ; } } void IEnumerator . R e s e t ( ) {

162

CAPITOLUL 5. ITERATORI
throw new NotSupportedException ( ) ; } }

Elementele generate temporar de compilator pentru ecare instruct iune foreach si right ale obiectului enumerator. C ampul sunt promovate n c ampuri left state al obiectului enumerator este actualizat astfel nc at metoda Dispose() corect a s a e apelat a n mod corect atunci c and apare o eroare. Nu este posibil a rescrierea codului utiliz and o structur a simpl a de tip foreach.

S-ar putea să vă placă și