Sunteți pe pagina 1din 159

2. Introducere n Visual Studio .

NET
Cursul de Medii i Tehnologii de Programare i propune s prezinte aspecte ale programrii
.NET utiliznd limbajul C#, ns este conceput astfel nct s nu prezinte exclusiv acest limbaj
de programare, ci face, pe alocuri, comparaii cu limbajul Visual Basic, punctnd diferenele
dintre cele dou limbaje, avantajele i dezavantajele specifice lor. Astfel, vei putea s v
facei o idee mai bun asupra celor dou limbaje de programare i s l alegei, n aplicaiile
pe care le vei dezvolta ulterior, pe acela care se va potrivi cel mai bine stilului dumneavoastr de programare.

2.1. Limbajele Visual Basic i Visual C#


Limbajele de programare Visual Basic i C# pot fi utilizate pentru multe categorii de aplicaii,
cum ar fi site-uri web, aplicaii dektop, jocuri, aplicaii mobile sau utilitare n linie de
comand. Dintre acestea dou, n ultima decad, C# a fost, poate, limbajul cel mai des folosit
de ctre dezvoltatorii de aplicaii Windows, astfel c atunci cnd Microsoft a anunat c
Windows 8 va introduce un nou stil de aplicaii optimizate pentru dispozitive cu ecran tactil,
nu a fost o surpriz faptul c ele au fost printre cele patru limbaje de programare care ofer
suport complet pentru aplicaiile Metro (celelalte dou fiind C++ i JavaScript).
Limbajul Visual Basic deriv din limbajul BASIC (Beginner's All-purpose Symbolic
Instruction Code), sau, mai precis, din versiunea Microsoft a limbajului BASIC QuickBasic.
Prima dat cnd a aprut, Visual Basic a revoluionat programarea Windows. Prin tratarea
multor aspecte ale procesrii evenimentelor Windows, acesta a permis programatorilor s
se concentreze asupra detaliilor specifice aplicaiilor n loc s se risipeasc n probleme de
rutin ce in de programarea Windows.
n ceea ce privete stilul de programare, Visual Basic a urmrit o cale diferit fa de alte
limbaje, precum cele din familia limbajelor C, anume aceea de a oferi un mediu de
programare mai productiv i, n general, o sintax mai intuitiv. n orice caz, sintaxa Visual
Basic nu era prea recomandat celor care doreau s dezvolte aplicaii orientate pe obiecte.
Dezvoltatorii software puteau, totui, s construiasc aplicaii sigure, fiabile i extensibile,
ns aveau nevoie de ceva experien.
Visual Studio .NET a reuit s rezolve multe dintre deficienele versiunilor anterioare. Astfel,
Visual Basic conine numeroase mbuntiri, apropiindu-se ca stil de programare de C++,
dar, n acelai timp, pstrnd sintaxa specific limbajului. Visual Basic .NET conine
modificri menite s-l alinieze la CLR (Common Language Runtime) i la celelalte limbaje de
programare .NET. Astfel, include o nou modalitate de tratare a erorilor, sintaxe noi pentru
declaraii i iniializri de variabile, suprancrcarea funciilor i a subrutinelor i un model
mai puternic pentru crearea claselor care include motenire real (comparativ cu versiunile
anterioare ale limbajului, care permiteau declaraii de clase, ns nu i mecanisme de
motenire).
Versiunile mai noi de Visual Basic .NET adaug faciliti noi care fac din Visual Basic un
limbaj mai puternic ca oricnd. Astfel, acesta include noi faciliti de limbaj i mbuntiri
specifice programrii orientate pe obiecte.
Visual Basic .NET poate fi vzut ca o evoluie a clasicului Visual Basic, implementat ns pe
Microsoft .NET Framework. Introducerea acestuia a generat unele controverse n rndul
comunitii de dezvoltatori prin faptul c Visual Basic a suferit modificri majore care rup
compatibilitatea cu versiunile anterioare (compatibilitatea de sus n jos). Proiectele mai

Medii i Tehnologii de Programare curs

vechi, scrise Visual Basic, pot fi importate n .NET folosind un wizard dedicat acestui scop,
excepie fcnd, printre altele, secvenele de cod care acceseaz baze de date prin alte
tehnologii dect Microsoft ADO (ActiveX Data Objects).
Limbajul C# (C Sharp) este un limbaj relativ nou, prima versiune a acestuia fiind introdus
de abia n anul 2002 odat cu apariia Visual Studio .NET 2002. n anul 2012, odat cu Visual
Studio 2012 limbajul C# a ajuns la versiunea 5.0 i la 10 ani de existen. Numele limbajului
provine de la limbajul de programare C. Sharp este un semn care, n notaia muzical,
indic faptul c nota la care este ataat se interpreteaz cu un semiton mai sus (diez). Pe de
alt parte, n muzic C, este echivalentul notei Do.
C# este un limbaj avnd o sintax orientat pe obiecte, bazat pe C++, care include de
asemenea aspecte specifice ctorva limbaje de programare, n special Delphi i Java
(proiectul C# a fost condus de ctre Anders Hejlsberg, cel care anterior a condus proiectul
Delphi), fiind puse accente speciale pe simplificare, flexibilitate i robustee. Prin acestea s-a
urmrit ca programatorii familiarizai deja cu limbajele C i C++ s poat face uor trecerea
la C#.
Pentru a nelege un limbaj, este util compararea acestuia cu celelalte alternative existente,
apoi se poate opta pentru varianta potrivit n cunotin de cauz. Cel mai apropiat
competitor pentru C# este Visual Basic, un alt limbaj nativ .NET care ofer aproximativ
aceleai beneficii ca C#. n acest caz diferena dintre cele dou ine mai mult de sintax. C#
face parte din familia de limbaje C, iar dac suntei familiarizai cu cel puin un limbaj dintre
acestea (C, C++, Java, JavaScript) v vei simi ca acas cu sintaxa C#. Dac, ns, nu
cunoatei niciunul dintre aceste limbaje sau dac suntei familiarizat cu versiunile mai vechi
de Visual Basic sau cu variantele sale de scripting (VBA) atunci versiunea .NET a Visual Basic
va fi cu siguran mai uor de nvat.
O mare parte a puterii limbajelor .NET (ne referim aici n principal la C# i Visual Basic)
provine din gama larg de tehnici de programare pe care le suport. De exemplu, ofer
caracteristici de programare orientat pe obiecte, generice (generics) i programare funcional. Ofer caracteristici de lucru cu liste i mulimi prin LINQ, iar cele mai recente versiuni a
limbajelor adaug suport intrinsec pentru programare asincron. Unele dintre cele mai importante beneficii ale utilizrii limbajelor .NET sunt date de motorul de execuie a programelor care ofer servicii precum verificarea tipurilor la rulare, tratarea excepiilor, gestiunea
firelor de execuie i managementul automat al memoriei. La rularea aplicaiilor intr n
funcie un colector de gunoaie (garbage collector) care elibereaz dezvoltatorii de o mare
parte a muncii asociate cu recuperarea resurselor de memorie pe care programul nu le mai
folosete.
Desigur, limbajele nu exist ntr-un vacuum sunt eseniale bibliotecile care s ofere o gam
larg de caracteristici (trebuie s ofere acces deplin i convenabil la serviciile care stau la
baza funcionrii platformei). n acest sens limbajele .NET sunt foarte puternice, iar aceasta
datorit .NET Framework. Toate limbajele de programare .NET au acces la aceleai biblioteci
i ierarhii de clase, astfel c, practic, nu exist diferene ntre aplicaii similare scrise n
limbaje .NET diferite.

2.2. .NET Framework


nainte ca Microsoft s lanseze platforma .NET, dezvoltatorii software care creau aplicaii
pentru familia de sisteme de operare Windows adeseori utilizau modelul de programare
COM (Component Object Model). Acest model permitea dezvoltatorilor software s construiasc biblioteci de cod care s fie partajate ntre diferite limbaje de programare. De exemplu,
un programator C++ putea construi o bibliotec COM care s fie utilizat de ctre un programator Visual Basic. Acest caracter independent de limbaj al COM a fost cu siguran util; n
orice caz, COM a fost afectat de infrastructura complicat, un model fragil de implementare i
era posibil numai pe sistemul de operare Windows.

Introducere n Visual Studio .NET

n ciuda complexitii i limitrilor COM, au fost create cu succes nenumrate aplicaii bazate
pe aceast arhitectur. Totui, n prezent majoritatea aplicaiilor Windows nu mai sunt
create cu modelul COM ci, mai degrab, aplicaiile desktop, serviciile sistemului de operare i
bibliotecile de componente reutilizabile sunt create utiliznd platforma .NET.
.NET Framework reprezint o platform software pentru dezvoltarea de sisteme att pentru
familia de sisteme de operare Windows ct i pentru Mac OS X i diferite distribuii de
Unix/Linux. Iat o trecere n revist a ctorva dintre caracteristicile principale ale .NET:

Interoperabilitate cu codul existent: fiiere binare COM pot interopera cu software


.NET mai nou.

Suport pentru numeroase limbaje de programare: pot fi create aplicaii .NET


folosind orice numr de limbaje de programare (C#, Visual Basic, F#, C++ etc.)

Un motor de execuie comun pentru toate limbajele .NET: un aspect al acestui motor
l reprezint un set bine definit de tipuri de date pe care toate limbajele .NET le
neleg.

Integrarea limbajului: .NET suport motenire inter-limbaj, tratarea excepiilor


inter-limbaj i depanarea codului inter-limbaj. De exemplu, putei defini o clas n C#
i s extindei acest tip n Visual Basic.

O bibliotec cuprinztoare de clase: aceast bibliotec asigur protecie fa de


complexitatea apelurilor API de nivel jos i ofer un model obiect consistent utilizat
de toate limbajele .NET.

Un model de implementare simplificat: spre deosebire de COM, bibliotecile .NET nu


sunt nregistrate n registrele sistemului. Mai mult, platforma .NET permite existena
n armonie a mai multor versiuni ale aceluiai *.dll pe o singur main.

Microsoft a creat .NET Framework pentru a face mai uoar dezvoltarea de aplicaii pentru
diversele versiuni ale sistemului de operare Windows. Din acest motiv dezvoltarea aplicaiilor n .NET ar trebui s fie mai facil dect n versiunile anterioare. .NET Framework
mpreun cu limbajele .NET pot fi instrumente puternice, iar tot ce avei de fcut este s
descoperii modului n care acestea conlucreaz prin intermediul mediului de dezvoltare
integrat Visual Studio.
.NET Framework este plasat ntre limbajul de programare (Visual Basic, C# etc.) i sistemul
de operare (de la Windows 98 i Windows NT pn la Windows 8 i Windows Server 2012,
sau orice alte sub-versiuni ale acestora, cum ar fi cele destinate dispozitivelor mobile). .NET
Framework ofer funcionaliti specifice sistemului de operare Windows, furniznd ns i
biblioteci care extind aceste funcionaliti (calcule matematice, criptografie, accesarea bazelor de date etc.). Figura 2.1 ilustreaz vizual relaia ntre toate nivelele din .NET Framework.
O bun parte din dificultile pe care le ntmpin programatorii cnd migreaz la .NET
Framework provin deruta provocat de terminologia specific. Pentru eliminarea oricror
confuzii vom expune n continuare principalii termenii utilizai n dezvoltarea aplicaiilor
.NET. Din punctul de vedere al programatorului, n linii mari, .NET poate fi neles ca un
mediu de execuie i o bibliotec cuprinztoare de clase.

Medii i Tehnologii de Programare curs

Figura 2.1. Ierarhia .NET Framework (.NET Framework 2.0 anul 2005).

Base Class Library (BCL). Platforma .NET furnizeaz o bibliotec de clase care este disponibil tuturor limbajelor de programare .NET. Aceast bibliotec de clase ncapsuleaz nu
numai primitive precum fire de execuie, operaii cu fiiere, sisteme de redare grafic i
interaciunea cu diverse dispozitive hardware externe, ci furnizeaz i suport pentru anumite servicii solicitate de majoritatea aplicaiilor din lumea real.
Bibliotecile de clase definesc tot ceea ce avei nevoie pentru dezvoltarea oricrui tip de
aplicaie. De exemplu, putei utiliza ASP.NET pentru construirea site-urilor web, WCF pentru
dezvoltarea de servicii n reea, WPF pentru aplicaii desktop cu interfee grafice .a.m.d. De
asemenea, BCL permit interaciunea cu documente XML, sistemul local de fiiere directoare,
comunicarea cu baze de date relaionale (ADO.NET) etc. Pentru scrierea aplicaiilor programatorii pot utiliza biblioteca de clase mpreun cu codul scris de ei nii.
Programele scrise pentru .NET Framework sunt executate ntr-o main virtual care gestioneaz programele n timpul rulrii din punct de vedere al necesitilor acestora. Aceast
main virtual este cunoscut sub denumirea de Common Language Runtime (CLR) i
face parte din .NET Framework. Datorit faptului c programul va rula pe maina virtual
(CLR) programatorul nu are nevoie s ia n considerare tipul procesorului de pe calculatorul
care va rula aplicaia. Toate programele .NET ruleaz sub supervizarea CLR, fiind garantate
anumite proprieti i comportamente n ceea ce privete gestiunea memoriei, securitatea i
tratarea excepiilor.
.NET Framework utilizeaz o arhitectur pe nivele, la baza creia se situeaz Windows API
(vezi Figura 2.1). .NET Framework ofer o vedere orientat pe obiecte a funciilor sistemului
de operare, fr ns a le nlocui, astfel c majoritatea apelurilor din .NET Framework sunt
rezolvate n final ca apeluri ntr-unul din DLL-urile nucleului Windows. CLR reprezint primul nivel care aparine lui .NET Framework, fiind responsabil pentru serviciile de baz .NET,
precum gestiunea memoriei, colectarea de gunoaie, tratarea structurat a excepiilor, coordonarea firelor de execuie i efectuarea verificrilor de securitate. Ar trebui s imaginai
CLR ca fiind supervizorul tuturor aplicaiilor .NET: nu interacionai niciodat direct cu CLR,
ns toate aplicaiile voastre sunt controlate de acesta.
CLR ofer suport pentru mai multe limbaje de programare, asigurnd un mediu de execuie
robust i sigur. De asemenea acesta simplific procesul de distribuire i de management al
aplicaiei (scpai de comarul DLL).
CLR ruleaz o form de cod octet numit Common Intermediate Language (CIL), cunoscut i sub denumirea de Microsoft Intermediate Language (MSIL). Procesul de rulare a
unui program scris ntr-unul din limbajele .NET este ilustrat n Figura 2.2.

Introducere n Visual Studio .NET

Figura 2.2. Diagrama CLR

Intermediate Language (IL sau MSIL). Spre deosebire de limbajele de programare


tradiionale compilatoarele .NET nu produc cod nativ care s poat fi executat direct de ctre
procesor. n schimb, acestea produc aa-numitul cod IL, care reprezint un soi de limbaj
main pentru un procesor virtual care nu corespunde niciunui procesor fizic. Dei codul IL
este la un nivel mai jos dect majoritatea limbajelor de programare moderne, acesta este la
un nivel mai nalt dect limbajul de asamblare pur. IL este un limbaj orientat pe stiv (stackoriented) care nu adreseaz direct regitrii procesorului i nu are legtur cu conceptele
specifice limbajelor de nivel nalt (stringuri, excepii sau crearea obiectelor).
Limbajele .NET. Dei limbajele Visual Basic i Visual C# (spre exemplu) au sintax diferit i
cuvinte cheie diferite, ele sunt n linii mari echivalente, ambele permind utilizarea .NET
Framework la capacitate maxim. n plus, toate limbajele .NET Framework sunt compilate la
cod MSIL, care apoi este compilat n cod nativ. Din aceast cauz, nu pot fi sesizate diferene
notabile ntre limbaje diferite. O excepie de la aceast regul este cazul unei aplicaii care
utilizeaz pointeri i cod nesigur (unsafe code). Aceasta poate rula semnificativ mai rapid
dect o aplicaie echivalent scris n C# sau Visual Basic.
Compilatorul Just-in-Time (JIT Compiler). Deoarece nici un procesor nu poate executa
cod IL, CLR trebuie s l converteasc n cod nativ n timpul rulrii programului prin lansarea
compilatorului JIT i transmiterea ctre acesta a adresei funciei cu care pornete aplicaia
(de obicei, ntr-o aplicaie Visual Basic, procedura Sub Main). Atunci cnd procedura
principal apeleaz alte metode, .NET utilizeaz compilatorul .NET pentru transformarea
codului IL din aceste metode n cod nativ, apoi execut codul nativ. Aceast compilare din
zbor este efectuat numai o singur dat pentru fiecare metod pe durata de via a
aplicaiei, deoarece codul nativ este pstrat n memorie i reutilizat atunci cnd o metod
este apelat din nou.
Common Type Specifications (CTS). Acest set de specificaii dicteaz modul n care un tip
de dat expune cmpuri, metode, proprieti i evenimente; de asemenea definete modul n
care un tip de dat poate moteni alt tip de dat i poate suprancrca membrii acestuia.
Datorit faptului c toate limbajele .NET recunosc aceste specificaii, acestea pot face schimb
de date, pot utiliza sau moteni tipuri definite ntr-un alt limbaj. Spre exemplu, putei scrie o
clas Visual Basic care s moteneasc o alt clas scris n C#, i putei scrie o clas C# care
implementeaz o interfa definit Visual Basic.
Common Language Specifications (CLS). Acest set de specificaii dicteaz minimul de
caracteristici pe care un limbaj de programare trebuie s le aib pentru a face parte din
categoria limbajelor .NET. Spre exemplu, toate limbajele .NET trebuie s poat opera cu
tipuri de date primitive precum stringuri sau ntregi, i trebuie s fie capabile s proceseze o

Medii i Tehnologii de Programare curs

excepie care apare ca urmare a unei erori. Dac vei construi tipuri .NET care expun numai
caracteristici conforme cu CLS, putei s fii siguri c toate limbajele .NET le pot consuma.
Dimpotriv, dac utilizai un tip de dat sau structur de programare din afara CLS, nu putei
avea garania c toate limbajele .NET vor putea interaciona cu biblioteca dumneavoastr
.NET.
Cod gestionat i cod negestionat. Se spune c aplicaiile .NET execut cod gestionat
deoarece ruleaz sub controlul CLR i sunt mpiedecate s ruleze cod nesigur care poate
afecta rularea sistemului sau poate compromite datele utilizatorilor. Spre exemplu, CLR
trebuie s previn accesarea fiierelor sistem sau a regitrilor sistem n cazul n care
aplicaia a fost lansat dintr-o locaie Internet care nu este de ncredere. Prin contrast,
aplicaiile non-.NET, cum ar fi cele scrise n Visual Basic 6, execut cod negestionat, sau cod
nativ. Dintre toate limbajele de programare de la Microsoft, numai C++ poate produce att
cod gestionat ct i cod negestionat, ns chiar i dezvoltatorii C++ ar trebui s recurg la
scrierea de cod negestionat numai dac este strict nevoie spre exemplu, pentru efectuarea
operaiilor low-level deoarece numai codul gestionat beneficiaz de avantajele platformei
.NET.
n lumea .NET, limbajele de programare devin doar o modalitate de a interaciona cu .NET
Framework i, n consecin, cu sistemul de operare Windows. Toate programele au nevoie
de un set de reguli stabilite pentru interpretarea fluxului de instruciuni din cadrul programelor. Limbajul de programare .NET furnizeaz un set de reguli, iar .NET Framework pune la
dispoziie obiectele i evenimentele cu care se poate interaciona.
n esen, orice lucru pe care Windows l poate face este cuprins n cadrul .NET Framework.
n mod specific, .NET Framework d un nume programatic fiecrui obiect i eveniment pe
care Windows l poate controla. Orice programator poate utiliza acel nume pentru a se referi
n cod la orice are legtur cu sistemul de operare. De exemplu, dorii s i transmitei
imprimatei s efectueze dou copii ale documentului vostru? ncercai:
My.Computer.Printers.DefaultPrinter.PrinterSettings.Copies = 2

Avei nevoie s desenai pe ecran elemente grafice de culoare albastr? ncercai:


System.Drawing.Brushes.Blue

Dei Microsoft a inventat limbajul C#, acesta este documentat de organismul de standardizare ECMA (European Computer Manufacturers Association), permind oricui s implementeze limbajul de programare C#. Acest lucru nu este ceva ipotetic. Proiectul open source
Mono (http://www.mono-project.com) pune la dispoziie instrumente pentru construirea
de aplicaii C# care pot rula pe Linux, iOS i Android. Astfel, Mono poate rula fiierele binare
obinute pe platforme Windows cu Visual Studio .NET fr a mai fi nevoie de recompilarea
acestora. n Figura 2.3 este prezentat mediul MonoDevelop, un IDE GNOME gratuit, proiectat
special pentru programarea n C# i alte limbaje .NET.

Introducere n Visual Studio .NET

Figura 2.3. Scrierea unei aplicaii C# folosind IDE-ul MonoDevelop.

Medii i Tehnologii de Programare curs

3. Mediul de dezvoltare integrat Visual


Studio 2012

3.1. Scurt prezentare a mediului de dezvoltare integrat (IDE)


Imediat dup pornirea Visual Studio 2012 acesta este pregtit pentru a ncepe s lucrai cu el
(Figura 3.1).

Figura 3.1. Mediul Visual Studio 2012 imediat dup pornire.

n continuare putei alege fie s creai un proiect nou, fie s deschidei unul dintre ultimele
proiecte deschise n Visual Studio.
n funcie de componentele selectate la instalare, vei putea crea proiecte Visual Studio
dintre cele mai diverse, n funcie de limbajul de programare ales (Visual Basic, C#, Visual
C++, Visual F# sau JavaScript). Visual Basic i C# sunt singurele dou limbaje care permit
crearea acelorai tipuri de proiecte (i a celor mai multe dintre limbajele .NET).
Astfel, pentru proiecte Visual Basic sau C# putei crea de la aplicaii Windows uzuale
(Windows Forms Application, Console Application, biblioteci de clase, servicii Windows,
controale personalizate etc.), pn la aplicaii web Windows Store, aplicaii web, aplicaii
WCF (Windows Communication Foundation), aplicaii Silverlight, aplicaii Windows Phone
.a.m.d. (vezi Figura 3.2).

Introducere n Visual Studio .NET

De asemenea, putei s creai aplicaii Visual Studio 2012 pornind de la o serie de modele
predefinite sau exemple online.

Figura 3.2. Dialogul pentru crearea unui proiect nou n Visual Studio 2012.

Figura 3.3 prezint interfaa mediului de dezvoltare integrat Visual Studio 2012 imediat
dup crearea unui proiect nou C# de tip Windows Forms Application.

3
5
4

7
Figura 3.3. Configuraia iniial a interfeei mediului de dezvoltare Visual Studio 2012.

Interfaa este extrem de configurabil, astfel nct poate s arate complet diferit dac
rearanjai dup bunul plac elementele de interfa. Orice s-ar ntmpla, putei reveni la

Medii i Tehnologii de Programare curs

modul iniial de organizare a interfeei mediului de dezvoltare accesnd comanda de meniu


Window -> Reset Window Layout.
Elementele cheie ale mediului de dezvoltare vizibile n Figura 3.3 sunt numerotate dup cum
urmeaz.
1. Meniuri conin comenzi standard Visual Studio. Acestea manipuleaz elementele
soluiei curente i ale modulelor componente ale acesteia. Visual Studio activeaz sau
dezactiveaz meniurile i comenzile disponibile n funcie de obiectele selectate curent. n
Figura 3.3, este deschis Form Designer (marcat cu numrul 4), astfel c mediul de dezvoltare
afieaz meniurile i comenzile pentru proiectarea interfeelor ferestrelor.
2. Toolbars Barele de instrumente conin comenzile cel mai frecvent utilizate. Aceleai
comenzi pot fi disponibile att n meniuri ct i n barele de instrumente (pentru o apelare
mai rapid). Mediul de dezvoltare integrat definete o multitudine de bare de instrumente
printre care Standard, Layout, Build, Debug i Text Editor. Putei construi de asemenea
propriile bare de instrumente pentru accesarea rapid a instrumentelor favorite.
3. Toolbox Caseta cu instrumente conine instrumente potrivite cu obiectul curent selectat
i cu tipul de proiect la care lucrai. n Figura 3.3 este selectat modul Form Designer, astfel c
Toolbox va conine instrumentele potrivite pentru un Form Designer: controale i
componente uzuale Windows, plus instrumente din alte categorii: Menus & Toolbars, Data,
Components, Reporting, etc. Pentru alte categorii de proiecte acestea pot s difere. Spre
exemplu, un proiect de tip Web Application va afia numai controale i componente Web.
4. Form Designer permite proiectarea designului grafic al unei ferestre din cadrul
proiectului. Acest spaiu (spaiul principal de lucru al mediului) este mprit ntre
designerul de ferestre i editorul de cod. Dac adugai pe suprafaa ferestrei un control din
caseta cu instrumente, putei utiliza fereastra de proprieti (marcat cu 6) pentru modificarea proprietilor controlului nou desenat. n Figura 3.3 nu este selectat nici un control,
astfel c fereastra de proprieti va afia proprietile ferestrei.
5. Solution Explorer acesta v permite s gestionai fiierele asociate cu soluia curent.
Spre exemplu, n Figura 3.3, putei selecta Form1.cs din Solution Explorer apoi s dai click
pe butonul
View Code (al treilea de la dreapta n partea de sus a ferestrei Solution
Explorer) pentru a deschide editorul de cod asociat ferestrei. Putei de asemenea s dai
click dreapta pe un obiect n Solution Explorer pentru a avea acces la comenzile asociate
acelui obiect.
6. Properties fereastra de proprieti v permite modificarea proprietilor unui obiect n
timpul desenrii interfeei (design time). Atunci cnd selectai un obiect n Form Designer
sau n Solution Explorer, fereastra de proprieti afieaz proprietile acelui obiect. Pentru
a modifica valoarea unei proprieti, dai click pe proprietate i introducei noua valoare.
7. Output / Error List fereastra Output poate afia mesaje de stare pentru diferite
caracteristici din mediul de dezvoltare integrat. Fereastra Error List afieaz erorile si
avertismentele (warnings) din proiectul curent. Spre exemplu, dac o variabil este folosit
fr a fi declarat, aceast list va afia la compilare aceast eroare. Dac o variabil este
declarat, dar nu este folosit, lista va afia la compilare un avertisment n acest sens.

3.1.2. Soluii i proiecte Visual Studio


Un proiect reprezint un grup de fiiere care produc la ieire un anumit rezultat. Aceast
ieire poate fi, printre altele, un fiier executabil, o pagin web, un DLL care poate fi folosit n
cadrul altor proiecte sau un control grafic care s fie utilizat pe suprafaa altor ferestre.
O soluie reprezint un grup format dintr-unul sau mai multe proiecte care sunt gestionate
mpreun. Spre exemplu, presupunem c dezvoltm o aplicaie server care ofer acces la o
anumit baz de date. De asemenea, dezvoltm o aplicaie client care va fi utilizat de mai

10

Introducere n Visual Studio .NET

multe persoane pentru interogarea aplicaiei server. Datorit strnsei legturi dintre aceste
dou proiecte, este firesc ca ele s fie gestionate ntr-o singur soluie. Atunci cnd soluia va
fi deschis, vei avea acces la toate fiierele din cadrul celor dou proiecte.
Att proiectele ct i soluiile pot include fiiere asociate, care pot fi utile pentru dezvoltarea
aplicaiilor, dar care nu vor face parte din produsul final compilat. La dublu click pe numele
fiierelor, acestea vor fi deschise cu aplicaia potrivit. Spre exemplu, un fiier cu extensia
.docx va fi deschis de ctre Visual Studio cu Microsoft Word.
Pentru asocierea unuia din aceste fiiere cu proiectul sau cu soluia dai click dreapta pe
numele proiectului/soluiei n Solution Explorer, selectai comanda Add -> Existing Item
(sau din meniul Project -> New Item). Se va deschide o fereastr dialog pentru selectarea
fiierului dorit.
Pentru a aduga o nou component software la proiect dai click dreapta pe numele
proiectului n Solution Explorer, selectai comanda Add -> New Item (sau din meniul Project
-> New Item) i utilizai fereastra dialog pentru selectarea noii componente pe care dorii s
o adugai la proiect (vezi Figura 3.4).

Figura 3.4. Adugarea unei componente noi la proiect

Un scenariu frecvent utilizat este acela n care codul surs este plasat ntr-un proiect,
iar documentaia n alt proiect din aceeai soluie.

3.1.1. Structura meniului


n continuare vor fi descrise meniurile cuprinse n mediul de dezvoltare Visual Studio 2012,
nencercnd ns o prezentare exhaustiv a comenzilor cuprinse n cadrul acestora. Ne vom
axa n consecin asupra unor comenzi mai importante, considernd inutil prezentarea
unor comenzi uzuale sau foarte rar folosite.

11

Medii i Tehnologii de Programare curs

Meniul FILE
Meniul File conine comenzi pentru creare, deschidere, salvare i nchidere a proiectelor i a
fiierelor asociate acestora (Figura 3.5).

Figura 3.5. Meniul File cuprinde comenzi asociate cu soluia i cu fiierele acesteia

New submeniul New permite crearea unui proiect nou, site Web (ASP.NET sau Serviciu
WCF), proiect Team Foundation Server (TFS) sau fiier (text, bitmap, icon, html, clas etc.).
Comanda Project From Existing Code creeaz un proiect nou i permite alegerea fiierelor
care s fie incluse n noul proiect.
Open submeniul Open conine comenzi pentru deschiderea unei soluii, a unui proiect, site
Web, proiect TFS sau fiier. Comanda Convert permite prin intermediul unui wizard conversia proiectelor scrise n versiuni mai vechi de C# sau VB.
Save All salveaz toate fiierele modificate de la deschiderea acestora sau de la ultima
operaie de salvare.
Export Template acest wizard permite crearea unui ablon de proiect sau alte elemente
care pot fi utilizate mai trziu.
Page Setup i Print permit configurarea imprimantei, respectiv tiprirea documentului
curent. Aceste comenzi sunt activate numai cnd are sens tiprirea documentului curent. De
exemplu, sunt activate atunci cnd vizualizai un fiier text (fiier surs sau XML), ns sunt
dezactivate atunci cnd vizualizai un bitmap sau suntei n Form Designer.

Meniul EDIT
Meniul Edit (Figura 3.6) conine comenzi care manipuleaz text sau alte tipuri obiecte.
Printre acestea clasicele comenzi Undo, Redo, Copy, Cut i Paste pe care le putei gsi n
majoritatea aplicaiilor Windows.

12

Introducere n Visual Studio .NET

Figura 3.6. Meniul Edit conine comenzi pentru manipularea textului i a altor tipuri de obiecte

Cycle Clipboard Ring Clipboard ring conine ultimele elemente copiate n clipboard.
Aceast comand copiaz n locaia curent elementul anterior din clipboard ring. Prin
utilizarea repetat a acestei comenzi, putei parcurge elementele din clipboard ring pn la
gsirea celui pe care l dorii.
Go To permite poziionarea rapid pe o anume linie n fiierul surs curent.
Advanced submeniul Advanced conine comenzi pentru efectuarea unor formatri mai
complexe ale documentului, cum ar fi convertirea textului la majuscule sau minuscule, word
wrap, indentri, comentarea i decomentarea codului.
Bookmarks submeniul Bookmarks conine comenzi pentru adugarea i tergerea
marcajelor, precum i poziionarea pe marcajele deja memorate.
Outlining submeniul Outlining permite expandarea sau comprimarea seciunilor de cod,
precum i activarea sau dezactivarea acestei opiuni.
IntelliSense ofer acces la facilitile IntelliSense. Spre exemplu, comanda List Members
afieaz lista cu proprietile, metodele i evenimentele obiectului curent.
Refactor conine cteva opiuni utile pentru code refactoring. Vom expune n continuare
funciile de refactoring oferite de Visual Studio.
1) Comanda Rename este util atunci cnd dorii s redenumii o variabil sau o metod,
deoarece o redenumete n toate locurile n care aceasta este referit n codul proiectului.
2) Comanda Extract Method ofer o modalitate simpl de creare a unei metode noi pornind de la un fragment de cod.
3) Comanda Encapsulate Field ajut programatorii la crearea unei proprieti pornind de
la un cmp privat al unei clase.
4) Comada Extract Interface ofer o modalitate de creare rapid a unei interfee pornind
de la membrii unei clase, structuri sau interfee.
5) Comanda Remove Parameters ofer o modalitate mai simpl de ordonare a parametrilor unei metode, att n definiia acesteia ct i n apelurile ei.

13

Medii i Tehnologii de Programare curs

6) Comanda Reorder Parameters ofer o modalitate mai simpl de tergere a unuia sau a
mai multor parametri ai unei metode, att n definiia acesteia ct i n apelurile ei.

Meniul VIEW
Meniul View (Figura 3.7) conine comenzi care permit ascunderea sau afiarea diverselor
ferestre sau bare de instrumente din cadrul mediului de dezvoltare integrat Visual Studio
2012.

Figura 3.7. Meniul View permite afiarea i ascunderea ferestrelor i a barelor cu instrumente Visual Studio

Code comanda Code deschide fiierul selectat ntr-un editor de cod. Spre exemplu, pentru
editarea codului asociat unui formular (de exemplu, Form1), dai click pe formular
(Form1.cs pentru proiect C#, sau Form1.vb pentru proiect Visual Basic) n Solution
Explorer i selectai View Code.
Designer comanda Designer deschide fiierul selectat ntr-un editor grafic, dac exist
vreunul definit pentru acel tip de fiier. Spre exemplu, dac fiierul este un formular, Visual
Studio l deschide ntr-un editor grafic de formulare. Dac fiierul este o clas sau o alt
component de cod, meniul View ascunde aceast comand deoarece Visual Studio nu
dispune de un editor grafic pentru acest tip de fiiere.
Open deschide elementul selectat cu editorul implicit pentru acesta.
Open With deschide elementul selectat cu un editor la alegere. Spre exemplu, putei
deschide codul asociat unui formular cu un editor de text.

14

Introducere n Visual Studio .NET

Tab Order n mod implicit, n Visual Studio 2012, aceast comand nu apare n meniul
View, ns poate fi adugat prin dialogul deschis de comanda Tools -> Customize. Dac un
formular conine controale, comanda Tab Order afieaz deasupra fiecrui control o cifr
care indic ordinea n care vor fi selectate controalele la apsarea tastei TAB (n timpul
rulrii). Pentru a defini aceast ordine trebuie s dai click pe controale n ordinea dorit.

Figura 3.8. Stabilirea ordinii de selectare a controalelor cu comanda Tab Order

Meniul PROJECT
Meniul Project (Figura 3.9) conine comenzi care v permit adugarea, respectiv tergerea
de elemente n/din proiectul curent. n funcie de elementul selectat n Solution Explorer
difer i comenzile disponibile n acest meniu.

Figura 3.9. Meniul Project v permite adugarea de fiiere i referine n proiectul curent

Iat o descriere a comenzilor asociate cu meniul Project:


Add New Item afieaz dialogul din Figura 3.4. Dialogul permite selecia dintr-o gam
larg de elemente printre care fiiere text, fiiere bitmap i module de clas.
Show All Files aceast comand face ca Solution Explorer s afieze lista cu fiierele care,
n mod normal, sunt ascunse. Acestea includ fiiere de resurse asociate formularelor, clase
pariale ascunse cum ar fi secvene de cod generate automat, fiiere din directoarele OBJ i
BIN, care sunt create automat de Visual Studio atunci cnd compileaz programul. n mod
normal nu avei nevoie s interacionai direct cu aceste fiiere, astfel c ele sunt ascunse.
Selectai aceast comand pentru afiarea lor, apoi selectai-o din nou pentru ascunderea lor.
Add Reference permite n prim faz selectarea categoriei unui obiect extern, a unei clase,
sau a unei biblioteci pe care dorii s o gsii. Putei aduga o referin la o component
.NET, la o component COM (Component Object Model), cum ar fi o bibliotec ActiveX sau un
control creat n Visual Basic 6, sau la un alt proiect Visual Studio.

15

Medii i Tehnologii de Programare curs

Dup ce ai adugat o referin la un proiect, putei s accesai prin cod obiectele publice ale
referinei. Spre exemplu, dac fiierul MyMathLibrary.dll definete clasa MathTools, iar acea
clas definete funcia public Fibonacci, un proiect care are o referin la acest DLL poate
utiliza urmtoarea secven de cod:
MyMathLibrary.MathTools math_tools = new MyMathLibrary.MathTools();
MessageBox.Show("Fib(5) = " + math_tools.Fibonacci(5));

Add Service Reference afieaz un dialog prin care putei s adugai referine la servicii
Windows Communication Foundation (WCF) i ADO.NET Data.
Set as StartUp Project seteaz unul dintre proiectele unei soluii (cel curent selectat) ca
fiind proiectul care va rula implicit la rularea soluiei curente.
[Nume proiect] Properties aceast comand afieaz paginile cu proprieti ale proiectului. Proprietile vor diferi de la un tip de proiect la altul. Astfel, pentru un proiect C# de
tip Windows Forms Application pagina Application a proprietilor va fi cea din Figura 3.10.

Figura 3.10. Pagina Application a proprietilor unui proiect C#

n cazul unui proiect Visual Basic de tip Windows Forms Application pagina Application a
proprietilor acestuia va conine unele diferene, majoritatea provenind din caracteristicile
diferite pe care le pune la dispoziie Visual Basic fa de C# (vezi Figura 3.11).
Una dintre diferenele proprietilor unui proiect Visual Basic i ale unuia C# provine din
modul diferit prin care se indic punctul de intrare n aplicaie. n C# punctul de intrare ntro aplicaie este funcia Main. Implicit, proiectele C# conin fiierul Program.cs care o implementeaz. Pentru proiectele C# de tip Windows Forms Application funcia Main creeaz o
instan a clasei Form1 pe care o afieaz pe ecran:

16

Introducere n Visual Studio .NET

static class Program


{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}

Dac programatorul dorete s modifice fereastra de start a aplicaiei va trebui modifice


codul din funcia Main astfel nct, la pornire, programul s afieze alt fereastr.

Figura 3.11. Pagina Application a proprietilor unui proiect Visual Basic

n C# pot exista mai multe fiiere surs care s implementeze funcia Main. Din pagina de
proprieti putei indica fiierul surs care implementeaz varianta dorit de dumneavoastr (Figura 3.12).

Figura 3.12. Indicarea punctului de intrare ntr-o aplicaie C#

n cazul proiectelor Visual Basic de tip Windows Forms Application punctul de intrare n
aplicaie se definete mai simplu, selectnd n caseta Startup object fie numele ferestrei de
start (vezi Figura 3.13), fie numele unui modul de program care implementeaz funcia Main
(dac n proiect exist aa ceva).

17

Medii i Tehnologii de Programare curs

Figura 3.13. Indicarea punctului de intrare ntr-o aplicaie Visual Basic

Diferenele dintre proiectele C# i Visual Basic nu se opresc ns aici. n fereastra de proprieti a proiectelor Visual Basic se poate alege condiia de terminare a execuiei aplicaiei (vezi
Figura 3.14). Implicit, execuia aplicaiilor Visual Basic de tip Windows Forms Application se
termin atunci cnd se nchide fereastra de start (lucru valabil i pentru proiectele C#, dei
aceast opiune lipsete de pe fereastra de proprieti a acestora).

Figura 3.14. Selectarea condiiilor de nchidere a un program Visual Basic

Aceast setare implicit nu este potrivit pentru aplicaiile Visual Basic care conin mai
multe ferestre, deoarece nu este permis nchiderea ferestrei de start fr a se ncheia
execuia aplicaiei, chiar dac pe ecran se afieaz n loc alte ferestre. n acest caz se va
selecta opiunea de nchidere a aplicaiei numai atunci cnd se nchide i ultima fereastr de
pe ecran. Acest lucru se poate implementa i n C#, ns cu ceva mai mult efort din partea
programatorului.
Pe pagina Compile a proiectelor Visual Basic exist patru proprieti care merit o atenie
special (vezi Figura 3.13). Prima dintre ele, Option Explicit determin din partea Visual
Basic cerina ca toate variabilele s fie declarate nainte de a fi utilizate. Inactivarea acestei
opiuni poate conduce uneori la bug-uri subtile. Spre exemplu, urmtoarea secven de cod
intenioneaz s afieze o list a numerelor pare ntre 0 i 10. Din nefericire, o greeal de
tastare face ca funcia Debug.WriteLine s tipreasc valoarea variabilei j, nu a lui i. Deoarece
j nu este iniializat, codul produce la ieire o list de valori nule. Dac setai Option Explicit la
valoarea On, compilatorul va semnala faptul c variabila j nu este declarat, iar problema
devine uor de rezolvat.
For i = 1 To 10
If i Mod 2 = 0 Then Debug.WriteLine(j)
Next i

Figura 3.13. Pagina Compile a proprietilor unui proiect Visual Basic conine opiuni importante pentru
controlul generrii codului

A doua opiune de compilare este Option Strict. Atunci cnd aceast opiune este inactiv,
Visual Studio permite n cod conversii implicite de la un tip de dat la altul, chiar dac
tipurile de date nu sunt ntotdeauna compatibile. Spre exemplu, Visual Basic va permite
urmtoarei secvene de cod s ncerce copierea stringului s n ntregul i. Dac textul din
string se ntmpl s reprezinte o valoare numeric, precum n primul caz, va funciona. n
cazul contrar, precum se vede n cel de al doilea caz, va aprea o eroare la rulare.

18

Introducere n Visual Studio .NET

Dim
Dim
s =
i =
s =
i =

i As Integer
s As String
10
s
Corect.
Hello
s
Incorect.

Dac activai opiunea Option Strict, Visual Studio v va avertiza cu privire la incompatibilitatea dintre cele dou tipuri de date, astfel c vei putea rezolva uor problema n timp ce
scriei codul. Vei putea utiliza funcii de conversie de date precum CInt, Int i Integer.Parse
pentru convertirea stringului la ntreg, ns va trebui s efectuai explicit aceste aciuni.
Acest lucru va duce la diminuarea ansei de apariie a erorilor de conversie.
Pentru evitarea confuziilor sau a unor sesiuni lungi i obositoare de depanare, ar trebui s
setai permanent opiunile Option Explicit (On) i Option Strict (On).
Directiva de compilare Option Compare, poate lua valorile Binary sau Text. Dac setai
Option Compare la Binary, Visual Basic compar stringurile pe baza reprezentrii lor
binare. Dac setai Option Compare la Text, Visual Basic compar stringurile folosind o
metod case-insensitive care depinde de setrile calculatorului. Compare Binary este mai
rapid, dar poate s nu produc ntotdeauna rezultatele ateptate.
Ultima directiv de compilare, Option Infer poate lua valorile On sau Off. Odat setat pe
On, este activat opiunea de deducere a tipului unei variabile locale, n cazul n care,
pentru respectiva variabil, tipul acesteia nu a fost precizat explicit (vezi Figura 3.14).

Figura 3.14. Deducerea tipului unei variabile cu directiva Option Infer

Toate cele patru opiuni de compilare pot fi setate local, la nivel de fiier, acestea avnd
prioritate fa de opiunile globale, setate la nivel de proiect.
i n C# poate fi utilizat opiunea de deducere a unei variabile. Aceasta se aplic ns numai
variabilelor locale al nivel de metod, declarndu-le ca fiind de tipul implicit var. Compilatorul este cel care determin tipul variabilei n funcie de valoarea care i este atribuit.
Practic este acelai lucru ca i cnd ai fi declarat variabila ca fiind de tipul dedus. Exemplu:
static void Main(string[] args)
{
var a = 5.23;
var b = 5.23f;
var c = "text";
var d = 5;
Console.WriteLine("Variabila
Console.WriteLine("Variabila
Console.WriteLine("Variabila
Console.WriteLine("Variabila
}

a
b
c
d

este
este
este
este

de
de
de
de

tipul
tipul
tipul
tipul

{0}",
{0}",
{0}",
{0}",

a.GetType().ToString());
b.GetType().ToString());
c.GetType().ToString());
d.GetType().ToString());

La rularea aplicaiei va fi afiat urmtorul rezultat:


Variabila
Variabila
Variabila
Variabila

a
b
c
d

este
este
este
este

de
de
de
de

tipul
tipul
tipul
tipul

System.Double
System.Single
System.String
System.Int32

Dac n Solution Explorer selectai numele soluiei apoi apelai comanda Properties din
meniul Project, Visual Studio afieaz fereastra cu proprietile soluiei (Figura 3.15). n

19

Medii i Tehnologii de Programare curs

cazul n care soluia conine mai multe proiecte putei alege care s fie proiectul de start
(acesta va fi compilat i depanat prima dat).

Figura 3.15. Pagina de proprieti a soluiei.

Meniul BUILD
Meniul Build (Figura 3.16), conine comenzi care permit compilarea proiectelor dintr-o
soluie.

Figura 3.16 Meniul Build permite compilarea proiectelor.

Urmeaz o scurt descriere a unor comenzilor asociate meniului Build:


Build Solution Aceast comand compileaz numai acele fiiere i componente care au
fost modificate de la ultima compilare.
Rebuild Solution aceast comand terge nti fiierele temporare i intermediare ale
soluiei (similar comenzii "clean"), apoi compileaz de la zero toate fiierele i componentele
proiectelor din cadrul soluiei curente.
Clean Solution aceast comand terge fiierele temporare sau intermediare create la
compilarea soluiei, pstrnd doar fiierele surs i rezultatele finale (fiierele EXE sau DLL).
Build [nume proiect] Aceast comand compileaz proiectul curent. Visual Studio
examineaz fiierele proiectului pentru a vedea dac au aprut modificri de la ultima
compilare a proiectului. La orice modificare din cadrul fiierelor, Visual Studio recompileaz
aceste fiiere i actualizeaz rezultatul.
Rebuild [nume proiect] aceast comand foreaz recompilarea de la zero a proiectului
curent.

20

Introducere n Visual Studio .NET

Configuration Manager comanda Configuration Manager afieaz dialogul din Figura


3.17. Acest dialog poate fi folosit pentru a indica n ce mod se va compila un proiect
(debug/release) i platformele destinaie (x64 sau x86). Putei utiliza casetele de bifare
Build pentru a determina care proiect va fi compilat. V putei folosi de aceast opiune
pentru a evita compilarea anumitor proiecte din cadrul soluiei curente. Dac observai c
anumite pri din soluie nu sunt compilate, verificai opiunile din Configuration Manager.

Figura 3.17. Configuration Manager

Configuraiile Release utilizeaz mai multe optimizri dect configuraiile Debug, astfel nct
ele furnizeaz programe executabile mai mici i mai rapide. Acestea nu includ suport pentru
depanare, astfel c nu vei putea depana un program compilat pentru release.
n caseta combo Active solution configuration selectai <New...> pentru crearea unei noi
configuraii. Atunci cnd selectai aceasta, Visual Studio va fia un dialog n care putei da un
nume configuraiei i putei selecta o configuraie existent de la care vor fi copiate valorile
implicite.
Vei putea astfel s indicai compilatorului c dorii ca unele proiecte din cadrul soluiei s
fie compilate folosind configuraia Debug, iar altele folosind configuraia Release. Evident,
cele compilate cu Release nu vor putea fi depanate ulterior. Acest mod de abordare a
problemei poate fi util n cazul n care dorii s predai anumite proiecte clienilor
(versiunile release), n timp ce versiunile debug ale proiectelor continuai s le dezvoltai.
Dac debifai caseta Build asociat unui proiect, acel proiect va fi exclus din cadrul
operaiilor de construire. La construirea soluiei acesta nu va fi compilat. Visual Studio
afieaz rezultatele compilrii n fereastra Output i contorizeaz numrul de proiecte
necompilate. Urmtoarea linie arat un exemplu n care, la construirea unei soluii care
conine dou proiecte, un proiect a fost compilat iar cellalt nu.
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 1 skipped ==========

Meniul DEBUG
Meniul Debug (Figura 3.18), conine comenzi care v ajut s depanai un program. Aceste
comenzi v ajut s rulai un program n mod depanare (debugger), s v deplasai prin cod,
s setai i s eliminai breakpoint-uri i, n general, s urmrii execuia codului pentru a
observa modul n care acesta ruleaz, n sperana gsirii eventualelor erori.

21

Medii i Tehnologii de Programare curs

Figura 3.18. Meniul Debug conine comenzi pentru depanarea unei aplicaii.

Comenzile vizibile n meniu se modific n funcie mai multe condiii, cum ar fi: tipul
fiierului deschis, starea programului (dac programul ruleaz sau nu), linia de cod care
conine cursorul, sau dac linia de cod curent conine un breakpoint.
Iat o scurt descriere a unor comenzilor asociate meniului Debug:
Windows Acest submeniu pune la dispoziie alte ferestre ce au legtur cu depanarea.
Continue Comanda reia execuia unui program. Programul va rula pn la terminarea
execuiei acestuia, pn la ntlnirea unui breakpoint sau pn la oprirea manual a execuiei
lui.
Break All Oprete execuia tuturor programelor rulate n mod depanare. Comanda aceasta
poate fi util dac mai multe programe ruleaz n strns legtur unul cu cellalt.
Stop Debugging Oprete execuia programului i termin sesiunea de depanare.
Detach All Detaeaz debugger-ul de orice proces de care acesta este ataat. Acest lucru nu
duce la oprirea acestor procese.
Terminate All Oprete orice proces la care este ataat debugger-ul.
Restart Oprete procesul care ruleaz i repornete proiectul setat ca implicit.
Attach to Process Afieaz un dialog care permite s ataai debugger-ul la un proces care
ruleaz.
Exceptions Aceast comand afieaz un dialog care conine o list de erori posibile. Dac
bifai n dreptul unei erori caseta Thrown, debugger-ul se va opri ori de cte ori va aprea
eroarea selectat. Dac bifai User-unhandled, debugger-ul se va opri la apariia acelei
erori, iar programul nu va putea s o trateze nici mcar cu ajutorul codului de tratare a
excepiilor.

22

Introducere n Visual Studio .NET

Step Into Face ca debugger-ul s execute linia de cod curent. Dac aceast linie apeleaz o
funcie sau procedur, punctul de execuie se mut n acea procedur.
Step Over Face ca debugger-ul s execute linia de cod curent. Dac aceast linie apeleaz
o funcie sau procedur debugger-ul apeleaz acea rutin, dar nu va intra n interiorul
codului acesteia dect dac acea rutin conine un breakpoint.
Step Out Aceast comand face ca debugger-ul s ruleze pn la prsirea rutinei care se
afl n execuie, apoi execuia se va ntrerupe la ntlnirea liniei de cod care a apelat acea
rutin.
QuickWatch Afieaz un dialog care ofer informaii legate de obiectul din secvena de cod
selectat. Din aceast fereastr putei modifica valoarea unei variabile sau s o adugai la
fereastra Watch.

Ferestrele Command i Immediate


Fereastra Command este folosit pentru a executa comenzi sau alias-uri direct din mediul
Visual Studio. Putei executa att comenzi de meniu ct i comenzi care nu apar n meniu.
Fereastra Command o putei afia prin comanda de meniu View -> Other Windows ->
Command Window sau prin scurttura de taste Ctrl+Alt+A.
Fereastra Immediate este folosit n timpul depanrii programelor pentru evaluarea
expresiilor, executarea instruciunilor, afiarea valorilor unor variabile .a.m.d. Aceasta v
permite s introducei expresii pentru a fi evaluate sau executate n timpul depanrii
programelor. Fereastra Immediate este accesibil din meniul Debug -> Windows ->
Immediate sau prin scurttura de taste Ctrl+Alt+I.
Spre exemplu, din fereastra Command putem deschide fereastra QuickWatch pentru
variabila nume. Simbolul > reprezint prompterul ferestrei.
>Debug.QuickWatch nume

n fereastra Immediate putem utiliza, de exemplu, urmtoarea linie de cod pentru


deschiderea unui fiier n mod citire:
Dim fs As FileStream = File.OpenRead( _
C:\Program Files\Customer Orders\Summary & _
datetime.Now().ToString(yymmdd) & .dat)

Una dintre cele mai utile comenzi pentru fereastra Immediate este Debug.Print. De exemplu,
comanda Debug.Print x afieaz valoarea variabilei x. Putei utiliza semnul ? ca abreviere a
acestei comenzi (123 reprezint valoarea variabilei x afiat n fereastr):
>? x
123

n cazul de fa putei verifica n fereastra Immediate dac un anumit fiier exist, evitnd
astfel apariia unei erori n program:
? System.IO.File.Exists(C:\Program Files\Customer Orders\Summary & _
DateTime.Now().ToString(yymmdd) & .dat)

Ambele ferestre, Command i Immediate, includ suport pentru IntelliSense.

Meniul FORMAT
Meniul Format (Figura 3.19), conine comenzi pentru aranjarea controalelor pe un formular.

23

Medii i Tehnologii de Programare curs

Figura 3.19. Meniul Format conine comenzi pentru formatarea i aranjarea controalelor pe un formular.

Meniul TOOLS
Meniul Tools (Figura 3.20), conine diverse utilitare i instrumente care nu au fost
considerate potrivite pentru a fi cuprinse n cadrul altor meniuri.

Figura 3.20. Meniul Tools ofer acces la diferite instrumente i utilitare

Iat o prezentare a ctorva dintre comenzile cuprinse n meniul Tools:


Attach to Process Afieaz un dialog care v permite s ataai debugger-ul la un proces
care ruleaz.
Connect to Database Afieaz dialogul Connection Properties, n care putei defini o
conexiune la o baz de date. Conexiunea este adugat la fereastra Server Explorer i putei
s o utilizai ulterior.
Code Snippets Manager Afieaz fereastra Code Snippets Manager, care v permite
adugarea sau tergerea fragmentelor de cod pe care le putei insera n programele pe care
le scriei.
Error Lookup Afieaz un dialog n care putei afla, pe baza unui cod de eroare introdus de
dumneavoastr, o descriere a erorii respective.

24

Introducere n Visual Studio .NET

Spy++ Aceast comand lanseaz o unealt numit Spy++, care v permite s vedei
mesajele trimise ctre aplicaie.
External Tools Afieaz un dialog care v permite s adugai/tergei comenzi n/din
meniul Tools. Putei, de exemplu, s adugai comenzi pentru lansarea oricrei aplicaii pe
care o considerai util.
Customize permite modificarea comenzilor din meniurile i barele cu instrumente ale
Visual Studio 2012.

3.1.2. Editorul de cod Visual Studio 2012


Editorul de text din mediul de dezvoltare Visual Studio 2012 este adesea referit ca editor de
cod deoarece este utilizat pentru editarea codului programelor Visual Studio. Putei s l
folosii de asemenea ca editor XML, HTML sau CSS.
Putei deschide mai multe instane ale editorului de cod asociat diferitor formulare sau
module i putei copia sau lipi secvene de cod dintr-una ntr-alta. n meniul Window avei
acces la toate documentele deschise n instane diferite ale editorului de cod.
Editorul de cod, n funcie de limbajul n care scriei cod, ofer caracteristici cum ar fi:

Acces la proprietile, metodele i evenimentele obiectelor n modul design.


Completarea instruciunilor pe baza IntelliSense.
Seciuni de cod care pot fi expandate sau comprimate, dup preferin, cu ajutorul
directivei #region (n C#: #region #endregion, n Visual Basic: #Region #End Region),
precum se poate vedea n Figura 3.21.

Fereastr de definire a codului care afieaz codul surs pentru un obiect sau
element.

Opiune de inserare a unor fragmente de cod predefinite (code snippets), care v


permite s adugai blocuri de cod prefabricate.

Opiuni pentru definirea indent-urilor, tab-urilor i a comportamentului la operaii


de tip drag&drop.

Pagini de cod unicode.

Emulri ale editoarelor Emacs i Brief.

Figura 3.21. Definirea unei regiuni n codul unui proiect C#

O facilitate a editorului de cod din pachetul Microsoft Visual Studio, foarte util programatorilor, este IntelliSense. Aceasta implementeaz autocompletarea codului scris de
programator (automat n diverse momente ale scrierii codului surs, sau manual prin
combinaia de taste CTRL+Spaiu), servind de asemenea ca documentaie pentru numele
variabilelor, funciilor, metodelor sau evenimentelor unui obiect (Figura 3.22).

25

Medii i Tehnologii de Programare curs

Figura 3.22. IntelliSense n aciune

Elemente ale editorului de cod


Editorul de cod din Visual Studio 2012 (Figura 3.23) prezint urmtoarele elemente:
1. Panoul de cod. Acesta reprezint zona n care este afiat pentru editare codul sau textul.
Acesta ofer faciliti IntelliSense pentru limbajul n care scriei codul.
2. Marginea pentru indicatori. Aceasta reprezint o coloan gri, situat n partea stng a
editorului de cod, pe care sunt afiai indicatori de tip breakpoint, bookmark sau
indicator pentru execuia liniei curente. Dac dai click pe aceast margine vei seta un
breakpoint pe linia de cod corespunztoare.
3. Marginea de selecie. Aceasta reprezint o coloan, situat ntre marginea pentru
indicatori i fereastra de editare, pe care putei da click pentru selectarea liniilor de cod.
Modificrile fcute n cod sunt reflectate pe aceast margine cu diferite culori (galben:
modificrile fcute n cod de la ultima salvare, verde: modificrile salvate).
4. Listele Class Name i Method Name. Acestea reprezint dou liste derulante plasate n
partea superioar a editorului de cod. Lista Class Name, situat n partea stng, ofer
acces la componentele clasei curente (de exemplu, pentru formulare lista controalelor
situate pe formular, iar pentru module Visual Basic lista claselor, funciilor,
procedurilor etc. declarate n interiorul acestuia). Lista Method Name, situat n partea
dreapt, ofer, n funcie de elementul selectat n Class Name, acces la membrii
acestuia.

26

Introducere n Visual Studio .NET

4
1

Figura 3.23. Editorul de cod din Visual Studio 2012

27

Medii i Tehnologii de Programare curs

4. Elemente de baz n programarea


.NET cu Visual C#
Din cauza diferenelor dintre versiunilor anterioare ale limbajului Visual Basic i C/C++ unii
programatori i-au dezvoltat o prere greit despre posibilitile limbajului Visual Basic
.NET. Acetia cred c Visual C# este un limbaj mai puternic dect Visual Basic. Cu alte
cuvinte, acetia presupun c exist o mulime de lucruri pe care le poi face n Visual C#, nu
ns i n Visual Basic. Aceast presupunere a lor este incorect. Dei exist diferene ntre
Visual Basic .NET i Visual C# .NET, ambele sunt limbaje de prima clas, bazate pe Microsoft
.NET Framework, utilizeaz Common Language Runtime, iar ambele sunt la fel de puternice.
Practic nu exist diferene de performan ntre Visual Basic .NET i Visual C# .NET. S-ar
putea spune totui c Visual C# .NET are cteva caracteristici mai puternice, iar Visual
Basic .NET nclin puin spre uurin n utilizare.

4.1. Programe C#
4.1.1. Punctul de intrare n aplicaie
Toate aplicaiile executabile C# (aplicaii n consol, aplicaii desktop Windows sau servicii
Windows) trebuie s conin o clas care s defineasc metoda Main(), care este utilizat
pentru a indica punctul de intrate n aplicaie.
Implicit, compilatorul C# va cuta o metod Main() i o va folosi automat ca punct de intrare
n program. Aceast metod trebuie s ntruneasc o serie de cerine. Prima dintre acestea
este ca metoda s fie static, ceea ce nseamn c, pentru invocarea metodei, nu este nevoie
de crearea unei instane pentru clasa care o conine. Nu este nevoie ca metoda Main() s
returneze ceva (lucru menionat prin utilizarea cuvntului cheie void, precum n exemplul de
mai jos), dei, dac dorii, putei returna o valoare int, lucru ce permite programului s
returneze un cod de ieire pe care sistemul de operare l va raporta la terminarea
programului. n ceea ce privete argumentele metodei Main(), aceasta trebuie fie s nu
primeasc nici unul, fie s accepte un singur argument: un vector de valori string pentru
argumentele transmise la apelul aplicaiei din linie de comand.
Formal vorbind, clasa care definete metoda Main() este numit obiect aplicaie. Este posibil
ca o aplicaie s aib mai multe obiecte aplicaie. Iat un astfel de exemplu:
using
using
using
using
using

System;
System.Collections.Generic;
System.Linq;
System.Text;
System.Threading.Tasks;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello, world! My name is Program");
Console.ReadKey();

28

Elemente de baz n programarea .NET cu C#

}
}
}
namespace ConsoleApplication1
{
class MyClass
{
static void Main(string[] args)
{
Console.WriteLine("Hello, world! My name is MyClass");
Console.ReadKey();
}
}
}

n acest caz, n care exist mai multe obiecte aplicaie, va trebui s i indicai compilatorului
care metod Main() ar trebui utilizat ca punct de intrare. Acest lucru putei s l indicai n
pagina de setri a aplicaiei (Figura 4.1).

Figura 4.1. Indicarea punctului de intrare ntr-o aplicaie C#

Fiierul surs ncepe cu o serie de directive using. Acestea sunt opionale, ns aproape toate
fiierele surs le conin, iar acestea spun compilatorului ce spaii de nume dorim s folosim.
Despre spaii de nume vom vorbi puin mai ncolo n cadrul acestui capitol.
i pentru aplicaiile de tip Windows Forms Application punctul de intrare este tot metoda
Main(). Dac nu modificai codul implicit generat la crearea aplicaiei, comanda
Application.Run(new Form1()) va ncepe s ruleze bucla de mesaje standard pentru firul de
execuie curent i va face vizibil fereastra indicat. Despre aceste aspecte vom discuta n
cadrul acestui curs la seciunea Programarea orientat pe evenimente.
using
using
using
using
using

System;
System.Collections.Generic;
System.Linq;
System.Threading.Tasks;
System.Windows.Forms;

namespace WindowsFormsApplication5
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{

29

Medii i Tehnologii de Programare curs

Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}

4.1.1.1 Formatarea datelor afiate n consol


Aplicaiile n mod consol (proiectele de tip Console Application) interacioneaz cu utilizatorul prin funciile din clasa Console, cel mai adesea Write, WriteLine, Read i ReadLine. Metodele
Write i WriteLine permit formatarea datelor afiate pe ecran ntr-un mod similar funciei
printf din limbajul C.
Primul argument transmis metodei WriteLine() reprezint un ir care conine substitueni
opionali marcai prin {0}, {1}, {2} .a.m.d. ntotdeauna numerele ordinale din perechile de
acolade ncep de la 0. Nu este ns nevoie ca substituenii s apar n ordine. Ceilali
parametri ai metodei WriteLine sunt reprezentai de valorile care trebuie inserate n locul
substituenilor reprezentai prin perechile de acolade. Substituenii vor fi nlocuii, n
ordinea cresctoare a numerelor ordinale, cu argumentele care urmeaz n apelul metodei.
// Afiseaza: 20, 10, 30
Console.WriteLine("{1}, {0}, {2}", 10, 20, 30);

Opional, dac avei nevoie de o formatare mai elaborat pentru datele numerice, fiecare
substituent poate conine diverse caractere de formatare. n tabelul 4.2 putei observa care
sunt caracterele uzuale de formatare a datelor numerice.
Caracter formatare
C sau c
D sau d
E sau e
F sau f
G sau g
N sau n
X sau x

Semnificaie
Formatare de tip Currency.
Decimal (se poate specifica i numrul minim de cifre cu care s se afieze
valoarea).
Notaie exponenial.
Virgul fix (se poate specifica i numrul minim de cifre cu care s se
afieze valoarea).
General. Acest caracter poate fi utilizat pentru afiarea unui numr n format
fix sau exponenial.
Formatri numerice simple.
Formatare n hexazecimal.

Tabelul 4.2. Caracterele utilizate pentru formatarea datelor numerice

Aceste caractere de formatare sunt sufixate la valoarea unui anumit substituent folosind
semnul : (de exemplu, {0:C}, {1:d}, {2:X}). Secvena de cod de mai jos ilustreaz aceste
cazuri de utilizare a caracterelor de formatare.
Console.WriteLine("Valoarea 99999 in diferite formate:");
Console.WriteLine("c format: {0:c}", 99999);
Console.WriteLine("d9 format: {0:d9}", 99999);
Console.WriteLine("f3 format: {0:f3}", 99999);
Console.WriteLine("n format: {0:n}", 99999);
Console.WriteLine("E format: {0:E}", 99999);
Console.WriteLine("e format: {0:e}", 99999);
Console.WriteLine("X format: {0:X}", 99999);
Console.WriteLine("x format: {0:x}", 99999);

La ieire se va afia:
Valoarea 99999 in diferite formate:
c format: $99,999.00
d9 format: 000099999
f3 format: 99999.000
n format: 99,999.00
E format: 9.999900E+004

30

Elemente de baz n programarea .NET cu C#

e format: 9.999900e+004
X format: 1869F
x format: 1869f

Dup acelai principiu putei apela, n cadrul oricrei aplicaii, metoda string.Format pentru
formatarea irurilor de caractere care urmeaz a fi afiate.

4.2. Variabile
4.2.1. Variabile locale
n mod normal, programele preiau, prelucreaz i produc informaii, astfel c definirea i
identificarea acestora reprezint una dintre cele mai importante caracteristici ale unui
limbaj. La fel ca majoritatea limbajelor de programare, C# v permite s definii variabile
locale. Acestea reprezint elemente plasate n cadrul unei metode, care primesc un nume i
care pot stoca informaie.
Spre deosebire de unele limbaje, n C# nu este posibil crearea unor declaraii globale ci, mai
degrab, toi membrii i metodele trebuie coninute n cadrul definiiei unui tip (class,
interface, structure, enumeration sau delegate).
n sintaxa de declarare a unei variabile tipului de dat i urmeaz imediat numele variabilei.
Numele acesteia trebuie s nceap obligatoriu cu o liter sau cu caracterul underscore (_),
urmat de orice combinaie de litere, cifre sau underscore. Aceleai reguli se aplic oricrei
entiti definite de utilizator, cum ar fi clase sau metode.
La fel ca toate limbajele derivate din C, limbajul C# permite declaraii multiple de variabile
printr-o singur instruciune. n acest fel putei, dac dorii, s i atribuii valori acestor
variabile n aceeai linie de cod. inei minte faptul c toate variabilele declarate sau
atribuite n acest fel trebuie s fie de acelai tip.
static void Main()
{
int i = 1, j = 10, k = 100;
Console.WriteLine("{0} {1} {2}", i, j, k);
// Declararea si initializarea a trei constante string.
const string s1 = "unu", s2 = "doi", s3 = "trei";
Console.WriteLine("{0} {1} {2}", s1, s2, s3);
// Declararea a trei variabile. Initializam una dintre ele.
int x = 1, y, z;
Console.WriteLine(j);
y = z = 0; // Initializarea celorlalte
Console.WriteLine("{0} {1}", y, z);
}

La ieire vor fi afiate urmtoarele rezultate:


1 10 100
unu doi trei
1
0 0

Urmtoarea declaraie va genera o eroare de conversie, aceasta putnd fi rezolvat prin


conversia la tipul int a valorii 9.9.
int a = 5, b = 9.9;

//eroare

31

Medii i Tehnologii de Programare curs

4.2.1.1. Declaraii multiple de variabile


Dei avantajul declarrii multiple de variabile este cel al spaiului redus necesar declaraiei,
exist i dezavantaje, i anume lipsa de claritate i imposibilitatea de adugare a unui
comentariu pentru fiecare variabil declarat. Acest mod de declarare este fr ndoial mai
clar:
long cant;
float greutate;
string adresa;

// Numarul de produse
// Greutatea totala a produselor
// Adresa de livrare

4.2.1.2. Variabile la nivel bloc


Domeniul de vizibilitate al variabilelor locale se ntinde de la declaraia acesteia pn la
sfritul blocului care o conine. Un bloc reprezint o regiune de cod delimitat de o pereche
de acolade {}. n acest caz, variabilele locale se mai numesc i variabile bloc.
if (x == 0)
{
int y = 0;
//
}

// variabila bloc

Variabilele la nivel de bloc (variabile bloc) pot fi utilizate numai n interiorul blocului n care
au fost definite:
// Acest cod nu se va compila.
if (x == 0)
{
int y = 0;
// variabila bloc
//
}
x = y;
// Eroare: y nu este accesibila din afara blocului if.

Corpul unei metode este un bloc, astfel c o variabil definit ntr-o metod nu este vizibil
n alt metod, deoarece este n afara domeniului de vizibilitate. Secvena de cod din
continuare va genera o eroare de acest tip.
static void Test1()
{
int val = 42;
}
static void Test2()
{
Console.WriteLine(val); //Eroare: variabila folosita in afara domeniului de vizibilitate
}

Variabilele bloc sporesc lizibilitatea codului deoarece acestea clarific locurile n care pot fi
i n care nu pot fi utilizate. O metod poate conine mai multe variabile bloc cu acelai nume
(chiar avnd tipuri diferite), cu condiia ca acestea s nu fie definite n blocuri suprapuse sau
ncuibate:
// Codul se va compila fara erori
//...
if (x == 0)
{
int y = 0;
// o variabila bloc
//
}
do
{
string y = null;
// alta variabila bloc
//
} while (true);

32

Elemente de baz n programarea .NET cu C#

// Codul nu se va compila.
//...
int y = 0;
// Variabila la nivel de metoda
if (x == 0) {
string y = null;
// Eroare: variabila bloc cu acelasi nume
//
}

Nu este ns nimic greit n a utiliza variabile bloc avnd acelai nume cu o alt variabil
declarat n afara metodei, la nivel de clas.
Buclele for i foreach v permit s definii variabilele contor (variabile de control) ca
variabile bloc:
for (int i = 1; i <= 10; i++)
{
Console.WriteLine(i);
}

Sintaxa aceasta este preferat n toate cazurile datorit faptului c previne reutilizarea
accidental a valorii variabilei contor atunci cnd se prsete bucla for, lucru care este
considerat ca fiind o greeal de programare i o potenial surs de erori.
Ce valoare va avea variabila i la ieirea din bucla for anterioar?
Dar dac bucla este prsit mai devreme?

4.2.1.3. Iniializarea variabilelor


Atunci cnd utilizai o variabil, aceasta va conine valoarea pe care i-ai atribuit-o. Dac
ncercai s folosii n program o variabil nainte de a-i fi atribuit o valoare, compilatorul C#
va genera eroare.
int valoare;
Console.WriteLine(valoare);

//eroare de folosire a unei variabile neinitializate!

Putei declara i iniializa o variabil local sau o cmp de la nivelul unei clase ntr-o singur
declaraie. Aceast caracteristic v permite simplificarea codului i i sporete lizibilitatea.
Valoarea atribuit nu este nevoie s fie o constant, ci poate fi o expresie sau o funcie.
Iniializarea funcioneaz i pentru variabile care stocheaz referine la obiecte.
DataSet ds;
ds = new DataSet();
// sau
DataSet ds = new DataSet();
// sau chiar
DataSet ds = new DataSet("Studenti");

4.2.1.4. Atribuiri de obiecte


Atribuirea de obiecte se face n acelai mod n care se face atribuirea de valori:
tb = textBox1;
// sau
TextBox tb2 = textBox1;

Chiar dac semnul egal funcioneaz la atribuirea de obiecte, trebuie s folosii totui metoda
ReferenceEquals() pentru a testa dac dou obiecte indic spre acelai obiect din memorie.
object
object
object
object

mar = new object();


para = new object();
obj1 = null;
obj2 = null;

33

Medii i Tehnologii de Programare curs

object obj3 = null;


bool eval = false;
obj1 = mar;
obj2 = mar;
obj3 = para;
eval
eval
eval
obj3
eval

=
=
=
=
=

object.ReferenceEquals(obj1, obj2);
object.ReferenceEquals(obj3, obj2);
object.ReferenceEquals(mar, obj3);
mar;
object.ReferenceEquals(obj2, obj3);

// eval -> True.


// eval -> False.
// eval -> False.
// eval -> True.

4.2.2. Modificatori de acces


Modificatorii de acces reprezint cuvinte cheie folosite pentru a indica accesibilitatea unui
membru sau a unui tip. Aceti modificatori de acces sunt: public, protected, internal i private.
n C# pot fi specificate cinci niveluri de accesibilitate:
public: accesul nu este restricionat.

protected: accesul este limitat la clasa care conine membrul sau la tipurile derivate

internal: accesul este limitat la ansamblul curent.

protected internal: accesul este limitat la ansamblul curent sau la tipurile derivate

private: accesul este limitat la tipul care conine membrul.

din aceasta.

sin clasa care conine membrul.

Pentru un membru sau tip este permis utilizarea unui singur modificator de acces, cu
excepia cazului n care este utilizat combinaia protected internal.
Utilizarea modificatorilor de acces nu este permis la nivel de spaii de nume (namespaces).
Acestea nu au restricii de acces.
n funcie de contextul n care apare declararea unui membru, sunt permii numai anumii
modificatori acces. Dac n declararea unui membru nu este indicat nici un modificator de
acces, atunci este folosit accesibilitatea implicit.
Tipurile situate la nivel superior, care nu sunt ncuibate n ale tipuri, pot avea accesibilitate
numai internal sau public. Accesibilitatea implicit pentru acestea este internal.
Tipurile ncuibate, care sunt membri ai altor tipuri, pot avea accesibiliti precum cele
indicate n Tabelul 4.3.
Membri ai
enum
class

Accesibilitate implicit
a membrilor
public
private

interface
struct

public
private

Accesibilitate permis a
membrilor
public
protected
internal
private
protected internal
public
internal
private

Tabelul 4.3. Accesibilitatea membrilor

34

Elemente de baz n programarea .NET cu C#

4.2.2.1. Variabile neatribuite i variabile neutilizate


n cazul n care declarai o variabil local pe care nu o utilizai niciunde n metoda curent
Visual C# .NET va emite un avertisment la compilare. Chiar dac acest lucru nu afecteaz n
vreun fel execuia programului, prezena acestei probleme poate fi simptomul unei greeli
de programare mult mai severe.
Visual C# .NET utilizeaz un motor de analiz a fluxului de cod pentru a afla dac o referin
la o variabil poate cauza o eroare de tip NullReferenceException. Considerai urmtorul
fragment de cod:
string s;
int x = Console.Read();
if (x >= 48 && x <= 57)
s = "#";
Console.WriteLine(s); //eroare

Ultima linie va duce al apariia unei erori deoarece compilatorul nu are cum s determine
dac n timpul rulrii condiia if va evaluat la true. Pe de alt parte, eroarea dispare dac
toate cile posibile de execuie vor atribuie o valoare variabilei n cauz:
string s;
int x = Console.Read();
if (x >= 48 && x <= 57)
s = "#";
else
s = "*";
Console.Write(s);
//nicio eroare

Din nefericire, motorul de analiz a codului este departe de a fi perfect. De exemplu, nu va fi


emis niciun avertisment dac atribuii explicit valoarea null variabilei nainte de a o utiliza:
string s = null;
Console.Write(s.Length);

//nu va genera eroare la compilare ci in timpul rularii

4.2.2.2. Deducerea tipului unei variabile


n mod normal toate variabilele trebuie declarate avnd precizat explicit tipul de dat.
Totui, acest lucru se poate omite n cazul n care folosii cuvntul cheie var. n acest caz,
variabila trebuie iniializat obligatoriu pentru ca compilatorul s deduc tipul acesteia din
valoarea pe care o primete:
var obj;
var i=8;

// eroare.
// i va fi de tip int.

Cuvntul cheie var poate fi utilizat n urmtoarele situaii:

La variabile locale (declarate la nivel de metod), ca n exemplul anterior.


ntr-o instruciune de iniializare:
for(var x = 1; x < 10; x++)

ntr-o instruciune de iniializare foreach:


foreach(var item in list){/*...*/}

ntr-o instruciune using:


using (var file = new StreamReader("C:\\myfile.txt")) {/*...*/}

Asupra declaraiilor de variabile al cror tip este dedus se aplic cteva restricii:
var poate fi utilizat atunci cnd o variabil local este declarat i iniializat n
cadrul aceleiai instruciuni; variabila nu poate fi iniializat la null.

var nu poate fi utilizat asupra cmpurilor la nivel de clas.

35

Medii i Tehnologii de Programare curs

Variabilele declarate cu var nu pot fi utilizate n expresia de iniializare. Cu alte


cuvinte, dei prima expresie din codul de mai jos este legal, a doua expresie va
produce eroare la compilare:
int i = (i = 20);
var i = (i = 20);

// permis
// eroare

Variabilele multiple cu tipul dedus nu pot fi iniializate n aceeai instruciune.


var i=2, j=10;

// eroare

4.2.2.3. Tipuri anonime


Tipurile anonime ofer o modalitate convenabil de ncapsulare a unui set de proprieti
read-only ntr-un singur obiect fr a fi nevoie de definirea explicit a unui tip. Numele
tipului este generat de compilator i nu este disponibil la nivelul codului surs. Tipul fiecrei
proprieti este dedus de ctre compilator.
Putei crea tipuri anonime prin utilizarea operatorului new mpreun cu iniializarea
obiectului.
var v = new {Valoare = 10, Mesaj = "Salut"};
// v.Valoare si v.Mesaj vor avea deduse tipurile int si string.
Console.WriteLine(v.Valoare + v.Mesaj);

Tipurile anonime sunt folosite de regul n clauza select a unei expresii de interogare (LINQ)
pentru a returna un subset a proprietilor pentru fiecare obiect din secvena de cod.
Tipurile anonime conin una sau mai multe proprieti read-only. Nicio alt categorie de
membri ai unei clase, cum ar fi metode sau evenimente, nu sunt valide. Expresia utilizat
pentru iniializarea unei proprieti nu poate fi null, o funcie anonim sau un tip pointer.
Tipurile anonime sunt clase care deriv direct din object i care nu pot fi convertite la nici un
alt tip, cu excepia tipului object. Compilatorul furnizeaz un nume pentru fiecare tip anonim,
chiar dac aplicaia voastr nu l poate accesa. Din perspectiva CLR, un tip anonim nu este cu
nimic diferit fa de un tip referin.
Nu putei declara un cmp, o proprietate, un eveniment sau tipul returnat de o metod ca
fiind de tip anonim.

4.3. Tipuri de date


n Tabelul 4.4 gsii informaii referitoare la cantitatea de memorie ocupat i domeniul de
valori pentru principalele tipuri de date utilizate n aplicaii.

36

Tip C#
byte
sbyte
ushort
short
uint
int
ulong
long

Nume CLR
System.Byte
System.SByte
System.UInt16
System.Int16
System.UInt32
System.Int32
System.UInt64
System.Int64

Cu semn?
nu
da
nu
da
nu
da
nu
da

Octei
1
1
2
2
4
4
8
8

float

System.Single

nu

Domeniu de valori
0 .. 255
-128 .. 127
0 .. 65535
-32768 .. 32767
0 .. 4294967295
-2147483648 .. 2147483647
0 .. 18446744073709551615
-9223372036854775808 ..
9223372036854775807
-3.4028235E+38 .. -1.401298E-45 pentru
valori negative;

Elemente de baz n programarea .NET cu C#

double

System.Double

nu

decimal
char
string

System.Decimal
System.Char
System.String

nu
nu
nu

16
2
2 nr.
caractere

1.401298E-45 .. 3.4028235E+38 pentru


valori pozitive.
-1.79769313486231570E+308 ..
4.94065645841246544E-324 pentru valori
negative;
4.94065645841246544E-324 ..
1.79769313486231570E+308 pentru valori
pozitive
- 10^38 +1 .. 10^38 - 1
0 .. 65535.
aprox. 2 miliarde de caractere Unicode.

Tabelul 4.4. Dimensiunile i domeniile de valori ale principalelor tipurilor de date.

4.3.1. Alegerea corect a tipului de date numerice


Dei la prima vedere nu pare s fi aa, pentru sporirea performanei aplicaiilor voastre este
recomandat utilizarea variabilelor double n locul celor de tip float, deoarece acestea nu
necesit vreo conversie atunci cnd sunt scrise sau citite n/din regitrii n virgul mobil ai
procesorului. Putei utiliza valori float numai pentru economisirea memoriei la crearea unor
iruri mari de valori n virgul mobil, evident, dac suntei mulumii de precizia i domeniul de valori al acestora.
Atunci cnd este vital ca o serie de operaii matematice s nu fie supuse la operaii de rotunjire sau trunchiere (cum ar fi cazul sumelor de bani) se recomand utilizarea variabilelor
decimal. Tipul de date decimal stocheaz un numr n format virgul fix, fiind astfel util la
prevenirea problemelor legate de rotunjire sau trunchiere.
Valorile decimal sunt extrem de rapide cnd sunt implicate n operaii de adunare sau
scdere, ns performana lor este mult mai slab la operaii de nmulire sau mprire. Prin
comparaie, variabilele double sunt mai lente la adunare i scdere, ns sunt mai rapide n
cazul celorlalte operaii matematice.

4.3.2.Conversii ntre tipuri de date


Fiecare valoare are un tip asociat, care definete atribute precum spaiul alocat valorii,
domeniul de valori posibile i membrii pe care i pune la dispoziie. O valoare poate fi exprimat sub forma mai multor tipuri de date. De exemplu, valoarea 4 poate fi exprimat att ca
numr ntreg ct i ca numr n virgul mobil. Conversia dintre tipuri creeaz o valoare
exprimat ntr-un nou tip, echivalent cu valoarea din vechiul tip, dar nu pstreaz neaprat
identitatea (sau valoarea exact) a obiectului original.
Conversia valorilor poate fi fcut fie prin operatorul cast, fie prin metodele oferite de clasa
System.Convert. Clasa System.Convert ofer metode pentru conversia unui tip de baz n alt tip
de baz.

4.3.2.1. Tipuri de conversie


n general, atunci cnd dorii s efectuai conversia unei valori avnd un anumit tip de dat
la o valoare care aparine unui alt tip de dat, pot aprea dou situaii care se ncadreaz
ntr-una dintre urmtoarele tipuri de conversie sau tipuri de conversie: widening sau
narrowing. Conversiile de tip widening apar atunci cnd o valoare de un anumit tip este
convertit la alt tip care este de mrime cel puin egal. O conversie de tip narrowing apare

37

Medii i Tehnologii de Programare curs

atunci cnd o valoare de un anumit tip este convertit la un tip de mrime mai mic. Tabelele
prezentate mai jos ilustreaz comportamentele tipurilor de baz n ambele cazuri de
conversie.

Conversii de tip widening


Tabelul 4.5. descrie conversiile de tip widening care pot fi efectuate fr pierdere de
informaii.
Tip
Byte
SByte
Int16
UInt16
Char
Int32
UInt32
Int64
UInt64
Single

Poate fi convertit fr pierdere de date la:


UInt16, Int16, UInt32, Int32, UInt64, Int64, Single, Double, Decimal
Int16, Int32, Int64, Single, Double, Decimal
Int32, Int64, Single, Double, Decimal
UInt32, Int32, UInt64, Int64, Single, Double, Decimal
UInt16, UInt32, Int32, UInt64, Int64, Single, Double, Decimal
Int64, Double, Decimal
Int64, UInt64, Double, Decimal
Decimal
Decimal
Double
Tabelul 4.5. Conversii widening fr pierdere de informaii

Unele conversii widening la Single la Double pot provoca o pierdere a preciziei. Tabelul 4.6.
descrie conversiile widening care, uneori, pot avea ca rezultat pierderea de informaii.
Tip
Int32
UInt32
Int64
UInt64
Decimal

Poate fi convertit la:


Single
Single
Single, Double
Single, Double
Single, Double

Tabelul 4.6. Conversii widening care pot provoca pierderea de informaii

Conversii de tip narrowing


O conversie de tip narrowing la Single sau Double poate provoca o pierdere de informaii.
Dac tipul destinaie nu poate exprima ntr-un mod potrivit mrimea tipului surs atunci
tipul rezultat este setat la constantele PositiveInfinity sau NegativeInfinity. PositiveInfinity
rezult din mprirea unui numr pozitiv la zero i este de asemenea returnat cnd valoarea
unui Single sau Double depete valoarea cmpului MaxValue. NegativeInfinity rezult din
mprirea unui numr negativ la zero i este de asemenea returnat cnd valoarea unui
Single sau Double se situeaz sub valoarea cmpului MinValue. O conversie de la Double la
Single ar putea avea ca rezultat PositiveInfinity sau NegativeInfinity.
double d=1234567890123456789012345679801234567890.5;
float f;
f = Convert.ToSingle (d);
Console.WriteLine(f); // Infinit

O conversie narrowing poate de asemenea s provoace pierderea de informaii pentru alte


tipuri de date. Oricum, dac valoarea tipului surs se situeaz n afara domeniului specificat
de ctre cmpurile MaxValue i MinValue ale tipul destinaie, este generat o excepie de tip
OverflowException, deoarece conversia este verificat la rulare pentru ca valoarea exprimat n tipul destinaie s nu depeasc valorile MaxValue i MinValue ale acestuia. Conversiile
efectuate prin metodele clasei System.Convert sunt ntotdeauna verificate n acest mod.

38

Elemente de baz n programarea .NET cu C#

byte b;
int i=1234;
b = Convert.ToByte(i);
Console.WriteLine(b);

// eroare de tip OverflowException

Tabelul 4.7 afieaz conversiile care genereaz o excepie OverflowException n cazul n care
valoarea tipului surs se situeaz n afara domeniului definit pentru tipul destinaie.
Tip
Byte
SByte
Int16
UInt16
Int32
UInt32
Int64
UInt64
Decimal
Single
Double

Convertit la:
SByte
Byte, UInt16, UInt32, UInt64
Byte, SByte, UInt16
Byte, SByte, Int16
Byte, SByte, Int16, UInt16, UInt32
Byte, SByte, Int16, UInt16, Int32
Byte, SByte, Int16, UInt16, Int32, UInt32, UInt64
Byte, SByte, Int16, UInt16, Int32, UInt32, Int64
Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64
Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64
Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64

Tabelul 4.7. Conversiile care genereaz erori de depire a domeniului de valori

4.3.2.2. Cuvntul cheie checked


n cazul n care scriei aplicaii n care este inacceptabil pierderea de date, C# v pune la
dispoziie cuvintele cheie checked i unchecked pentru a v asigura c nici o pierdere de date
nu va scpa nedetectat.
S presupunem c n cadrul unui program dorii s adunai dou valori byte, fiind siguri c
fiecare dintre ele se situeaz sub valoare maxim admis (255). Dac ar fi s adunai aceste
valori (convertind prin operatorul cast ntregul returnat la byte) ai presupune c rezultatul
va fi exact suma fiecrui membru.
static void Main()
{
byte b1 = 100;
byte b2 = 250;
byte sum = (byte)Add(b1, b2);
// sum ar trebui sa fie 350. Totusi, va avea valoarea 94!
Console.WriteLine("sum = {0}", sum);
}

Dup rularea aplicaiei vei observa cu surprindere c suma va conine valoarea 94 (nu 350).
Motivul este c un System.Byte poate stoca numai valori cuprinse ntre 0 i 255, astfel c suma
va conine o valoare depit (350 256 = 94). Dac nu vei lua msuri de corectare a
acestor probleme, atunci situaiile de depire superioar sau inferioar vor aprea fr a se
semnala erori.
C# pune la dispoziia programatorilor cuvntul cheie checked. Dac vei cuprinde una sau mai
multe instruciuni ntr-un bloc checked, atunci compilatorul C# va verifica situaiile n care
pot aprea depiri la operaii de adunare, scdere, nmulire sau mprire a dou valori
numerice. Astfel, la apariia unei astfel de depiri vei primi o excepie de tipul
System.OverflowException cu mesajul: Arithmetic operation resulted in an overflow.
static void Main()
{
byte b1 = 100;
byte b2 = 250;
try
{
byte sum = checked((byte)Add(b1, b2));

39

Medii i Tehnologii de Programare curs

Console.WriteLine("sum = {0}", sum);


}
catch (OverflowException ex)
{
Console.WriteLine(ex.Message);
}
}

n cazul n care dorii ca verificrile asupra depirilor s se extind asupra mai multor
instruciuni putei defini un bloc checked:
try
{
checked
{
byte sum = (byte)Add(b1, b2);
Console.WriteLine("sum = {0}", sum);
}
}
catch (OverflowException ex)
{
Console.WriteLine(ex.Message);
}

Compilatorul C# suport flag-ul /checked pentru verificarea depirilor fr a mai fi nevoie de


utilizarea cuvntului cheie checked n codul surs. Acest flag putei s l activai la nivel de
proiect deschiznd fereastra de proprieti a acestuia, pagina Build, apoi dnd click pe
butonul Advanced. n fereastra dialog ce se va deschide (Figura 4.8) selectai caseta Check
for arithmetic overflow/underflow.

Figura 4.8. Activarea la nivel de proiect a verificrii depirilor

4.3.2.3. Exprimarea tipului pentru constantele numerice


Atunci cnd scriei o valoare numeric literal putei s i indicai tipul. Dac scriei un ntreg,
tipul acestuia va fi int, uint, long sau ulong. Compilatorul va alege primul tip din aceast list
n domeniul creia se ncadreaz valoarea. De exemplu, 125 va fi int, 3000000000 va fi uint,
5000000000 va fi long etc. Dac scriei un numr cu virgul, de exemplu 1.25, acesta va fi
considerat double.
Putei s i spunei compilatorului tipul dorit prin adugarea unui sufix. Astfel, 125U va fi
uint, 125L va fi long, iar 125UL va fi ulong. Literele din sufix nu sunt case-sensitive i nu
conteaz nici ordinea n care ele apar. Deci constantele 125UL, 125Lu i 125uL sunt echivalente.

40

Elemente de baz n programarea .NET cu C#

Valorile numerice haxazecimale se exprim prin prefixul 0x urmat de secvena de


caractere de la 0 la F. Exist, desigur, i metode pentru conversia constantelor hexazecimale
exprimate ca string la valori ntregi, precum putei observa n secvena de cod de mai jos:
int val0 = 0xFFFF;
string hexVal1 = "FFFE";
int val1 = Convert.ToInt32(hexVal1, 16);
string hexVal2 = "FFFD";
int val2 = Int32.Parse(hexVal2, System.Globalization.NumberStyles.HexNumber);

Pentru valori double, float i decimal utilizai sufixele D, F, respectiv M. Aceste trei tipuri
suport formatul literal exponenial. Conform acestui format, valoarea 1.5E-20 este echivalent cu 1.5*10-20. Implicit, valorile astfel exprimate vor fi considerate de tip double, ns,
dac dorii, putei aduga la valoare sufixele F sau M pentru a indica tipul float sau decimal.

4.3.2.4. Tipul Boolean


C# definete un tip numit bool, sau System.Boolean. Acesta ofer numai dou valori: true i
false. Chiar dac unele limbaje din familia C permit asocierea valorilor booleene cu valori
numerice (0, -1), C# nu va accepta pentru o variabil bool un numr, ci numai valori true sau
false. Acest lucru are i alte implicaii, de exemplu, la utilizarea n cadrul unei instruciuni if:
if (numar) {/*...*/}
if (numar!=0) {/*...*/}

// eroare!
// corect.

4.3.2.5. Tipul Object


Tipul object este clas de baz pentru toate tipurile C#. Variabilelor de tip object le pot fi
atribuite valori de orice tip, deoarece n .NET Framework toate tipurile de dat sunt derivate
din object, inclusiv valorile ntregi i irurile de caractere. Conform paradigmei POO unei
variabile i poate fi atribuit ntotdeauna o valoare a crui tip este derivat din tipul variabilei.
n consecin, atribuirile urmtoare sunt perfect legale:
object o;
string s;
s = "ABCDE";
o = 123;
// Atribuirea unei valori intregi unei variabile object.
o = s;
// Atribuirea unui sir de caractere unei variabile object.

4.3.2.6. Tipuri pentru lucrul cu date calendaristice i intervale de timp


Spaiul de nume System definete cteva tipuri de dat utile, printre care structurile DateTime
i TimeSpan. Tipul DateTime permite reprezentarea unei date calendaristice (zi, lun, an) sau a
unui moment de timp, ambele putnd fi formatate ntr-o multitudine de moduri cu ajutorul
membrilor pui la dispoziie. Structura TimeSpan permite definirea uoar i transformarea
unitilor de timp. Exemplul de mai jos ilustreaz utilizarea ctorva metode ale acestor
tipuri:
static void Main()
{
// Acest constructor primeste (an, luna, zi, ora, minut, secunda)
DateTime dt = new DateTime(2013, 10, 16, 16, 0, 0);
// Ce zi din saptamana este aceasta?
Console.WriteLine("Ziua de {0} este {1}", dt.Date, dt.DayOfWeek);
// Acum este luna decembrie
dt = dt.AddMonths(2);
// Acest constructor primeste (ore, minute, secunde)
TimeSpan ts = new TimeSpan(18, 00, 0);
Console.WriteLine(ts);

41

Medii i Tehnologii de Programare curs

// Scade 15 minute din ts si afiseaza rezultatul


Console.WriteLine(ts.Subtract(new TimeSpan(0, 15, 0)));
}

La rulare, aplicaia va fi afia:


Ziua de 16.10.2013 16:00:00 este Wednesday
18:00:00
17:45:00

Structura DateTime pune la dispoziia programatorilor o serie de metode i proprieti utile,


cele mai importante dintre acestea putnd s le examinai n Tabelul 4.9:
Membru
Now
Today
TimeofDay
Year
Month
Day
Hour
Minute
Second
IsLeapYear()
DaysInMonth()
Compare()
CompareTo()
Equals()
Add()
AddYears()
AddMonths()
AddDays()
AddHours()
AddMinutes()
AddSeconds()

Semnificaie
Returneaz un obiect DateTime setat la data i timpul curent.
Returneaz un obiect DateTime setat la data curent.
Returneaz un obiect DateTime setat la timpul curent.
Returneaz componentele din data reprezentat de instana curent.

Returneaz componentele din timpul reprezentat de instana curent.


Returneaz dac anul primit ca argument este bisect.
Returneaz numrul de zile din luna transmis ca argument (mpreun cu anul).
Compar dou instane ale DateTime i returneaz un ntreg (mai mic, mai mare sau
egal cu zero).
Compar instana curent DateTime cu cea primit ca argument i returneaz un
ntreg (mai mic, mai mare sau egal cu zero).
Returneaz o valoare boolean care indic dac valoarea instanei curente este
egal cu cea specificat ca argument.
Returns o nou instan DateTime care adaug la instana curent valoarea
TimeSpan specificat ca argument.

Returneaz o nou instan DateTime la care s-a adugat la valoarea instanei


curente numrul specificat de ani, luni, zile, ore, minute sau secunde.

Tabelul 4.9. Metode i proprieti utile ale structurii DateTime.

4.3.2.7. Tipul Char


n C# datele textuale sunt reprezentate prin tipurile string i char (prescurtri ale tipurilor
.NET System.String i System.Char). Acestea opereaz cu caractere Unicode. Tipul System.Char
v pune la dispoziie o serie de metode statice prin care putei determina dac un anumit
caracter este cifr, liter, semn de punctuaie sau altceva, precum putei observa n exemplul
de mai jos:
static void Main()
{
char myChar = 'a';
Console.WriteLine("char.IsDigit('a'): {0}", char.IsDigit(myChar));
Console.WriteLine("char.IsLetter('a'): {0}", char.IsLetter(myChar));
Console.WriteLine("char.IsWhiteSpace('Hello world!', 5): {0}",
char.IsWhiteSpace("Hello world!", 5));
Console.WriteLine("char.IsWhiteSpace('Hello world!', 6): {0}",
char.IsWhiteSpace("Hello world!", 6));
Console.WriteLine("char.IsPunctuation('?'): {0}", char.IsPunctuation('?'));
}

42

Elemente de baz n programarea .NET cu C#

Aplicaia va afia la ieire urmtorul rezultat:


char.IsDigit('a'): False
char.IsLetter('a'): True
char.IsWhiteSpace('Hello world!', 5): True
char.IsWhiteSpace('Hello world!', 6): False
char.IsPunctuation('?'): True

Precum se poate observa n exemplul de mai sus, multe dintre metodele clasei System.Char au
dou convenii de apelare: cea cu un singur caracter i cea cu un string mpreun cu un index
numeric care specific poziia caracterului care trebuie testat.

4.3.2.8. Analizarea valorilor din date String


Tipurile de date .NET ofer posibilitatea de generare a unei variabile pornind de la un
echivalent textual. Aceast tehnic poate fi extrem de util atunci cnd dorii s convertii
date introduse de utilizator (cum ar fi, de exemplu, selecia dintr-un control Combo Box)
ntr-o valoare numeric. n exemplul de mai jos putei observa cteva astfel de conversii de
la formatele textuale prin metoda Parse a claselor corespunztoare tipurilor de date:
static void Main()
{
bool b = bool.Parse("True");
Console.WriteLine("b = {0}", b);
double d = double.Parse("99.884");
Console.WriteLine("d = {0}", d);
int i = int.Parse("8");
Console.WriteLine("i = {0}", i);
char c = Char.Parse("w");
Console.WriteLine("c = {0}", c);
}

Aplicaia va afia la rulare urmtorul rezultat:


b
d
i
c

=
=
=
=

True
99.884
8
w

4.3.2.9. Tipul String


Tipul string (sinonim cu tipul CLR System.String) reprezint o secven de caractere text.
Fiecare caracter din secven este de tip char, reprezentat pe 16 bii (caracter Unicode).
Clasa System.String ofer mai multe metode care permit manipularea datelor text, cum ar fi
aflarea lungimii unui ir, gsirea unui subir n irul curent sau conversia textului la caractere majuscule sau minuscule. Manipularea elementelor de tip string este intuitiv. Nu
trebuie dect s declarai o variabil string i s utilizai metodele oferite de clasa
System.String. Trebuie s tii c unele dintre aceste metode sunt statice, fiind apelate mai
degrab la nivel de clas. n Tabelul 4.10 gsii civa dintre cei mai importani membri ai
clasei System.String.
Membru
Length
Compare()
Contains()
Equals()
Format()
Insert()
PadLeft()

Semnificaie
Returneaz lungimea stringului curent.
Compar dou stringuri.
Determin dac un string conine un anumit substring.
Testeaz dac dou obiecte string conin caractere identice.
Formateaz un string folosind un ir de formatare i substitueni (similar
metodei Console.WriteLine()).
Insereaz un string ntr-un alt string dat.
Metode utilizate pentru umplerea unui string cu anumite caractere.

43

Medii i Tehnologii de Programare curs

PadRight()
Remove()
Replace()
Split()
ToLower()
ToUpper()
Trim()

Metode utilizate pentru obinerea unei copii modificate a unui string (avnd
caractere terse sau nlocuite).
Returneaz un vector de valori string care conine substringurile delimitate de
elementele char sau string specificate.
Returneaz o copie a instanei curente convertite la caractere minuscule sau
majuscule, utiliznd regulile culturii curente.
terge toate apariiile unui set de caractere specificate de la nceputul i
sfritul stringului curent.
Tabelul 4.10. Metode i proprieti utile ale clasei System.String.

static void Main()


{
string prenume = "Alexandru";
Console.WriteLine("prenume: {0}", prenume);
Console.WriteLine("prenume are {0} caractere", prenume.Length);
Console.WriteLine("prenume cu majuscule: {0}", prenume.ToUpper());
Console.WriteLine("prenume cu minuscule: {0}", prenume.ToLower());
Console.WriteLine("prenume contine litera x?: {0}", prenume.Contains("x"));
Console.WriteLine("prenume dupa inlocuire: {0}", prenume.Replace("andru", ""));
}

La rulare programul va afia urmtoarele:


prenume: Alexandru
prenume are 9 caractere
prenume cu majuscule: ALEXANDRU
prenume cu minuscule: alexandru
prenume contine litera x?: True
prenume dupa inlocuire: Alex

Concatenarea irurilor
Pentru construirea unor iruri de caractere mai mari variabilele string pot fi alturate cu
ajutorul operatorului +. Aceast tehnic este cunoscut sub denumirea de concatenare. n
cazul lucrului cu variabile de tip string operatorul + este procesat de compilator, fiind apoi
efectuat un apel la metoda static String.Concat(). Astfel, putei concatena iruri de caractere
fie cu operatorul +, fie direct prin apelul metodei String.Concat(), singura diferen fiind c, n
al doilea caz, vei avea ceva mai mult de scris.

Stringurile i egalitatea
Implicit, atunci cnd efectuai un test de egalitate asupra tipurilor referin (cu ajutorul
operatorilor C# == i !=) vei obine valoarea True dac referinele pointeaz spre acelai
obiect din memorie. Totui, dei string este un tip referin, operatorii de egalitate au fost
redefinii pentru a compara valoarea obiectelor string, nu obiectele din memorie la care se
refer.
static void Main()
{
string s1 = "Salut!";
string s2 = "Pa!";
Console.WriteLine("s1 = {0}", s1);
Console.WriteLine("s2 = {0}", s2);
// Testeaza egalitatea acestor stringuri
Console.WriteLine("s1 == s2: {0}", s1 == s2);
Console.WriteLine("s1 == Salut!: {0}", s1 == "Salut!");
Console.WriteLine("s1 == SALUT!: {0}", s1 == "SALUT!");

44

Elemente de baz n programarea .NET cu C#

Console.WriteLine("s1 == salut!: {0}", s1 == "salut!");


Console.WriteLine("s1.Equals(s2): {0}", s1.Equals(s2));
Console.WriteLine("Pa!.Equals(s2): {0}", "Pa!".Equals(s2));
}

La rulare programul va afia:


s1 = Salut!
s2 = Pa!
s1 == s2: False
s1 == Salut!: True
s1 == SALUT!: False
s1 == salut!: False
s1.Equals(s2): False
Pa!.Equals(s2): True

Operatorii de egalitate din C# efectueaz un test de egalitate case-sensitive, caracter cu


caracter, asupra obiectelor string. n consecin, Salut! este diferit de SALUT! i de
salut!. Reinei faptul c pentru obiecte de tip string putem utiliza att operatorii de
egalitate ct i metoda Equals() a clasei System.String. Datorit faptului c textele literale
(cum ar fi Pa!) reprezint instane valide ale clasei System.String, putem accesa i pentru
acestea metodele i proprietile specifice clasei.

Stringurile sunt invariabile


Un aspect interesant al clasei System.String este acela c, dup atribuirea unei valori iniiale
unui obiect string, datele stocate n acesta nu mai pot fi schimbate. Acest lucru ar putea
prea cel puin curios, deoarece le putem atribui valori obiectelor string de cte ori dorim,
iar clasa System.String ofer o serie de metode care par s modifice datele text stocate.
Totui, dac vom privi cu mai mult atenie ceea ce se ntmpl, vom observa c metodele
clasei System.String returneaz de fapt modificrile n obiecte noi de tip string.
static void Main()
{
string s1 = "Acesta este stringul meu";
Console.WriteLine("s1 = {0}", s1);
string textMajuscule = s1.ToUpper();
Console.WriteLine("textMajuscule = {0}", textMajuscule);
Console.WriteLine("s1 = {0}", s1);
}

Dac examinm mai aproape rezultatul rulrii aplicaiei, vom observa c obiectul original
(s1) nu este modificat la apelul metodei ToUpper(). n schimb, este returnat o copie a
stringului n formatul modificat.
s1 = Acesta este stringul meu
textMajuscule = ACESTA ESTE STRINGUL MEU
s1 = Acesta este stringul meu

Aceeai lege a invariabilitii este valabil chiar i la utilizarea operatorului de atribuire C#.
Pentru ilustrare vom examina secvena de cod de mai jos.
static void Main()
{
string s2 = "Stringul meu";
s2 = "Noua valoare string";
}

n continuare, dac vom compila aplicaia i vom ncrca ansamblul n utilitarul isdasm.exe
(acesta permite vizualizarea codului intermediar: MSIL, CIL sau IL), ar trebui s gsim
urmtorul cod intermediar generat pentru metoda anterioar:
.method private hidebysig static void Main() cil managed
{
// Code size 14 (0xe)
.maxstack 1

45

Medii i Tehnologii de Programare curs

.locals init ([0] string s2)


IL 0000: nop
IL 0001: ldstr "Stringul meu"
IL 0006: stloc.0
IL 0007: ldstr "Noua valoare string"
IL 000c: stloc.0
IL 000d: ret
} // end of method Program::Main

Putei observa numeroasele apeluri ale instruciunii ldstr. Aceasta ncarc un nou obiect
string n heap. Memoria ocupat de obiectul string anterior, cel care coninea valoarea
Stringul meu", va fi eventual eliberat de ctre garbage collector.
Ce am nvat de aici? n concluzie, clasa string poate fi ineficient i generatoare de mult cod
dac nu este folosit corespunztor, n special la operaiile de concatenare. Pentru operaii
simple, care manipuleaz cantiti mici de date, clasa string poate fi considerat acceptabil.
Dac ns scriei aplicaii care manipuleaz frecvent cantiti mari de date textuale (de
exemplu, un procesor de text), atunci utilizarea obiectelor string nu ar fi o alegere bun, din
cauza efecturii a numeroase copii inutile a datelor text.

4.3.2.10. Tipul System.Text.StringBuilder


Considernd faptul c tipul string poate fi ineficient, biblioteca de clase .NET v pune la
dispoziie spaiul de nume System.Text, n care vei gsi clasa StringBuilder. La fel ca i clasa
System.String, StringBuilder definete metode care efectueaz operaii uzuale asupra datelor
string. Ceea ce face deosebit aceast clas este faptul c, la apelarea membrilor acestui tip,
modificai direct datele obiectului (ceea ce sporete eficiena), nu obinei o copie a datelor
n formatul modificat. Atunci cnd creai o instan a clasei, putei preciza valoarea iniial
prin intermediul unuia dintre constructori.
using System.Text;
static void Main()
{
StringBuilder sb = new StringBuilder("Limbaje de programare:");
sb.Append("\n");
sb.AppendLine("Visual C#");
sb.AppendLine("Visual Basic");
sb.AppendLine("Visual C++");
sb.AppendLine("Visual F#");
Console.WriteLine(sb.ToString());
Console.WriteLine("sb are {0} caractere\n", sb.Length);
sb.Replace("#", " Sharp");
Console.WriteLine(sb.ToString());
Console.WriteLine("sb are {0} caractere", sb.Length);
Console.ReadKey();
}

n programul de mai sus a fost construit un obiect StringBuilder setat la valoarea iniial
Limbaje de programare, apoi adugm la bufferul intern, putnd s nlocuim sau tergem
caractere. Implicit, un obiect StringBuilder poate stoca iniial un string de maxim 16
caractere, urmnd ca acesta s i mreasc automat dimensiunea la nevoie. Aceas valoare
implicit poate fi modificat prin intermediul constructorului:
// Crearea unui obiect StringBuilder cu dimensiunea initiala de 256
StringBuilder sb = new StringBuilder("Limbaje de programare", 256);

Dac adugai mai multe caractere dect limita specificat, obiectul StringBuilder i va copia
datele ntr-o nou instan i va mri bufferul cu limita specificat.

46

Elemente de baz n programarea .NET cu C#

4.3.3. Cuvntul cheie readonly


Cuvntul cheie readonly reprezint un modificator care poate fi aplicat cmpurilor. Atunci
cnd declaraia unui cmp include un modificator readonly, atribuirile ctre cmp nu pot fi
fcute dect n declaraie sau ntr-un constructor din aceeai clas.
class Varsta
{
public readonly int myVal = 100;
readonly int _an;
Varsta(int an)
{
_an = an;
}
void Modifica()
{
_an = 1980; // Eroare la compilare: valoarea nu pote fi modificata!
}
}

Cuvntul cheie readonly este diferit de cuvntul cheie const. Un cmp const poate fi iniializat
numai la declaraia acestuia. Un cmp readonly poate fi iniializat fie la declaraia acestuia, fie
n constructor. n consecin, cmpurile readonly pot avea valori diferite n funcie de
constructorul utilizat. De asemenea, un cmp const reprezint o constant la compilare, pe
cnd un cmp readonly poate fi utilizat pentru atribuirea de constante la rulare, ca n
exemplul de mai jos:
public readonly DateTime time=DateTime.Now;

4.3.4. Constante
Cuvntul cheie const se folosete pentru declararea unui cmp constant sau a unei variabile
locale, specificnd faptul c valoarea cmpului sau a variabilei locale este constant, neputnd fi modificat. La declararea constantelor este obligatorie iniializarea acestora cu valori
de tipul declarat al cmpului const.
const int x = 0;
private const string denumireLimbaj = "Visual C#";

C# pune la dispoziie cuvntul cheie const, care pare a avea aceeai semnificaie cu readonly,
chiar dac readonly se aplic numai cmpurilor. Un cmp readonly este iniializat apoi nu i
mai schimb valoarea niciodat, pe cnd un cmp const definete o valoare care este invariabil aceeai. Un cmp readonly este mult mai flexibil: acesta poate fi de orice tip, iar
valoarea acestuia poate fi calculat n timpul execuiei programului. Valoarea unui cmp
const este determinat la compilare, ceea ce limiteaz valorile disponibile. Pentru majoritatea tipurilor referin, singura valoare const suportat este null, astfel c, n practic, este
util folosirea const numai cu tipurile suportate intrinsec de compilator. Dac dorii s utilizai alte valori dect null, un cmp const trebuie s fie de tip numeric, bool, string sau tip
enumerare.
Trebuie s fii ateni la cmpurile const compilatorul consider c valoarea nu se va
modifica niciodat. Codul care citete valoarea dintr-un cmp readonly va extrage din
memorie valoarea pe care o are cmpul la rulare. ns la utilizarea unui cmp const,
compilatorul citete valoarea la compilare i o copiaz n codul dumneavoastr ca i cnd ar
fi o valoare literal. Astfel c, dac scriei o bibliotec DLL care declar un cmp const, iar
ulterior i modificai valoarea, aceast modificare nu va fi luat n considerare dect dup
recompilarea codului.
Singurul beneficiu a cmpurilor const este c acesta poate fi utilizat n anumite contexte n
care un cmp readonly nu poate. De exemplu, eticheta pentru un case dintr-un bloc switch
trebuie s fie stabilit la compilare, astfel c nu poate fi referit sub forma unui cmp

47

Medii i Tehnologii de Programare curs

readonly. n schimb putei defini un case cu ajutorul cmpurilor const. Putei de asemenea s
folosii cmpuri const n expresia care definete valoarea unui alt cmp const (cu condiia s

nu introducei referine circulare).

const double KmPerMila = 1.609344;

Aceast expresie de iniializare este opional pentru cmpurile obinuite i pentru cele
readonly. Dac omitei expresia de iniializare, atunci cmpul va fi iniializat la valoarea
implicit (0 pentru valori numerice, false pentru bool, null pentru obiecte etc.). Dac folosii
o expresie de iniializare pentru un cmp obinuit, acesta nu are nevoie s fie evaluat la
compilare, astfel c poate efectua la rulare operaii precum apeluri la metode sau citirea
proprietilor.
Iniializatorii cmpurilor non-statice ruleaz pentru fiecare instan pe care o creai i se
execut n ordinea n care apar n fiier, imediat dup rularea constructorului. Iniializatorii
cmpurilor statice se execut numai o singur dat, indiferent de numrul de instane create.
Acetia se execut de asemenea n ordinea n care sunt declarai, ns este greu de stabilit cu
exactitate cnd sunt rulai. Dac clasa nu are constructor static, C# garanteaz rularea
iniializatorilor de cmpuri nainte de prima accesare a unui cmp al clasei. Dac exist un
constructor static, atunci lucrurile sunt mai clare: iniializatorii pentru cmpurile statice
ruleaz imediat nainte de rularea constructorului static.

4.3.5. Enumerri
Cuvntul cheie enum declar un tip de dat foarte simplu care definete un set de valori care
primesc un nume. Exemplul de mai jos ilustreaz o enumerare care definete un set de
alegeri care se exclud reciproc.
public enum TemperaturaMancarii
{
PreaCalda,
PreaRece,
NumaiBuna
}

Tipurile enum sunt limitate, n sensul c nu putei defini ca membri metode sau proprieti, ci
numai constante numerice ntregi. Implicit valorile constantelor definite ntr-o declaraie
enum sunt de tip ntreg pe 32 de bii. Dac nu i este atribuit o valoare explicit, primul
membru al enumerrii primete valoarea 0, al doilea membru valoarea 1 i aa mai departe.
O enumerare poate fi utilizat n majoritatea situaiilor n care putei utiliza un tip (o variabil local, un cmp sau parametru al unei metode etc.). ns cea mai uzual modalitate de
folosire a unei enumerri este ntr-un bloc switch, precum n exemplul de mai jos.
switch (pranz.Temperatura)
{
case TemperaturaMancarii.PreaCalda:
AsteaptaPutin();
break;
case TemperaturaMancarii.PreaRece:
IncalzesteMancarea();
break;
case TemperaturaMancarii.NumaiBuna:
ConsumaMancarea();
break;
}

Precum ai observat, pentru a referi membrii enumerrii trebuie s i precedai de numele


tipului. De fapt, o enumerare reprezint o modalitate de definire a unui set de cmpuri
constante. Membrii enumerrii reprezint valori ntregi, pe care, dac dorii, le putei
specifica explicit, precum n exemplul de mai jos.

48

Elemente de baz n programarea .NET cu C#

public enum TipDesen


{
Puncte = 1,
Linii = 2,
Dreptunghiuri = 3,
Elipse = 4
}

Atributul [Flags] (sau [System.Flags]) aplicat unei enumerri permite atribuirea de valori
multiple enumerrii cu ajutorul operatorilor binari. La ntlnirea acestui atribut compilatorul va permite atribuirea enumerrii cu ajutorul operatorilor binari.
Urmtorul exemplu ilustreaz modul de utilizare i efectele atributului System.Flags asupra
declaraiei enum.
[Flags]
public enum OptiuniAuto
{
// flagul este 0001
Trapa = 0x01,
// flagul este 0010
Spoiler = 0x02,
// flagul este 0100
FaruriCeata = 0x04,
// flagul este 1000
GeamuriFumurii = 0x08
}
class Program
{
static void Main()
{
// 0001 OR 0100 = 0101
OptiuniAuto optiuni = OptiuniAuto.Trapa | OptiuniAuto.FaruriCeata;
// Numele fiecarui element care corespunde unui flag ...
// ...care are valoarea 1 in variabila optiuni
Console.WriteLine(optiuni);
// Valoarea intreaga a lui 0101 este 5.
Console.WriteLine((int)optiuni);
}
}

La rulare, programul va afia urmtorul rezultat:


Trapa, FaruriCeata
5

n lipsa atributului Flags, programul de mai sus va afia urmtoarele valori:


5
5

Avantajul major al utilizrii atributului [Flags] apare la apelarea metodei ToString pentru o
valoare enum. Pentru tipul OptiuniAuto, metoda ToString va converti valoarea 5 la stringul
Trapa, FaruriCeata, ns fr atributul Flags, aceasta ar fi tratat ca o valoare necunoscut
iar metoda ToString va returna doar stringul care conine cifra 5.
Cu acest tip de enumerare bazat pe flaguri putei ajunge s rmnei fr bii disponibili.
Implicit, o enumerare folosete tipul int pentru reprezentarea valorii, iar pentru o secven
de valori ce se exclud mutual acesta este de regul suficient. Folosind un bit pentru fiecare
flag, tipul int ofer spaiu pentru 32 de flaguri. Datorit faptului c tipurile enum pot
specifica tipul elementelor ca fiind orice tip numeric ntreg, putei, n cazul n care specificai
acest tip ca fiind long s obinei spaiu pentru 64 de flaguri.
[Flags]
public enum Optiuni : long
{

49

Medii i Tehnologii de Programare curs

//...
}

Tipurile enum pot s sporeasc uneori lizibilitatea codului. O mulime de API-uri accept
parametri bool care controleaz anumite aspecte ale comportamentului acestora, ns mult
mai util ar fi folosirea unui enum. n lipsa acestuia, numai IntelliSense v mai poate ajuta.
var sr = new StreamReader(stream, true);
var fs = new FileStream(path, FileMode.Append);

// cod opac
// claritate: utilizarea unui enum

4.4. Vectori
Un vector (ir) reprezint un set de elemente de acelai tip, care pot fi accesate printr-un
index numeric.
// Crearea unui vector de elemente int indexate cu 0, 1, 2
int[] valori = new int[3];
// Crearea unui vector de 100 de elemente string indexate de la 0 la 99
string[] carti = new string[100];

Atunci cnd declarai n C# un vector folosind aceast sintax, numrul utilizat n declaraia
vectorului nu reprezint indexul maxim, ci numrul total de elemente. Indexul primului
element din vector este ntotdeauna 0. Atunci cnd declarai un vector, ns nu i atribuii
explicit o valoare fiecrui element, elementele neatribuite vor primi valoarea implicit
pentru tipul de dat al elementelor vectorului. Astfel, un vector de valori bool va fi setat la
false, iar un vector de valori numerice ntregi va fi setat la 0.

4.4.1. Iniializarea vectorilor


C# permite ca, dup declararea vectorilor, s i putei atribui valori fiecrui element folosind
sintaxa standard de iniializare. Pentru aceasta specificai valorile fiecrui element din
vector n interiorul unei perechi de acolade. Aceast sintax poate fi util atunci cnd dorii
s creai un vector de dimensiuni cunoscute i dorii s specificai rapid valorile iniiale ale
elementelor acestuia.
// Initializarea vectorului folosind cuvantul cheie new
string[] strVector = new string[] {"unu", "doi", "trei"};
Console.WriteLine("strVector are {0} elemente", strVector.Length);
// Initializarea vectorului fara cuvantul cheie new
bool[] boolVector = {false, false, true};
Console.WriteLine("boolVector are {0} elemente", boolVector.Length);
// Initializarea vectorului folosind cuvantul cheie new si dimensiunea
int[] intVector = new int[4] { 20, 22, 23, 0 };
Console.WriteLine("intVector are {0} elemente", intVector.Length);

Observai c, atunci cnd utilizai aceast sintax de iniializare, nu este nevoie s specificai
dimensiunea vectorului, deoarece aceasta va fi dedus din numrul de elemente introduse
ntre acolade. Putei observa de asemenea c folosirea cuvntului cheie new este opional (la
construirea vectorului boolean). n cazul declaraiei vectorului de ntregi, reapelarea valorii
numerice specificate reprezint numrul de elemente din vector, nu valoarea indexului
maxim. Dac n acest caz apare vreo neconcordan ntre dimensiunea declarat i numrul
de iniializatori, vei primi o eroare de compilare:
// Eroare! Nepotrivire intre dimensiune si numarul de elemente!
int[] intVector = new int[2] { 20, 22, 23, 0 };

50

Elemente de baz n programarea .NET cu C#

4.4.2. Vectori locali cu tipul dedus


Cu ajutorul cuvntului cheie var putei aloca un vector fr a mai specifica tipul elementelor
componente:
static void Main()
{
// a este int[].
var a = new[] { 1, 10, 100, 1000 };
Console.WriteLine("a este un: {0}", a.ToString());
// b este double[].
var b = new[] { 1, 1.5, 2, 2.5 };
Console.WriteLine("b este un: {0}", b.ToString());
// c este string[].
var c = new[] { "hello", null, "world" };
Console.WriteLine("c este un: {0}", c.ToString());
}

Evident, la fel ca n cazul atribuirii explicite de elemente unui vector, elementele din lista de
iniializare trebuie s fie de acelai tip. Un vector cu tipul dedus nu va fi implicit de tip
System.Object, astfel c o astfel de declaraie va genera eroare la compilare:
// Eroare! Mai multe tipuri de elemente!
var d = new[] { 1, "doi", 3, "patru", false };

4.4.3. Definirea vectorilor de tip System.Object


n majoritatea cazurilor, atunci cnd definii un vector, specificai n mod explicit tipul
elementelor pe care acesta le va conine. Dat fiind faptul c System.Object este clas de baz
pentru toate tipurile C#, putei defini un vector de tip, iar elementele s fie de orice tip.
static void Main()
{
// un vector de tip object poate primi elemente de orice tip
object[] myObj = new object[4];
myObj [0] = 10;
myObj[1] = false;
myObj[2] = new DateTime(1989, 12, 22);
myObj[3] = "Visual C#";
foreach (object obj in myObj)
{
// Afiseaza tipul si valoarea fiecarui element din vector
Console.WriteLine("Tip: {0}, Valoare: {1}", obj.GetType(), obj);
}
}

Metoda System.Object.GetType() poate fi utilizat pentru a obine numele complet al tipului


unui element. La rulare aplicaia va afia urmtoarele:
Tip:
Tip:
Tip:
Tip:

System.Int32, Valoare: 10
System.Boolean, Valoare: False
System.DateTime, Valoare: 22.12.1989 0:00:00
System.String, Valoare: Visual C#

4.4.4. Vectori multidimensionali


n plus fa de vectorii unidimensionali prezentai pn acum, C# suport dou tipuri de
vectori multidimensionali. Primul dintre acestea se numete matrice i reprezint un vector
multidimensional n care fiecare rnd are aceeai lungime.
static void Main()
{
// O matrice

51

Medii i Tehnologii de Programare curs

int[,] myMatr;
myMatr = new int[6, 6];
// Popularea matricei de 6 x 6
for (int i = 0; i < 6; i++)
for (int j = 0; j < 6; j++)
myMatr[i, j] = i * j;
// Afisarea matricei de 6 x 6
for (int i = 0; i < 6; i++)
{
for (int j = 0; j < 6; j++)
Console.Write(myMatr[i, j] + "\t");
Console.WriteLine();
}
}

La rulare aplicaia va afia:


0
0
0
0
0
0

0
1
2
3
4
5

0
2
4
6
8
10

0
3
6
9
12
15

0
4
8
12
16
20

0
5
10
15
20
25

Al doilea tip de vector multidimensional este numit jagged array. Aa cum indic i
denumirea, acesta conine un numr de vectori interni, fiecare dintre ei putnd avea
dimensiuni diferite. De exemplu:
static void Main()
{
// Jagged array (un vector de 5 vectori)
int[][] myJagArray = new int[5][];
// Creare jagged array
for (int i = 0; i < myJagArray.Length; i++)
myJagArray[i] = new int[i + 7];
// Afisare rand cu rand (valoarea implicita a elementelor este 0)
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < myJagArray[i].Length; j++)
Console.Write(myJagArray[i][j] + " ");
Console.WriteLine();
}
}

La rulare aplicaia va afia:


0
0
0
0
0

0
0
0
0
0

0
0
0
0
0

0
0
0
0
0

0
0
0
0
0

0
0
0
0
0

0
0
0
0
0

0
0
0
0

0
0
0

0
0

4.4.5. Vectori ca argumente sau valori returnate


Dup ce ai creat un vector, suntei liberi s l transmitei ca argument sau s l primii ca
rezultat al unei funcii. De exemplu, metoda AfisareVector() primete ca argument un vector
de ntregi i afieaz fiecare membru, iar metoda ReturnareVector() populeaz un vector de
stringuri i l returneaz la apelant:
static void AfisareVector(int[] myInts)
{
for(int i = 0; i < myInts.Length; i++)
Console.WriteLine("Elementul {0} = {1}", i, myInts[i]);
}
static string[] ReturnareVector()

52

Elemente de baz n programarea .NET cu C#

{
string[] myStrings = { "Vector", "returnat", "de", "metoda" };
return myStrings;
}

Metodele care primesc argumente de tip vectori i cele care returneaz valori de tip vectori
pot fi apelate ca orice alt metod.
Dac pn acum am prezentat modul de definire, populare i examinare a coninutului unui
vector, n continuare vom prezenta rolul clasei System.Array.

4.4.6. Clasa System.Array


Fiecare vector pe care l creai primete o bun parte din funciile oferite de clasa
System.Array. Folosind membrii acesteia, putei opera cu datele unui vector prin intermediul
unui model obiect consistent. Tabelul 4.11 prezint civa dintre cei mai utili membri ai
clasei System.Array.
Membru
Clear()
CopyTo()
Length
Rank
Reverse()
Sort()

Semnificaie
Seteaz un domeniu de elemente ale vectorului la 0, false sau null, n funcie de tipul
acestora.
Copiaz elementele dintr-un vector surs ntr-unul destinaie.
Returneaz numrul de elemente ale unui vector.
Returneaz numrul de dimensiuni ale vectorului curent.
Metod static ce inverseaz coninutul unui vector unidimensional.
Metod static ce sorteaz un vector unidimensional de elemente de tip intrinsec.
Dac elementele din vector implementeaz interfaa IComparer, putei sorta
elemente de orice tip.
Tabelul 4.11. Membri ai clasei System.Array

n exemplul de mai jos putei observa modul de folosire a metodele statice Reverse() i
Clear().
static void Main()
{
string[] limbajeProgramare = { "Java", "Visual Basic", "Visual C#" };
// Afisarea elementelor in ordine
Console.WriteLine("Vectorul este:");
for (int i = 0; i < limbajeProgramare.Length; i++)
Console.Write(limbajeProgramare[i] + ", ");
Console.WriteLine("\n");
// Inversarea elementelor
Array.Reverse(limbajeProgramare);
Console.WriteLine("Vectorul inversat:");
for (int i = 0; i < limbajeProgramare.Length; i++)
Console.Write(limbajeProgramare[i] + ", ");
Console.WriteLine("\n");
// Stergerea tuturor elementelor in afara de ultimul
Console.WriteLine("Sterge toate elementele in afara de unul...");
Array.Clear(limbajeProgramare, 1, 2);
for (int i = 0; i < limbajeProgramare.Length; i++)
Console.Write(limbajeProgramare[i] + ", ");
}

La rulare aplicaia va afia:


Vectorul este:
Java, Visual Basic, Visual C#,
Vectorul inversat:
Visual C#, Visual Basic, Java,
Sterge toate elementele in afara de unul...

53

Medii i Tehnologii de Programare curs

Visual C#, , ,

Observai c muli membri ai clasei System.Array sunt definii ca membri statici, fiind apelai
la nivel de clas (Array.Sort(), Array.Reverse()). Acestor metode le este pasat vectorul pe care
dorii s l prelucrai. Ali membri ai clasei System.Array sunt apelate la nivel de obiect, astfel
c putei s i invocai direct pentru vectorul n cauz.

4.4.7. Copierea vectorilor


C# suport atribuirea de vectori, ns rezultatul este diferit de ceea ce v-ai atepta deoarece
un vector .NET este un tip referin. Iat n continuare care este diferena dat de tipul
referin al unui vector:
int[] arr1 = { 0, 111, 222, 333 };
// Creeaza o noua referinta la vector
int[] arr2 = arr1;
// Modifica vectorul prin intermediul celei de a doua variabile
arr2[1] = 999;
// Vectorul original a fost modificat si el
Console.WriteLine(arr1[1]);
// => 999

Putei copia un vector prin crearea unui nou vector, ale crui elemente s fie copii ale
elementelor din vectorul original, prin intermediul metodei Clone() pe care o expune clasa
System.Array. Aceast metod creeaz o copie a vectorului original i returneaz o referin la
aceast copie. Iat cum ar arta exemplul precedent rescris prin folosirea metodei Clone:
int[] arr3 = {0,111,222,333};
// Creeaza o copie a vectorului
int[] arr4 = (int[])arr3.Clone();
// Modificam un element din noul vector
arr4[1] = 999;
// Vectorul original nu a fost afectat
Console.WriteLine(arr3[1]);
// => 111

Metoda Clone() returneaz o valoare de tip object, iar atribuirea este de fapt o conversie de
tip narrowing conversion. De aceea este nevoie de utilizarea operatorului cast pentru conversia de la object la int[].
Este permis atribuirea unui vector de elemente de tip referin (de exemplu, String) unui
alt vector de elemente Object. Urmtoarea secven de cod va rula fr erori:
string[] strArr = { "00", "11", "22", "33", "44" };
object[] objArr = strArr;
Console.WriteLine(objArr[2]); // => 22

4.5. Operatori logici i condiionali


La fel ca i n cazul celorlalte limbaje din familia C, operatorii logici AND i OR ar trebui s v
fie familiari. Acetia evalueaz al doilea operand numai dac este necesar. De exemplu, la
evaluarea expr1 && expr2, dac expresia expr1 este false, atunci codul generat de compilator
nu va mai ajunge s evalueze expr2, deoarece rezultatul final va fi false, indiferent de
valoarea pe care o va avea expr2. Invers, operatorul condiional OR nu va mai evalua al doilea
operand dac primul este true, deoarece rezultatul final va fi true indiferent de valoarea
celui de al doilea operand. Acest aspect este important dac expresia din al doilea operand
are efecte secundare (de exemplu, include apelul unei metode) sau poate produce o eroare.
Pentru exemplificare, putei observa adesea secvene de cod precum cea de mai jos:
if (s != null && s.Length > 10)
//...

54

Elemente de baz n programarea .NET cu C#

Aici se verific dac variabila s conine valoarea null, ceea ce nseamn c aceasta nu se
refer la nicio valoare. Utilizarea operatorului && n acest caz este important, deoarece dac
s este null, evaluarea expresiei s.Length ar provoca apariia unei erori. Dac am utiliza
operatorul &, compilatorul ar genera cod care va evalua ambii operanzi, ceea ce nseamn c
la rulare am primi o excepie de tip NullReferenceException dac s este null, ns utilizarea
operatorului condiional evit acest lucru, deoarece operandul s.Length > 10 va fi evaluat
numai dac s nu este null.
Operaia x && y corespunde operaiei x & y, cu excepia c dac x este false, y nu este evaluat.
Acest evaluare este cunoscut sub numele de evaluare scurtcircuit, iar operatorii se mai
numesc operatori de scurtcircuitare.
class Program
{
static void Main()
{
Console.WriteLine("*** Operatorul AND:");
if (Metoda1() & Metoda2())
Console.WriteLine("Ambele metode au returnat true.");
else
Console.WriteLine("Cel putin o metoda a returnat false.");
Console.WriteLine("\n*** Operatorul de scurtcircuitare AND:");
if (Metoda1() && Metoda2())
Console.WriteLine("Ambele metode au returnat true.");
else
Console.WriteLine("Cel putin o metoda a returnat false.");
Console.ReadKey();
}
static bool Metoda1()
{
Console.WriteLine("Metoda1 a fost apelata.");
return false;
}
static bool Metoda2()
{
Console.WriteLine("Metoda2 a fost apelata.");
return true;
}
}

La ieire va fi afiat:
*** Operatorul AND:
Metoda1 a fot apelata.
Metoda2 a fot apelata.
Cel putin o metoda a returnat false.
*** Operatorul de scurtcircuitare AND:
Metoda1 a fot apelata.
Cel putin o metoda a returnat false.

4.6. Metode
Metodele reprezint secvene de cod denumite care, opional, pot returna un rezultat i care
pot primi argumente. C# face distincie ntre parametri i argumente: o metod definete o
list de intrri parametrii, iar codul din interiorul metodei se refer la acetia prin nume.
Valorile vzute de cod pot s difere de fiecare dat cnd metoda este invocat, iar argumentele se refer la valoarea specific transmis unui parametru la o invocare.

55

Medii i Tehnologii de Programare curs

Atunci cnd un exist un specificator de acces, acesta apare la nceputul declaraiei metodei.
Urmeaz cuvntul cheie opional static, apoi declaraia metodei stabilete tipul returnat. n
cazul n care metoda nu returneaz nimic n locul tipului returnat va aprea cuvntul cheie
void. n interiorul metodei vei utiliza cuvntul cheie return urmat de expresia care specific
valoarea returnat de metod. n cazul unei metode void, putei utiliza cuvntul cheie return
fr nicio alt expresie, ns acest lucru este opional, deoarece o metod void va returna
oricum la terminarea execuiei acesteia.
n principiu, C# suport ca o metod s returneze numai un singur tip. Totui, este posibil ca
o metod s returneze valori multiple, deoarece putei alege parametri ca ieire nu ca
intrare. Exemplul de mai jos returneaz dou valori, ambele produse de mprirea
ntregilor. Principala valoare returnat este rezultatul, ns mai returneaz i restul
mpririi prin ultimul parametru, care a fost marcat cu cuvntul cheie out.
public static int Imparte(int x, int y, out int rest)
{
rest = x % y;
return x / y;
}

La invocarea unei astfel de metode este obligatorie utilizarea cuvntului cheie out. Unele
limbaje din familia C nu fac nicio distincie vizual ntre apelurile care transmit valori i cele
care transmit referine, ns semantica difer, astfel c C# face totul explicit.
int r;
// Apelul unei metode cu un parametru out
int q = Imparte(10, 3, out r);

Secvena de cod de mai sus ruleaz prin transmiterea unei referine la variabila r, astfel c
atunci cnd metoda Imparte atribuie o valoare n rest, o atribuie efectiv variabilei r a
apelantului. Acesta este de tip int, care este un tip valoare, astfel c n mod normal nu ar fi
transmis prin referin, iar acest tip de referin este limitat. Numai argumentele metodelor
pot utiliza aceast caracteristic. Nu putei declara o variabil local sau un cmp care s
rein o astfel de referin, deoarece referina este valid numai pe durata apelului.
O referin out necesit ca informaia s fie transmis de la metod napoi la apelant: dac
metoda returneaz fr a atribui ceva n toate argumentele out, vei primi eroare la
compilare (aceast cerin nu se aplic dac metoda arunc o excepie n loc s returneze).
Exist un cuvnt cheie asemntor ref, care are o semantic similar, ns care permite flux
de informaii bidirecional. n cazul unui argument ref metoda are acces direct la variabila pe
care apelantul o transmite (putem citi i modifica valoarea acesteia). Apelantul este obligat
s se asigure c orice variabile transmise cu ref conin o valoare nainte de a efectua apelul
astfel c, n acest caz, metoda nu mai este obligat s modifice valorile. Dac apelai o metod
cu un parametru notat cu ref, trebuie s indicai clar faptul c intenionai s transmitei o
referin la o variabil ca argument.
long x = 41;
Operatii.Increment(ref x); // Apelul unei metode ref

Putei utiliza cuvintele cheie out i ref i pentru tipurile referin. Aceasta poate suna redundant, ns poate fi util, deoarece ofer indirectare dubl metoda primete o referin la o
variabil care stocheaz o referin. n mod normal, atunci cnd transmitei un argument de
tip referin ctre o metod, acea metod primete acces la obiectul pe care i-l transmitei,
astfel c att timp ct metoda poate utiliza membrii acelui obiect, nu l poate nlocui cu un
obiect diferit. ns dac marcai un argument de tip referin cu ref, metoda are acces la
variabil i o poate nlocui cu o referin la un obiect complet diferit.
Argumentele constructorilor funcioneaz la fel ca la orice metod, astfel c putei utiliza out
i ref i la constructori. Cuvintele cheie out i ref fac parte din semntura metodei. Apelantul
transmite un argument out sau ref dac i numai dac parametrul a fost declarat ca out sau
ref. Nu putei decide s transmitei un argument prin referin unei metode care nu ateapt
aa ceva. Argumentele metodelor pot fi fcui opionali prin definirea de valori implicite.
Exemplul de mai jos specific valorile pe care argumentele ar trebui s le aib dac apelantul

56

Elemente de baz n programarea .NET cu C#

nu le-ar transmite. Aceasta metod poate fi apelat apoi chiar i fr argumente, cu un


argument sau cu ambele argumente.
// O metoda cu parametri optionali
public void Afiseaza(string titlu = "domnul", string nume = "Ionescu")
{
Console.WriteLine("Urmatorul client este {0} {1}.", titlu, nume);
}

n mod normal, cnd invocai o metod specificai argumentele n ordine. Totui, ce se


ntmpl dac dorii s apelai metoda de mai sus, ns dorii s transmitei o valoare pentru
al doilea argument, folosind pentru primul valoarea implicit? Dac ai lsa primul argument
gol ai primi eroare.
Afiseaza(,"Popescu"); // Eroare

Ce putei face este s specificai numele argumentului pe care dorii s l transmitei folosind
sintaxa artat n exemplul de mai jos. C# va nlocui argumentele omise cu valorile implicite
specificate.
// Specificarea numelui unui argument
Afiseaza(nume: "Popescu");

Evident, aceasta funcioneaz numai la invocarea metodelor care definesc valori implicite
pentru argumente. Totui, suntei liberi s specificai numele argumentelor la invocarea
oricrei metode uneori acest lucru poate fi util chiar dac nu omitei vreun argument,
deoarece poate face mai clar semnificaia argumentelor atunci cnd citii codul surs.
Cnd invocai o metod fr a-i transmite toate argumentele, compilatorul genereaz cod
care transmite un set complet de argumente, practic rescriind codul dumneavoastr prin
adugarea napoi a argumentelor lsate deoparte.
Uneori vei observa un mecanism alternativ care permite omiterea argumentelor: suprancrcarea, care semnific faptul c unui singur nume sau simbol i pot fi date mai multe
nelesuri.
public void Afiseaza(string titlu, string nume)
{
Console.WriteLine("Urmatorul client este {0} {1}.", titlu, nume);
}
public void Afiseaza(string titlu)
{
Afiseaza(titlu, "Ionescu");
}
public void Afiseaza()
{
Afiseaza("domnul", "Ionescu");
}

ntr-un anumit sens acest mecanism este mai puin flexibil dect cel de utilizare a valorilor
implicite pentru argumente, deoarece nu avei cum s mai specificai o valoare pentru
argumentul nume la alegerea titlului implicit. Pe de alt parte, suprancrcarea metodelor
ofer dou poteniale avantaje: v permite s decidei asupra valorilor implicite la rulare,
dac este nevoie, i ofer o modalitate prin care putei s operai cu argumente out i ref.
Acestea necesit referine la variabile locale, astfel c nu putei defini o valoare implicit,
ns putei oferi suprancrcri cu i fr aceste argumente, dac avei nevoie.

4.6.1. Metode de extensie


C# v permite s scriei metode care par a fi noi membri ai tipurilor existente. O metod de
extensie, la fel cum i spune i numele, arat ca o metod static obinuit, ns avnd

57

Medii i Tehnologii de Programare curs

cuvntul cheie this adugat la primul parametru. Putei defini metode de extensie numai ca
membri ai claselor statice. Exemplul de mai jos adaug o metod de extensie tipului string:
namespace MyApp
{
public static class StringExtension
{
public static int WordCount(this string s)
{
return s.Split(new char[] { ' ', ',', '.' },
StringSplitOptions.RemoveEmptyEntries).Length;
}
}
}

Am inclus n exemplu i declaraia spaiului de nume deoarece spaiile de nume sunt importante: metodele de extensie sunt disponibile numai dac ai scris o directiv using pentru
spaiul de nume n care este definit extensia, sau dac codul scris este definit n acelai
spaiu de nume. n caz contrar, clasa string va arta normal, fr metoda Show.
// Metoda de extensie este disponibila pentru ca este declarata in acelasi spatiu de nume
namespace MyApp
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello, world! I am a new extension method".WordCount());
}
}
}

Codul de mai jos este plasat ntr-un spaiu de nume diferit, ns are acces la metoda de
extensie din cauza utilizrii directivei using.
// Metoda de extensie este disponibila din cauza utilizarii directivei using
using MyApp;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello, world!".WordCount());
}
}
}

Metodele de extensie nu sunt n realitate membri ai claselor pentru care sunt definite (n
exemplul de mai sus clasa string nu va dobndi o nou metod), acest lucru fiind doar o
iluzie meninut de compilatorul C#. Acest mecanism poate fi util atunci cnd avei nevoie de
anumite funcii. Putei activa aceste caracteristici de limbaj pentru tipuri care nu le suport
direct, prin scrierea unor metode de extensie potrivite.

4.7. Proprieti
O proprietate reprezint un membru care ofer un mecanism flexibil de citire, scriere sau
calculare a valorii unui cmp privat. Proprietile pot fi utilizate ca orice ali membri publici,
ns acestea sunt de fapt metode speciale numite accesori. Acest lucru permite accesarea
uoar a datelor i ajut la promovarea siguranei i flexibilitii metodelor. Proprietile
permit unei clase s expun un mod public de obinere i setare a valorilor, n timp ce
implementarea sau codul pentru verificare sunt ascunse.

58

Elemente de baz n programarea .NET cu C#

n exemplul de mai jos, clasa IntervalTimp stocheaz un interval de timp. Intern, clasa
stocheaz timpul n secunde, ns proprietatea Ore permite unui client s specifice timpul n
ore. Accesorii pentru proprietatea Ore efectueaz conversia ntre ore i secunde.
class IntervalTimp
{
private double secunde;
public double Ore
{
get { return secunde / 3600; }
set { secunde = value * 3600; }
}
}
class Program
{
static void Main()
{
IntervalTimp t = new IntervalTimp();
// Apelarea accesorului 'set'
t.Ore = 24;
// Apelarea accesorului 'get'
System.Console.WriteLine("Timpul in ore: " + t.Ore);
}
}

Aplicaia va afia la rulare:


Timpul in ore: 24

Exemplul de mai jos ilustreaz un ablon uzual: o proprietate cu accesori get i set, care ofer
acces la un cmp. De ce s nu facem acel cmp public? Pentru c acest lucru ar permite
codului extern s modifice statusul unui obiect fr ca obiectul s tie acest lucru. Ar putea fi
nevoie s scriei ulterior cod pentru ca obiectul s efectueze anumite operaii ori de cte ori
se modific valoarea. Un alt motiv pentru utilizarea proprietilor ar fi faptul c unele tipuri
nu suport cmpuri, ci numai proprieti (de exemplu, interfeele).
Accesorul get returneaz o valoare de tipul proprietii, iar accesorul set primete
parametrul implicit value, de acelai tip cu cel al proprietii, folosit pentru atribuirea unei
noi valori. Nu suntei obligai s folosii acea valoare pentru a o stoca ntr-un cmp; putei
scrie orice cod n interiorul celor dou metode. Oricum, o proprietate este vizibil din
exterior ca un cmp oarecare.
La declararea unei proprieti putei ignora accesorul set pentru a obine o proprietate readonly sau accesorul get pentru a obine o proprietate write-only. Proprietile read-only pot fi
utile pentru aspecte fixe ale unui obiect (de exemplu, un identificator). Accesorii unei
proprieti pot avea diferite niveluri de acces. Putei, de exemplu, s definii proprieti n
care accesorul get s fie public iar set privat.
public int Varsta { get; private set; }

4.8. Indexatori
Indexatorii reprezint o convenie de sintax care permit crearea unei clase, structuri sau
interfee pe care aplicaiile client le pot accesa ntocmai ca pe un vector. Indexatorii sunt cel
mai frecvent implementai n tipurile ale cror scop principal este s ncapsuleze o colecie
intern sau un vector.
S presupunem c avem o clas Temperaturi care reprezint temperatura msurat la 10
momente de timp diferite pe parcursul unui interval de 24 de ore. Clasa conine vectorul temp

59

Medii i Tehnologii de Programare curs

care reprezint temperaturile. Prin implementarea unui indexator n aceast clas, clienii
pot accesa temperaturile dintr-o instan a clasei sub forma
float temp = tr[4]

n loc de
float temp = tr.temps[4]

Notaia indexatorului nu numai simplific sintaxa pentru aplicaiile client, ci face clasa mai
uor de neles pentru ali dezvoltatori.
Pentru declararea unui indexator al unei clase, folosii cuvntul cheie this, ca n exemplul de
mai jos:
class Temperaturi
{
private float[] temps = new float[10] { 16.2F, 16.7F, 16.5F, 16.9F, 18.8F,
21.3F, 25.9F, 22.1F, 19.2F, 17.5F };
// Declaratia indexatorului
public float this[int index]
{
get
{
return temps[index];
}
set
{
temps[index] = value;
}
}
}
class Program
{
static void Main()
{
Temperaturi temp = new Temperaturi();
temp[3] = 18.3F;
temp[5] = 20.1F;
for (int i = 0; i < 10; i++)
{
System.Console.WriteLine("Elementul {0} = {1}", i, temp[i]);
}
System.Console.ReadKey();
}
}

Aplicaia va afia la ieire:


Element
Element
Element
Element
Element
Element
Element
Element
Element
Element

#0
#1
#2
#3
#4
#5
#6
#7
#8
#9

=
=
=
=
=
=
=
=
=
=

16.2
16.7
16.5
18.3
18.8
20.1
25.9
22.1
19.2
17.5

C# nu limiteaz tipul indexului la int. De exemplu, ar putea fi util folosirea unui string
mpreun cu un indexator. Un astfel de indexator ar putea fi implementat prin cutarea dup
string n colecie i returnarea valorii potrivite. Dac accesorii get i set sunt suprancrcai
atunci versiunile string i int pot s co-existe.
Cu ajutorul accesorilor get i set putei declara indexatori read-only sau read-write. De asemenea, putei s declarai indexatori multidimensionali.

60

Elemente de baz n programarea .NET cu C#

4.8.1. Diferene dintre proprieti i indexatori


Indexatorii sunt n mare msur asemntori cu proprietile. Exceptnd diferenele
prezentate n Tabelul 4.12, toate regulile definite pentru accesorii proprietilor se aplic i
pentru cei ai indexatorilor.
Proprietate
Permite metodelor s fie apelate ca i cnd ar fi
membri publici.
Accesat printr-un nume simplu.
Poate fi static sau membru al unei instane.
Accesorul get al unei proprieti nu are
parametri.
Accesorul set al unei proprieti conine
parametrul value implicit.

Indexator
Permite elementelor unei colecii interne a unui
obiect s fie accesate prin utilizarea notaiei
vectoriale asupra obiectului nsui.
Accesat printr-un index.
Trebuie s fie membru al unei instane.
Accesorul get al unui indexator are acelai
parametru formal ca i indexatorul.
Accesorul set al unui indexator are acelai
parametru formal ca i indexatorul i de asemenea
parametrul value.

Tabelul 4.12. Cteva diferene dintre proprieti i indexatori.

4.9. Clase
O clas reprezint o structur de date care permite crearea unor tipuri personalizate, putnd
grupa mpreun mai multe tipuri de elemente, cum ar fi: cmpuri, metode, evenimente etc. O
clas este ntocmai unui plan care definete datele i comportamentul unui tip. Dac clasa nu
este declarat ca static, codul client o poate folosi prin crearea obiectelor sau instanelor
clasei. Ele rmn n memorie pn la prsirea domeniului de vizibilitate a tuturor
referinelor la acestea, dup care CLR le marcheaz ca eligibile pentru garbage collector.
Dac clasa este declarat ca static, atunci n memorie exist numai o singur copie iar codul
client o poate accesa prin intermediul clasei nsi, nu prin numele unei instane.
Clasele ofer un mecanism pentru ncapsulare ele pot defini o interfa programabil
public pentru utilizarea de ctre programatori, n timp ce detaliile de implementare intern
rmn inaccesibile. Exemplul de mai jos prezint declaraia unei clase.
public class Contor
{
private int _val;
public int GetNextVal()
{
_val += 1;
return _val;
}
}

Cu toate c adesea sunt confundate, o clas i un obiect sunt lucruri diferite. O clas definete
un tip de obiect, ns nu este obiectul nsui. Un obiect este o entitate concret bazat pe o
clas, uneori fiind referit ca instan a unei clase. Obiectele pot fi create prin utilizarea
cuvntului cheie new urmat de numele clasei de tipul creia va fi obiectul:
Contor c1 = new Contor
Contor c2 = new Contor
Console.WriteLine("c1:
Console.WriteLine("c1:
Console.WriteLine("c1:
Console.WriteLine("c2:
Console.WriteLine("c1:

();
();
" +
" +
" +
" +
" +

c1.GetNextVal());
c1.GetNextVal());
c1.GetNextVal());
c2.GetNextVal());
c1.GetNextVal());

61

Medii i Tehnologii de Programare curs

Atunci cnd este creat o instan a unei clase, este pasat napoi ctre programator o
referin la obiect. n exemplul anterior, c1 este o referin la un obiect de tip Contor. Putei s
creai o referin la un obiect chiar fr s creai obiectul:
Contor c3;

Nu se recomand crearea n acest fel a referinelor la obiecte, deoarece ncercarea de


accesare a unui astfel de obiect va genera la rulare o eroare de tip NullReferenceException.
Totui, o astfel de referin poate fi fcut s pointeze spre un obiect, fie prin crearea unui
obiect nou, fie prin atribuirea ctre aceasta a unui obiect existent:
Contor c4 = new Contor ();
Contor c5 = c4;

Acest cod creeaz dou referine la obiecte care pointeaz spre acelai obiect. n consecin,
orice modificare asupra obiectului fcut prin intermediul lui c4 va fi reflectat i n obiectul
c5. Deoarece obiectele de tipul unor clase sunt adresate prin referin, clasele sunt cunoscute
ca tipuri referin.
C# nu necesit ca numele clasei s fie acelai cu numele fiierului surs, nici nu v limiteaz
la a avea o singur clas ntr-un fiier. Totui, prin convenie, proiectele C# conin clasele n
fiiere cu acelai nume.
n declaraia clasei Contor a fost folosit cuvntul cheie public. Opional, definiiile de clase pot
specifica accesibilitatea, care stabilete codul cruia i este permis s foloseasc clasa. Clasele
declarate la nivel de spaii de nume au doar dou posibiliti: public i internal, ultimul fiind
modificatorul de acces implicit. O clas intern este disponibil pentru utilizare numai n
interiorul componentei n care este declarat, astfel c, dac dorii s scriei o bibliotec de
clase, suntei liberi s definii att clase publice, ct i clase pe care numai componentele
bibliotecii le pot accesa.
Membrii claselor, incluznd aici i clasele ncuibate, pot avea urmtorii modificatori de
acces: public, protected internal, protected, internal sau private (modificatorul implicit).
Modificatorii de acces sunt opionali att pentru membri ct i pentru clase, modificatorul
implicit fiind cel mai restrictiv disponibil, n acest caz, private. Se recomand, totui,
precizarea explicit a modificatorilor de acces pentru claritatea codului (persoanele care vor
citi codul dumneavoastr nu vor ti dac omiterea unui modificator de acces a fost
intenionat sau accidental).
Definiiile claselor, structurilor, interfeelor sau a metodelor pot fi mprite ntre dou sau
mai multe fiiere surs cu ajutorul cuvntului cheie partial. Fiecare fiier surs conine o
parte din definiia tipului sau a metodei, iar la compilare toate prile sunt combinate. Acest
lucru poate fi util atunci cnd lucrai cu proiecte mari. Visual Studio folosete aceast
abordare, de exemplu, la proiectele de tip Windows Forms.
O clas poate conine declaraii ale urmtoarelor tipuri de membri: constructori, destructori,
constante, cmpuri, metode, proprieti, indexatori, operatori, evenimente, delegai, clase,
interfee, structuri.
Folosirea cmpurilor publice nu este o practic recomandat deoarece permite oricrei
metode de oriunde din program acces nerestricionat i neverificat la mecanismele interne
ale unui obiect. n general, cmpurile ar trebui s fie private, iar accesul la ele s fie fcut
numai prin metode sau proprieti ale clasei.

4.9.1. Membri statici


Cuvntul cheie static adugat la declaraia unui membru semnific faptul c membrul
aparine clasei, nefiind asociat cu nicio instan a clasei. Membrii statici pot fi apelai chiar
dac nu a fost creat nicio instan a clasei, fiind accesai prin numele clasei. Indiferent de
numrul de instane ale clasei, exist numai o singura copie a membrilor statici.

62

Elemente de baz n programarea .NET cu C#

Cmpurile statice de obicei sunt utilizate pentru a pstra numrul de instane ale clasei sau
pentru a stoca o valoare care trebuie partajat ntre toate instanele clasei. n C# nu putei
declara variabile locale statice.
Exemplul de mai jos arat o versiune modificat a clasei Contor, cu doi noi membri statici:
public class Contor
{
private int _val;
private static int _total;
public int GetNextVal()
{
_val += 1;
_total += 1;
return _val;
}
public static int Total
{
get
{
return _total;
}
}
}
Total este o proprietate public read-only care returneaz valoarea membrului privat _total.
Cmpul static _total reine numrul total de apeluri ale metodei GetNextVal, spre deosebire
de membrul non-static _val, care reine numrul de apeluri numai pentru instana curent.

n codul din cadrul clasei, cmpurile statice sunt utilizate n acelai mod n care sunt utilizate
cmpurile non-statice. Diferena dintre cele dou apare la apelarea lor n codul din afara
clasei: un membru static poate fi accesat prin numele clasei.
Console.WriteLine(Contor.Total);

//5

n exemplul de mai sus sunt utilizate de fapt doi membri statici: proprietatea Total i metoda
WriteLine din clasa Console.
Metodele i proprietile statice nu pot accesa cmpurile i evenimentele non-statice din
aceeai clas i nici nu pot accesa vreo instan a unei clase dect dac aceasta este
transmis explicit ntre parametrii metodei. Deoarece proprietatea Total a fost declarat ca
static, codul pe care l conine are acces numai la ali membri statici. Dac am fi ncercat s
utilizm un membru non-static, de exemplu cmpul _val, compilatorul ar fi generat
urmtorul mesaj de eroare:
error CS0120: An object reference is required for the non-static field, method, or property
'ConsoleApplication1.Contor._val'

Membrii statici sunt iniializai nainte de prima accesare a acestora i nainte de apelarea
constructorului static, dac exist vreunul. Dac o clas conine cmpuri statice, putei
declara un constructor static care s le iniializeze atunci cnd clasa este ncrcat.
Deoarece cmpurile non-statice sunt asociate cu o anumit instan a clasei din care fac
parte, C# are nevoie s cunoasc ce instan s foloseasc. n cazul unei metode sau
proprieti non-statice poate fi utilizat orice instan pentru invocarea acestora. n
exemplul de mai sus, a fost scris fie c1.GetNextVal(), fie c2.GetNextVal(), pentru alegerea unuia
dintre cele dou instane ale clasei. C# a transmis referina stocat n c1 sau c2, dup caz, ca
un prim parametru implicit. Pe acesta o putei accesa folosind cuvntul cheie this. Astfel,
prima linie din metoda GetNextVal ar fi putut fi scris astfel:
this._val += 1;

Acest mod de scriere indic explicit faptul c ne referim la membrul _val al instanei pentru
care a fost invocat metoda GetNextVal. Accesarea explicit a membrilor prin cuvntul cheie
this este uneori necesar din motive de suprapunere a numelor unor variabile. Metodele
statice nu folosesc cuvntul cheie this deoarece acestea nu sunt asociate cu nicio instan
anume.

63

Medii i Tehnologii de Programare curs

Metodele statice pot fi suprancrcate, ns nu pot fi suprascrise, deoarece ele aparin clasei,
nu vreunei instane a clasei.
Dei un cmp nu poate fi declarat ca static const, un cmp const se comport ca un cmp
static. Acesta aparine clasei, nu instanelor acesteia. Aadar, cmpurile const pot fi accesate
prin aceeai notaie NumeClas.NumeMembru folosit pentru cmpuri statice, nefiind nevoie de
vreo instan.

4.9.2. Constructori i destructori


Ori de cte ori este creat o clas sau o structur, constructorul acesteia este apelat. O clas
sau o structur pot avea mai muli constructori care primesc argumente diferite. Constructorii au acelai nume cu cel al clasei sau structurii i sunt folosii de regul pentru
iniializarea membrilor noului obiect.
n exemplul de mai jos, clasa Taxi definete un constructor simplu. Apoi aceast clas este
instaniat cu operatorul new. Constructorul este invocat de ctre operatorul new imediat dup
ce este alocat memoria pentru noul obiect.
public class Taxi
{
public bool esteOcupat;
public Taxi()
{
esteOcupat = true;
}
}
class TestTaxi
{
static void Main()
{
Taxi t = new Taxi();
Console.WriteLine(t.esteOcupat);
}
}

Un constructor care nu primete parametri este numit constructor implicit. Acetia sunt
invocai ori de cte ori este instaniat un obiect prin utilizarea operatorului new, nefiind
transmis ctre new nici un argument.
Declararea de constructori cu parametri este util pentru iniializarea cmpurilor clasei.
Dac nu creai un constructor pentru obiectul dumneavoastr, C# va crea unul implicit care
instaniaz obiectul i seteaz variabilele membre la valorile implicite. Clasele statice nu
primesc automat un constructor implicit.
Dac dorii ca o clas s nu poat fi instaniat, facei constructorul acesteia privat.
Constructorii pentru tipuri struct se aseamn cu cei ai claselor, ns structurile nu pot
conine un constructor explicit fr parametri, deoarece acesta este furnizat automat de
ctre compilator. Acest constructor iniializeaz fiecare cmp din structur la valoarea
implicit. Totui, acest constructor este invocat numai dac structura este instaniat cu
operatorul new. De exemplu, codul de mai jos folosete constructorul implicit pentru tipul
Int32, astfel c suntei siguri c ntregul este iniializat:
int i = new int();
Console.WriteLine(i);

Codul de mai jos va genera o eroare la compilare deoarece nu folosete operatorul new i
pentru c ncearc s foloseasc un obiect care nu a fost iniializat:
int i;
Console.WriteLine(i); // Eroare

64

Elemente de baz n programarea .NET cu C#

Att clasele ct i structurile pot defini constructori cu parametri, care trebuie apelai prin
new sau base. Clasele i structurile pot de asemenea s defineasc constructori multipli,
nefiind nevoie de definirea unui constructor implicit. De exemplu:
public class Angajat
{
public int salariu;
public Angajat(int salariuAnual)
{
salariu = salariuAnual;
}
public Angajat(int salariuSaptamanal, int nrSaptamani)
{
salariu = salariuSaptamanal * nrSaptamani;
}
}

Aceast clas poate fi instaniat ntr-unul din cele dou moduri prezentate n continuare
Angajat a1 = new Angajat (30000);
Angajat a2 = new Angajat (500, 52);

Un constructor poate utiliza cuvntul cheie base pentru a apela explicit constructorul clasei
de baz:
public class Director : Angajat
{
public Director (int salariuAnual)
: base(salariuAnual)
{
//...
}
}

n acest exemplu, constructorul pentru clasa de baz este apelat nainte de rularea codului
constructorului. Cuvntul cheie base poate fi utilizat cu sau fr parametri. Oricare parametri
ai constructorului pot fi utilizai ca parametri ai constructorului bazei. ntr-o clas derivat,
dac un constructor al clasei de baz nu este apelat explicit prin cuvntul cheie base, atunci
este apelat automat constructorul implicit. Acest lucru nseamn c urmtoarele dou
declaraii sunt identice:
public Director(int initData)
{
//...
}
public Director(int initData)
: base()
{
//...
}

Dac o clas de baz nu ofer un constructor implicit, atunci clasa derivat trebuie s fac un
apel explicit la un constructor din clasa de baz. Un constructor poate invoca un alt
constructor al aceluiai obiect prin utilizarea cuvntului cheie this. La fel ca i base, this
poate fi utilizat cu sau fr parametri, oricare din parametrii constructorului fiind disponibili
acestuia. De exemplu, al doilea constructor din exemplul anterior poate fi rescris astfel:
public Angajat(int salariuSaptamanal, int nrSaptamani)
: this(salariuSaptamanal * nrSaptamani)
{
}

ceea ce face ca urmtorul constructor s fie apelat:


public Angajat(int salariuAnual)
{

65

Medii i Tehnologii de Programare curs

salariu = salariuAnual;
}

Constructorii pot fi marcai ca public, private, protected, internal sau protected internal.
Aceti modificatori de acces definesc modul n care utilizatorii clasei pot instania clasa. Un
constructor poate fi declarat ca static.
Constructorii statici sunt apelai automat imediat nainte de accesarea oricrui cmp static i
sunt utilizai pentru iniializarea claselor statice, a membrilor statici ai claselor non-statice,
sau pentru executarea unor aciuni specifice care trebuie efectuate numai o singur dat.
Constructorii statici au urmtoarele proprieti:

Constructorii statici nu primesc modificatori de acces i nici parametri.

Un constructor static este apelat automat pentru iniializarea clasei nainte de


crearea primei instane sau de accesarea unui membru static.

Un constructor static nu poate fi apelat direct.

Utilizatorul nu poate controla momentul executrii constructorului static de ctre


program.

Dac un constructor static arunc o excepie, motorul de execuie nu l va invoca a


doua oar, iar clasa va rmne neiniializat pe ntreaga durat de via a aplicaiei.

Destructorii sunt utilizai pentru distrugerea instanelor claselor. Iat cteva observaii
privitoare la acetia:

Destructorii nu pot fi definii n cadrul structurilor, ci numai al claselor.

clas poate avea numai un singur destructor.


Destructorii nu pot fi motenii sau suprancrcai.

Destructorii nu pot fi apelai explicit. Ei sunt apelai automat.

Un destructor nu are parametri i nu primete modificatori de acces.

class Automobil
{
~Automobil()
{
// ...
}
}

Destructorul apeleaz implicit metoda Finalize a clasei de baz a obiectului. Aadar,


destructorul prezentat anterior poate fi tradus prin urmtorul cod:
protected override void Finalize()
{
try
{
// ...
}
finally
{
base.Finalize();
}
}

Aceasta nseamn c metoda Finalize este apelat recursiv pentru toate instanele din lanul
de motenire, de la clasa cea mai derivat la cea mai puin derivat.
Programatorul nu poate controla momentul n care este apelat destructorul, deoarece acesta
este determinat de ctre garbage collector. Garbage collector caut acele obiecte care nu mai
sunt utilizate de ctre aplicaie i dac consider c un obiect poate fi distrus, atunci apeleaz destructorul acestuia (dac exist vreunul) i elibereaz memoria ocupat de acesta. Este
posibil forarea acestei operaii prin apelarea metodei Collect, ns de cele mai multe ori

66

Elemente de baz n programarea .NET cu C#

acest lucru ar trebui evitat deoarece poate afecta performana aplicaiilor. Destructorii sunt
de asemenea apelai la prsirea programului.

4.9.3. Clase statice


Putei defini o clas static dac dorii s garantai faptul c aceasta nu poate fi instaniat,
nu motenete alt clas, nu poate fi motenit i poate conine numai membri statici.
Deoarece nu putei instania o clas static prin operatorul new, trebuie s accesai membrii
clasei statice prin numele clasei.
O clas static poate fi utilizat ca un container pentru metode care opereaz numai cu
parametrii de intrare, cum ar fi clasa static Math, care conine metode care efectueaz
operaii matematice, fr necesitatea de stocare sau extragere a datelor specifice unei
instane anume a clasei, precum se poate observa n exemplul urmtor:
double dub = -3.14;
Console.WriteLine(Math.Abs(dub));
Console.WriteLine(Math.Floor(dub));
Console.WriteLine(Math.Round(Math.Abs(dub)));

Principalele caracteristici ale unei clase statice sunt:

Conine numai membri statici

Nu poate fi instaniat

Este sigilat (nu poate fi motenit)


Nu poate conine constructori implicii.

Nu poate fi folosit n declaraia unei variabile locale, statice sau a unei instane, ca
argument al unui tip generic sau ca tip de element ntr-un vector.

Crearea unei clase statice este similar cu crearea unei clase care deriv din System.Object,
conine doar membri statici, fiind att sigilat ct i abstract. Avantajul utilizrii unei clase
statice este c compilatorul poate verifica faptul c nu au fost adugai accidental membri de
instan (non-statici). Compilatorul garanteaz faptul c nu pot fi create instane ale clasei.
Clasele statice sunt sigilate i, n consecin, nu pot fi motenite. Ele nu pot moteni nicio
clas, cu excepia clasei System.Object. O clas static nu poate conine un constructor
implicit, dar poate conine un constructor static. O clas non-static ar trebui s defineasc
un constructor static dac clasa conine membri statici care necesit n mod deosebit o
iniializare.
n continuare este prezentat un exemplu de clas static ce conine dou metode care
convertesc temperatura din grade Celsius n grade Fahrenheit i invers:
public static class ConvertorTemperatura
{
public static double Celsius2Fahrenheit(string tempC)
{
double celsius = Double.Parse(tempC);
// Conversie de la string la double
double fahrenheit = (celsius * 9 / 5) + 32;
return fahrenheit;
}
public static double Fahrenheit2Celsius(string tempF)
{
double fahrenheit = Double.Parse(tempF);
// Conversie de la string la double
double celsius = (fahrenheit - 32) * 5 / 9;
return celsius;
}
}
class Program
{

67

Medii i Tehnologii de Programare curs

static void Main()


{
Console.WriteLine("Selectati conversia");
Console.WriteLine("1. Din grade Celsius in Fahrenheit");
Console.WriteLine("2. Din grade Fahrenheit in Celsius");
Console.Write(":");
string sel = Console.ReadLine();
double F, C = 0;
switch (sel)
{
case "1":
Console.Write("Introduceti temperatura in grade Celsius: ");
F = ConvertorTemperatura.Celsius2Fahrenheit(Console.ReadLine());
Console.WriteLine("Temperatura in grade Fahrenheit: {0:F2}", F);
break;
case "2":
Console.Write("Introduceti temperatura in grade Fahrenheit: ");
C = ConvertorTemperatura.Fahrenheit2Celsius(Console.ReadLine());
Console.WriteLine("Temperatura in grade Celsius: {0:F2}", C);
break;
default:
Console.WriteLine("Selectati o conversie!");
break;
}
Console.ReadKey();
}
}

4.9.4. Clase abstracte i clase sigilate


O clas poate fi declarat abstract. O clas abstract conine metode abstracte care definesc
o semntur, ns nu sunt implementate. Clasele abstracte nu pot fi instaniate, ci pot fi
utilizate numai prin intermediul claselor derivate care implementeaz metodele abstracte.
Prin contrast, o clas sigilat nu permite altor clase s o moteneasc.
Metodele abstracte nu au nicio implementare, astfel c definiia metodei este urmat de
caracterul ;, nu de un bloc normal { }. Clasele derivate din clasele abstracte trebuie s
implementeze toate metodele abstracte.
O clas sigilat nu poate fi clas de baz i din acest motiv nu poate fi clas abstract.

4.9.5. Clase generice


Genericele introduc n .NET Framework conceptul de parametri tip, care fac posibil
definirea claselor i a metodelor care opereaz cu parametri de tip generic, acetia fiind
nlocuii la instanierea claselor i apelul metodelor cu argumente de tip bine precizat. De
exemplu, prin utilizarea parametrului de tip generic T putei scrie o singur clas pe care un
alt cod client o poate utiliza fr s fie nevoie ca motorul de execuie s efectueze conversii
ale argumentelor.
// Clasa generica
public class GenericList<T>
{
void Add(T input) { }
}
class TestGenericList
{
private class Element { }
static void Main()

68

Elemente de baz n programarea .NET cu C#

{
// Declara o lista de int
GenericList<int> list1 = new GenericList<int>();
// Declara o lista de string
GenericList<string> list2 = new GenericList<string>();
// Declara o lista de Element
GenericList<ExampleClass> list3 = new GenericList<Element>();
}
}

Biblioteca de clase din .NET Framework conine cteva clase colecie generice n spaiul de
nume System.Collections.Generic. Putei s v creai propriile interfee, clase, metode,
evenimente i delegai generici. Se recomand utilizarea claselor generice pentru
maximizarea reutilizrii codului, siguranei tipului i performanei.
Dac o clas generic implementeaz o interfa, atunci toate instanele clasei vor putea fi
convertite prin operatorul cast la acea interfa.

4.10. Interfee
O interfa definete un API care nu are nicio implementare. Clasele pot alege s ofere o
implementare a unei interfee. Putei scrie cod care s nu fie limitat la funcionarea numai cu
un anumit tip, ci cu orice tip care implementeaz interfaa.
O interfa declar metode, proprieti i evenimente, ns nu i coninutul acestora.
Proprietile indic doar faptul c accesorii get i set trebuie s fie prezeni. O interfa nu
este dect o list de membri pe care un tip va trebui s i pun la dispoziie dac va
implementa interfaa.
public interface IMyTest
{
string this[int i] { get; set; }
string Nume { get; set; }
int Id { get; }
void Show(string arg);
}

Pentru membrii interfeelor nu pot fi specificai modificatori de acces, deoarece accesibilitatea este controlat la nivelul interfeei (la fel ca i clasele, interfeele sunt publice sau
interne, ns n cazul n care sunt ncuibate pot avea orice modificator de acces). Interfeele
nu pot conine cmpuri sau tipuri ncuibate, deoarece ele definesc interfaa programabil
(API), nu implementarea. De asemenea, interfeele nu pot s declare constructori o
interfa indic acele servicii pe care un obiect ar trebui s le ofere dup ce a fost construit.
O clas declar interfeele pe care le implementeaz dup numele clasei, urmat de caracterul
: i lista de interfee (desprite prin virgul unele de altele). Clasa va trebui s implementeze toi membrii declarai n interfa, n caz contrar compilatorul va semnala eroare.
public class MyTest : IMyTest
{
public string this[int i]
{
get { return i.ToString(); }
}
public Nume { get; set; }
// ...
}

69

Medii i Tehnologii de Programare curs

Atunci cnd implementm n C# o interfa, de obicei definim fiecare metod a interfeei ca


membru public al clasei. Se poate ntmpla uneori ca un membru al clasei s aib acelai
nume cu unul al interfeei, sau dou interfee implementate s ofere cte un membru cu
acelai nume (ns cu semnificaie diferit), caz n care se poate folosi implementarea
explicit a unui membru al interfeei. ntr-o implementare explicit se prefixeaz numele
membrului cu numele interfeei, ns nu i putei specifica accesibilitatea.
void IMyTest.Show(string arg)
{
// ...
}

Atunci cnd un tip folosete implementarea explicit a membrilor unei interfee, acei
membri nu pot fi utilizai printr-o referin a tipului nsui. Acetia devin vizibili la referirea
unui obiect printr-o variabil de tipul interfeei.
MyTest c = new MyTest();
c.Show();
// Eroare
IMyTest i = c;
i.Show();
// OK

Cnd o clas implementeaz o interfa, aceasta devine implicit convertibil la tipul


interfeei. Astfel, de exemplu, putei transmite n locul unui argument de tip IMyTest orice
variabil de tip MyTest.

4.11. Motenire
Clasele C# suport mecanismul motenirii, specific programrii orientate pe obiecte. Motenirea este realizat prin derivarea unei clase dintr-o clas de baz de la care motenete
datele i comportamentul. O clas de baz este specificat prin adugarea la numele clasei
derivate a caracterului : urmat de numele clasei de baz.
Atunci cnd o clas declar o clas de baz, ea motenete toi membrii clasei de baz, cu
excepia constructorilor, la care poate s adauge noi membri. Spre deosebire de C++, o clas
C# poate moteni direct numai o singur clas de baz. Totui, deoarece o clas de baz
poate moteni la rndul ei o alt clas, o clas poate moteni indirect mai multe clase de
baz. De asemenea, o clas poate implementa direct mai multe interfee.
Tipurile valoare nu suport motenire. Unul dintre motive este c tipurile valoare nu sunt
folosite n mod normal prin referin, fapt care elimin unul dintre principalele beneficii ale
motenirii: polimorfismul n timpul rulrii. Motenirea nu este neaprat incompatibil cu
comportamentul tipurilor valoare, ns adesea are probleme. De exemplu, atribuirea unei
valori de un tip derivat unei variabile de tipul de baz duce la pierderea tuturor cmpurilor
pe care tipul derivat le-a adugat, problem cunoscut sub denumirea de slicing. C#
depete aceasta prin restricionarea motenirii la tipurile referin. Cnd atribuii o
variabil de un tip derivat uneia de tipul de baz, copiai de fapt o referin, nu obiectul
nsui, astfel c obiectul rmne intact. Slicing devine o problem dac clasa de baz ofer o
metod care cloneaz obiectul i nu ofer pentru clasele derivate o modalitate de extindere a
acestuia.
Clasele specific o clas de baz prin specificarea dup numele clasei a caracterului : urmat
de numele clasei de baz.
public class Baza
{
}
public class Deriv : Baza
{
}
public class Deriv1 : Baza, IDisposable

70

Elemente de baz n programarea .NET cu C#

{
public void Dispose() { }
}

Precum se poate vedea n exemplul de mai sus, dac clasa implementeaz interfee, acestea
sunt listate de asemenea dup caracterul :. Dac dorii ca o clas s moteneasc alt clas
i s implementai i interfee, atunci clasa de baz trebuie s apar prima n list.
Se poate ca o clas s moteneasc o clas derivat din alt clas. Clasa Deriv2 din exemplul
de mai jos deriv din Deriv, care la rndul ei este derivat din Baza.
public class Baza
{
}
public class Deriv : Baza
{
}
public class Deriv2 : Deriv
{
}

Aceasta nseamn c, din punct de vedere tehnic, Deriv2 are mai multe clase de baz: este
derivat att din Deriv (direct) ct i din Baza (indirect, prin intermediul Deriv). Aceasta nu
poate fi numit motenire multipl, deoarece exist numai o singur linie de motenire.
O instan a clasei derivate poate face tot ceea ce face o instan a clasei de baz. Orice
instan a clasei Deriv2 este o Deriv i de asemenea o Baza. C# recunoate aceast relaie.

4.11.1. Motenirea Interfeelor


Interfeele suport motenirea, ns aceasta nu este la fel ca motenirea claselor. Sintaxa este
similar, ns o interfa poate specifica mai multe interfee de baz, deoarece pentru
interfee C# suport motenire multipl. Motivul pentru care C# suport aceasta este c
majoritatea complicaiilor care pot s apar n cazul motenirii multiple nu se aplic i
tipurilor abstracte.
interface IBase1
{
void Base1Method();
}
interface IBase2
{
void Base2Method();
}
interface IBoth : IBase1, IBase2
{
void Method3();
}

La fel ca n cazul motenirii claselor, interfeele motenesc toi membrii interfeelor de baz.
Exist conversii implicite de la interfaa derivat la interfeele de baz. De exemplu, o
referin de tip IBoth poate fi atribuit unei variabile de tip IBase1 sau IBase2.
O caracteristic mai subtil legat de motenirea interfeelor este aceea c orice clas care
implementeaz o interfa derivat trebuie s implementeze interfaa de baz a acelei
interfee. Precum putei observa n exemplul de mai jos, clasa trebuie doar s indice faptul c
implementeaz interfaa derivat, ns compilatorul va aciona ca i cum IBase1 i IBase2 ar fi
n lista de interfee implementate de clas.
public class Impl : IBoth
{
public void Base1Method()
{
}

71

Medii i Tehnologii de Programare curs

public void Base2Method()


{
}
public void Method3()
{
}
}

Orice referin de tip Impl este implicit convertibil la IBoth, care n schimb este implicit
convertibil la IBase1 i IBase2. n general, dac o referin a unei clase C este implicit
convertibil la tipul T1 i o referin de tip T1 este implicit convertibil la tipul T2, aceasta
nu nseamn c C este implicit convertibil la T1. n C# conversiile implicite nu sunt
tranzitive.

4.11.2. Accesibilitatea i motenirea


Elementele publice sunt disponibile tuturor, membrii privai sunt accesibili numai din
interiorul tipului n care sunt declarai, iar membrii interni sunt disponibili oricrui cod
definit n acelai ansamblu (proiect). n cazul motenirii, avem acces la alte dou opiuni de
accesibilitate.
Membrii protejai sunt disponibili n interiorul tipului care i definete i de asemenea n
interiorul oricrui tip derivat, ns nu sunt vizibili din afar. Pentru codul care folosete o
instan a acestui tip, membrii protejai sunt la fel de inaccesibili precum cei privai.
Mai exist un nivel de protecie pentru membrii unui tip: protected internal (sau internal
protected ordinea nu conteaz). Membrii vor fi accesibili tuturor tipurilor derivate i
codului care partajeaz un ansamblu. Putei specifica ca protejat sau protejat intern orice
membru a unui tip, nu numai metode. Chiar i tipurile ncuibate pot folosi aceti specificatori
de acces.
Dei membrii protejai i cei protejai intern nu sunt disponibili prin intermediul unei
instane, acetia fac totui parte din interfaa programabil public al tipului, n sensul c
oricine care are acces la clasele dumneavoastr va putea utiliza aceti membri. De exemplu,
dac scriei o clas public care suport motenire, atunci oricine poate s o moteneasc i
s primeasc acces la membrii ei protejai.
Cnd motenii o clas, nu putei face clasa derivat mai accesibil dect clasa ei de baz. De
exemplu, dac motenii o clas intern, nu putei declara clasa derivat ca public. Dac
motenii o clas ncuibat protejat, clasa derivat ar putea fi protejat sau privat, nu
public, nici intern i nici protejat intern.
Aceast restricie nu se aplic interfeelor pe care le implementai. O clas public este liber
s implementeze interfee interne sau private. Totui, se aplic bazelor unei interfee: o
interfa public nu poate moteni o interfa intern.
Atunci cnd definii metode, exist alt cuvnt cheie pe care putei s l adugai pentru
beneficiul tipurilor derivate: virtual.

4.12. Polimorfism
Alturi de ncapsulare i motenire, polimorfismul este unul dintre conceptele de baz ale
programrii orientate pe obiecte. Polimorfismul prezint dou aspecte distincte:

72

La rulare, obiectele de tipul unei clase derivate pot fi tratate ca obiecte de tipul clasei
de baz n locuri precum parametri ai metodelor, colecii sau vectori. Atunci cnd se

Elemente de baz n programarea .NET cu C#

ntmpl aa ceva, tipul declarat al obiectului nu este identic cu tipul pe care l


primete la rulare.
Clasele de baz pot defini i implementa metode virtuale, iar clasele derivate le pot
suprascrie, ceea ce nseamn c ofer propria lor definiie i implementare. La
rulare, atunci cnd codul client apeleaz metoda, CLR verific tipul pe care obiectul l
are la rulare i invoc varianta suprascris a metodei virtuale. Astfel, n codul surs
putei apela o metod a clasei de baz i s se execute o variant a metodei din clasa
derivat.

Metodele virtuale v permit s operai cu grupuri de obiecte asociate ntr-un mod uniform.
S presupunem, de exemplu, c avei o aplicaie grafic care permite utilizatorilor s creeze
diferite tipuri de forme, fiecare dintre ele avnd asociat propria clas, toate fiind derivate
dintr-o singur clas de baz.
Un efect al polimorfismului este acela c o metod dintr-o clas derivat poate avea acelai
nume cu al unei metode din clasa de baz. O metod virtual este una pe care un tip derivat
poate s o nlocuiasc.
n C# toate tipurile sunt polimorfice deoarece motenesc clasa System.Object (inclusiv cele
definite de utilizatori). Cteva dintre metodele definite de clasa System.Object sunt virtuale:
ToString, Equals, GetHashCode i Finalize, fiind proiectate pentru a fi nlocuite. Codul acestor
funcii va diferi de la un tip la altul.
Pentru declararea unei metode virtuale se folosete cuvntul cheie virtual, precum putei
vedea n exemplul de mai jos.
public class Baza
{
public virtual void Afiseaza()
{
Console.WriteLine("Salutari din Baza!");
}
}

O metod virtual este apelat exact n acelai fel n care este apelat orice alt metod:
public static void ApelMetVirt(Baza b)
{
b.Afiseaza();
}

Diferena dintre invocrile metodelor virtuale i a celor non-virtuale este c n cazul apelului
unei metode virtuale se va decide la rulare care metod va fi invocat. Codul din secvena de
mai sus va inspecta obiectul transmis i, dac tipul obiectului ofer o variant proprie de
implementare a metodei Afiseaza, o va apela pe aceasta n locul celei definite n clasa Baza.
Metoda este aleas pe baza tipului pe care obiectul l poate avea la rulare, nu a tipului static
determinat la compilare.
Deoarece la invocarea unei metode virtuale aceasta este selectat n funcie de tipul
obiectului prin care o invocai, metodele statice nu pot fi virtuale.
Tipurile derivate nu sunt obligate s nlocuiasc metodele virtuale. Exemplul de mai jos
ilustreaz dou clase care motenesc o clas de baz. Prima clas derivat las neschimbat
implementarea metodei virtuale Afiseaza. A doua clas o suprascrie. Observai utilizarea
cuvntului cheie override C# necesit utilizarea acestuia pentru a exprima explicit intenia
de suprascriere a unei metode virtuale.
public class Deriv1 : Baza
{
}
public class Deriv2 : Baza
{
public override void Afiseaza()
{
Console.WriteLine("Metoda suprascrisa");

73

Medii i Tehnologii de Programare curs

}
}

Avnd definite aceste tipuri, putem utiliza acum metoda ApelMetVirt. Exemplul de mai jos o
apeleaz de trei ori, transmindu-i de fiecare dat un tip diferit de obiect.
ApelMetVirt(new Baza());
ApelMetVirt(new Deriv1());
ApelMetVirt(new Deriv2());

La rulare va fi afiat:
Salutari din Baza
Salutari din Baza
Metoda suprascrisa

Acest mecanism este foarte asemntor cu cel al implementrii interfeelor metodele


virtuale ofer o alt modalitate de scriere a codului polimorfic. Diferena major este c o
clas de baz poate furniza o implementare implicit pentru fiecare metod virtual, ceea ce
interfeele nu pot face.

4.12.1. Membri virtuali


Atunci cnd o clas derivat motenete o clas de baz, ea dobndete toate metodele,
cmpurile, proprietile i evenimentele clasei de baz. Proiectantul clasei derivate poate
alege s:
a) suprascrie membrii virtuali din clasa de baz;
b) moteneasc cea mai apropiat metod din clasa de baz fr s o suprascrie;
c) defineasc noi implementri non-virtuale ale acelor membri care s ascund implementrile clasei de baz.
O clas derivat poate suprascrie un membru al clasei de baz numai dac acesta este
declarat ca virtual sau abstract. Membrul derivat trebuie s foloseasc cuvntul cheie
override pentru a indica explicit faptul c metoda va participa n invocarea virtual.
public class Baza
{
public virtual void Metoda() { }
public virtual int Propr
{
get { return 0; }
}
}
public class Deriv : Baza
{
public override void Metoda() { }
public override int Propr
{
get { return 0; }
}
}

Cmpurile nu pot fi virtuale; numai metodele, proprietile, evenimentele i indexatorii pot


fi. Cnd o clas derivat suprascrie un membru virtual, acel membru este apelat chiar i cnd
o instan a acelei clase este accesat ca instan a clasei de baz.
Deriv D = new Deriv ();
D.Metoda(); // Apeleaza metoda suprascrisa
Baza B = (Baza)D;
B.Metoda(); // Apeleaza tot metoda suprascrisa

74

Elemente de baz n programarea .NET cu C#

4.12.2. Ascunderea membrilor clasei de baz


Dac dorii ca membrul din clasa derivat s aib acelai nume cu cel al unuia din clasa de
baz, ns nu dorii ca acesta s participe la invocarea virtual, putei folosi cuvntul cheie
new. Acesta este plasat nainte de tipul returnat al membrului clasei care este nlocuit.
public class Baza
{
public void Metoda() { Camp++; }
public int Camp;
public int Propr
{
get { return 0; }
}
}
public class Deriv : Baza
{
public new void Metoda() { Camp++; }
public new int Camp;
public new int Propr
{
get { return 0; }
}
}

Membrii ascuni ai clasei de baz pot fi accesai n continuare n cod prin casting al instanei
clasei derivate la o instan a clasei de baz.
Deriv B = new Deriv();
B.Metoda(); // Apeleaza metoda suprascrisa
Baza A = (Baza)B;
A.Metoda(); // Apeleaza metoda veche

4.12.3. Prevenirea suprascrierii membrilor virtuali de ctre clasele derivate


Membrii virtuali rmn virtuali, indiferent cte clase au mai fost declarate ntre membrul
virtual i clasa de origine care l-a declarat. Dac clasa A declar un membru virtual, clasa B
motenete clasa A, iar clasa C motenete clasa B, clasa C motenete membrul virtual i
poate s l suprascrie, indiferent dac clasa B l-a suprascris sau nu.
public class A
{
public virtual void Metoda() { }
}
public class B : A
{
public override void Metoda() { }
}

O clas derivat poate opri motenirea caracterului virtual prin declararea unei suprascrieri
sigilate. Acest lucru necesit folosirea cuvntului cheie sealed nainte de cuvntul override n
declaraia membrului clasei.
public class C : B
{
public sealed override void Metoda() { }
}

n exemplul anterior, metoda Metoda nu mai este virtual pentru nicio clas derivat din clasa
C, ns rmne virtual pentru instanele clasei C. Metodele sigilate pot fi nlocuite de clasele
derivate prin utilizarea cuvntului cheie new.

75

Medii i Tehnologii de Programare curs

public class D : C
{
public new void Metoda() { }
}

n acesta caz, dac Metoda este apelat printr-o instan a clasei D, va fi apelat noua metod
Metoda.

4.12.4. Accesarea membrilor virtuali ai clasei de baz din clasa derivat


O clas derivat care a nlocuit sau suprascris o metod sau proprietate poate nc accesa
metoda sau proprietatea original din clasa de baz prin utilizarea cuvntului cheie base.
public class Baza
{
public virtual void Metoda() {/*...*/ }
}
public class Deriv : Baza
{
public override void Metoda ()
{
//...
base.Metoda ();
// Apelarea Metoda din clasa de baza
}
}

Se recomand folosirea de ctre membrii virtuali a cuvntului cheie base pentru apelarea n
cadrul propriei implementri a implementrii acelui membru din clasa de baz.

4.13. Delegai
Un delegat este un tip care definete semntura unei metode. Cnd instaniai un delegat,
putei s i asociai orice metod cu o semntur compatibil. Putei invoca metoda prin
instana delegatului.
Delegaii sunt utilizai pentru transmiterea metodelor ca argumente pentru alte metode.
Procedurile eveniment (event handlers) nu sunt altceva dect metode care sunt invocate
prin delegai. Putei crea o metod, iar o clas, cum ar fi un control Windows, poate apela
acea metod atunci cnd apare un anumit eveniment. n exemplul urmtor este ilustrat
declaraia unui delegat:
public delegate int EfectuareOperatii(int x, int y);

Delegatului i poate fi atribuit orice metod din orice clas sau structur accesibil, care
corespunde semnturii delegatului (tip returnat i parametri). Metoda poate s fie static
sau metod a unei instane. Acest lucru face posibil modificarea prin program a apelurilor
metodelor i, de asemenea, insereaz cod nou n clasele existente. Att timp ct cunoatei
semntura delegatului, i putei atribui propria voastr metod.
n contextul suprancrcrii metodelor, semntura unei metode nu include valoarea
returnat, ns n contextul delegailor aceasta include i valoarea returnat. n
concluzie, o metod trebuie s aib aceeai valoare returnat cu a delegatului.

Aceast abilitate de referire la o metod ca parametru face ca delegaii s fie ideali pentru
definirea metodelor cu apel invers (callback). De exemplu, pentru un algoritm de sortare ar
putea fi pasat ca argument o referin la o metod care compar dou obiecte. Deoarece

76

Elemente de baz n programarea .NET cu C#

codul de comparare este ntr-o procedur separat, algoritmul de sortare poate fi scris ntrun mod mai general.
Delegaii au urmtoarele proprieti:

Delegaii sunt asemntori pointerilor la funcii din C++, ns sunt tipuri sigure.
Delegaii permit metodelor s fie transmise ca parametri.

Delegaii pot fi folosii pentru definirea metodelor cu apel invers (callback).


Delegaii pot fi nlnuii mpreun; de exemplu, pot fi apelate mai multe metode
pentru un singur eveniment.

Metodele nu trebuie s corespund exact semnturii delegatului. Atunci cnd atribuii unui delegat o metod, covariana i contravariana ofer flexibilitate pentru
potrivirea dintre semntura unei metode cu a unui delegat.

C# 2.0 a introdus conceptul de metode anonime, care permit blocurilor de cod s fie
transmise ca parametri n locul unei metode definite separat. C# 3.0 a introdus
expresii lambda ca un mod mai concis de scriere a blocurilor de cod inline. Att
metodele anonime ct i expresiile lambda (n anumite contexte) sunt compilate la
tipuri delegat. mpreun, aceste caracteristici sunt cunoscute ca funcii anonime.

Delegatul trebuie s fie instaniat cu o metod sau expresie lambda care are tip returnat i
parametri de intrare compatibili. Pentru utilizare cu metode anonime, delegatul i codul care
trebuie asociat cu acesta sunt declarate mpreun.
// Declararea delegatului defineste semnatura ceruta
delegate double MathAction(double num);
class Program
{
// Metoda care are semnatura identica cu a delegatului
static double Dublu(double input)
{
return input * 2;
}
static void Main()
{
// Instantierea delegatului cu o metoda
MathAction ma = Dublu;
// Invocarea delegatului ma:
double multByTwo = ma(4.5);
Console.WriteLine("Inmultire cu 2: {0}", multByTwo);
// Instantierea delegatului cu o metoda anonima
MathAction ma2 = delegate(double input)
{
return input * input;
};
double patrat = ma2(5);
Console.WriteLine("Patrat: {0}", patrat);
// Instantierea delegatului cu o expresie lambda
MathAction ma3 = s => s * s * s;
double cub = ma3(6.254);
Console.WriteLine("Cub: {0}", cub);
}
}

77

Medii i Tehnologii de Programare curs

4.13.1. Covarian i contravarian


Covariana permite unei metode s aib tipul returnat mai derivat dect cel definit de
delegat. Exemplul de mai jos demonstreaz modul n care delegaii pot fi utilizai cu metode
care au tipul returnat derivat din tipul returnat din semntura delegatului. Tipul returnat de
DogsHandler este de tip Dog, care deriv din Mammals, tipul definit de delegat.
class Mammals{}
class Dogs : Mammals{}
class Program
{
// Definirea delegatului
public delegate Mammals HandlerMethod();
public static Mammals MammalsHandler()
{
return null;
}
public static Dogs DogsHandler()
{
return null;
}
static void Test()
{
HandlerMethod handlerMammals = MammalsHandler;
HandlerMethod handlerDogs = DogsHandler; // Covarianta permite aceasta atribuire
}
}

Contravariana permite unei metode s aib tipuri de parametri mai puin derivate dect
cele din tipul delegat. Acest exemplu demonstreaz modul n care delegaii pot fi utilizai cu
metode care au parametri de tipul de baz a tipului din semntura delegatului. Prin
contravarian putei utiliza un singur event handler n locul handlerelor separate. Putei
crea, de exemplu, un event handler care accept un parametru de intrare EventArgs, i s l
folosii cu un eveniment Button.MouseClick care trimite un parametru de tip MouseEventArgs i,
de asemenea, cu un eveniment TextBox.KeyDown care trimite un parametru KeyEventArgs.
// Event hander: primeste un parametru de tip EventArgs
private void MultiHandler(object sender, System.EventArgs e)
{
label1.Text = System.DateTime.Now.ToString();
}
public Form1()
{
InitializeComponent();
// Evenimentul asteapta un parametru KeyEventArgs ...
this.button1.KeyDown += this.MultiHandler;
// Evenimentul asteapta un parametru MouseEventArgs ...
this.button1.MouseClick += this.MultiHandler;
}

78

Elemente de baz n programarea .NET cu C#

4.14. Spaii de nume


Spaiile de nume gzduiesc tipurile de date (clase, interfee, structuri etc.), ajutnd la
organizarea i structurarea acestora. Numai biblioteca de clase din .NET Framework conine
peste 10.000 clase, astfel c, n lipsa spaiilor de nume, ar fi fost dificil garantarea unicitii
numelor de clase i ar fi fost o adevrat provocare descoperirea numelui clasei de care ai fi
avut nevoie la un moment dat.
Cel mai important spaiu de nume System, care grupeaz clasele asociate tipurilor de date
baz (Int32, String, Array etc.) i clasa Object, din care deriv toate celelalte clase .NET.
Exceptnd spaiul de nume System, toate celelalte spaii de nume din .NET Framework sunt
ncuibate iar numele lor includ caractere punct (.) pentru separarea diferitor poriuni.
De obicei, spaiul de nume d un indiciu despre utilitatea unui tip. De exemplu, toate tipurile
care au legtur cu manipularea fiierelor pot fi gsite n spaiul de nume System.IO
(FileStream, StreamReader, StreamWriter etc.), pe cnd cele legate de reelistic se gsesc n
spaiul de nume System.Net. Spaiul de nume System.Windows.Forms conine clase utilizate la
interfeele utilizator ale aplicaiilor Windows (TextBox, ComboBox, ListBox etc.). Spaiile de nume
formeaz o ierarhie, astfel c spaiul de nume System nu conine numai tipuri, ci conine, de
asemenea, alte spaii de nume.
Spaiile de nume ofer o modalitate de asigurare a unicitii numelor tipurilor. Spaiul de
nume n care este definit un tip este parte a numelui ntreg a acelui tip. Acest lucru permite
bibliotecilor s foloseasc nume simple i scurte. Ar fi suprtor s trebuiasc s alegei un
nume diferit pentru clasele voastre numai pentru c acesta a fost deja ales pentru alt clas,
ns, datorit faptului c numele complet al unei clase conine i denumirea spaiului de
nume, putei defini clase care au acelai nume, cu condiia ca ele s fac parte din spaii de
nume diferite.

4.14.1. Referine la ansambluri .NET


nainte de a crea sau de a utiliza un tip din .NET Framework trebuie s adugai o referin la
ansamblul care l conine. Atunci cnd creai un proiect nou, Visual Studio adaug automat
referine la cele mai importante ansambluri .NET, cum ar fi System.Data.dll (conine clase
pentru lucrul cu baze de date) i System.Xml.dll (conine clase pentru lucrul cu XML). n funcie de tipul proiectului, pot fi referite i alte DLL-uri, de exemplu, System.Windows.Forms.dll
i System.Drawing.dll n cazul proiectelor de tip Windows Forms.
Pentru utilizarea unei clase definite ntr-un ansamblu, care nu este referit de ctre proiectul
curent, trebuie s o adugai manual. Putei folosi n acest scop comanda Add Reference
din meniul Project. Dialogul ce se va deschide v permite selectarea unuia sa a mai multor
ansambluri .NET sau a altor referine (Figura 4.13).

79

Medii i Tehnologii de Programare curs

Figura 4.13. Dialogul de adugare a unei noi referine

Putei vizualiza lista tuturor referinelor din proiectul curent prin deschiderea dosarului
References din Solution Explorer (Figura 4.14).

Figura 4.14. Dosarul References din fereastra Solution Explorer

4.14.2. Directiva using


Numele complet al unei clase .NET include spaiul de nume care o conine, similar cu numele
complet al unui fiier coninut de un director. Este lesne de neles faptul c utilizarea
numelor complete ale claselor face codul scris s fie stufos i greu de urmrit:
System.Drawing.Bitmap bmp;
System.Windows.Forms.Control ctrl;
System.ComponentModel.Component comp;

// Un bitmap
// Un control
// O componenta

Putei simplifica codul scris prin adugarea uneia sau a mai multor directive using la
nceputul fiierului surs curent; dac un spaiu de nume apare ca argument al directivei
using, putei omite ntregul spaiu de nume la declararea unei variabile, fcnd astfel codul
scris mai compact i mai lizibil:

80

Elemente de baz n programarea .NET cu C#

using System.Drawing;
using System.Windows.Forms;
using System.ComponentModel;
//...
Bitmap bmp;
Control ctrl;
Component comp;

// identic cu System.Drawing.Bitmap
// identic cu System.Windows.Forms.Control
// identic cu System.ComponentModel.Component

Putei scrie mai puin i n cazul n care nu avei o directiv using care s corespund exact cu
spaiul de nume a elementului pe care vrei s l referii. De exemplu:
using System;
//...
Drawing.Bitmap bmp;

// identic cu System.Drawing.Bitmap

Directivele using trebuie s includ ntotdeauna spaiul de nume complet pe care dorii s l
importai. Nu v putei folosi de o directiv using anterioar pentru a scurta o alta:
// Codul nu va fi compilat!
using System;
using Drawing;
// Se doreste inlocuirea using System.Drawing

O alt restricie se refer la utilizarea a dou directive using care se refer la spaii de nume
care conin clase cu nume identic. Totui, i n acest caz pot fi utilizate directive using prin
specificarea unui alias pentru unul dintre spaiile de nume care a produs conflict:
// Codul urmator nu va putea fi compilat!
using Animals.Mammals;
using Computers.Accessories;
//...
Mouse m;

// Codul urmator este corect


using Animals.Mammals;
using Acc = Computers.Accessories;
//...
Mouse m;
// identic cu Animals.Mammals.Mouse
Acc.Mouse m2;
// identic cu Computers.Accessories.Mouse

Majoritatea proiectelor C# se bazeaz pe cteva spaii de nume din .NET Framework, cum ar
fi spaiul de nume System, care conine toate tipurile elementare de date, sau
System.Collections.Generic, care conine clase i interfee care definesc colecii generice.
Importarea repetat a acestor spaii de nume n fiecare fiier surs din cadrul unui proiect
este un proces suprtor. Din fericire nu este nevoie s facei aa, deoarece n aplicaiile C#
putei defini un numr de referine globale la nivel de proiect.

4.14.3. Blocuri de spaii de nume


Toate clasele dintr-un proiect C# aparin unui spaiu de nume implicit definit n cmpul
Default Namespace de pe pagina Application din fereastra de proprieti a proiectului
(Figura 4.15).

Figura 4.15. Pagina Application din fereastra de proprieti a proiectului

81

Medii i Tehnologii de Programare curs

Iniial denumirea spaiului de nume implicit este aceeai cu numele proiectului, ns, dac
dorii, putei s o modificai. Nu este indicat s scriei niciuna din clase n spaiul de nume
System, sau ntr-altul subordonat acestuia, din cauz c acest spaiu de nume este rezervat
pentru clasele din .NET Framework.
Putei s creai propriile voastre spaii de nume oriunde n cadrul fiierelor surs din proiect
cu ajutorul cuvntului cheie namespace. Spre exemplu, putei defini spaiul de nume Resurse ca
i container pentru clasa Persoana:
namespace Resurse
{
public class Persoana
{
//...
}
}

Dac o secven de cod refer un tip declarat n alt spaiu de nume, trebuie s includ
numele complet al spaiului de nume ce conine elementul referit, precum n exemplul de
mai jos:
// Utilizam clasa Persoana din cadrul altui spaiu de nume
Resurse.Persoana p = new Resurse.Persoana();

Desigur, putei utiliza cuvntul cheie using pentru simplificarea referirii claselor definite n
cadrul proiectului, ns nu uitai c toate fiierele surs dintr-un proiect C# sunt cuprinse n
spaiul de nume implicit, iar acest spaiu de nume trebuie s apar n declaraia using:
// Presupunem ca spatiul de nume radacina este Test
using Test.Resurse;
//...
Persoana p = new Persoana();

n cadrul unui spaiu de nume putei declara unul sau mai multe dintre urmtoarele tipuri:
clase, interfee, structuri, enumerri, delegai sau alte spaii de nume. Aceste categorii sunt
considerate ca fiind tipuri. Din aceast cauz nu putei include declaraii de variabile sau
metode direct n interiorul unui spaiu de nume, ci, de exemplu, n interiorul unei clase
inclus ntr-un spaiu de nume. Spre exemplu, urmtoarea secven de cod nu se va compila:
namespace MyNamespace
{
// Eroare la compilare!
void MyMethod()
{
}
}

Este interesant faptul c putei avea n cadrul proiectului mai multe blocuri de spaii de
nume avnd acelai nume, n acelai fiier sau n fiiere diferite. Aceast caracteristic v
permite pstrarea organizrii logice a entitilor din codul surs separat de structura fizic a
fiierelor. Spre exemplu, putei avea un fiier care s conin mai multe spaii de nume, sau
putei avea toate elementele dintr-un spaiu de nume mprtiate n diverse fiiere surs (de
fapt, toate fiierele surs din proiect aparin spaiului de nume implicit definit pe pagina
Application din fereastra de proprieti a proiectului).
Este important de tiut faptul c spaiul de nume este un concept ce ine de limbajul de
programare, ns nici spaiile de nume, nici directivele using nu exist la nivelul
limbajului intermediar (MSIL). Putei dovedi uor acest lucru prin dezasamblarea unui
proiect C# i verificarea faptului c toate instruciunile MSIL refer clase .NET
Framework folosind numele lor complet, chiar dac n cod ai utilizat directive using
pentru a face codul surs mai scurt.

82

Elemente de baz n programarea .NET cu C#

4.14.4. Spaii de nume ncuibate


Aa cum am mai precizat, spaiile de nume pot fi i ncuibate; de fapt, majoritatea claselor
din .NET Framework sunt cuprinse n spaii de nume ncuibate, cum ar fi spaiul de nume
System.Collections (care conine tipuri colecie) i spaiul de nume System.IO (utilizat pentru
toate tipurile ce in de operaiile cu fiiere). Teoretic nu exist o limit de ncuibare a
spaiilor de nume, iar spaiile de nume ncuibate pe trei sau mai multe niveluri sunt ntlnite
frecvent n .NET Framework. Astfel, putei s ntlnii, spre exemplu, spaiul de nume
System.Xml.Schema sau spaiul de nume System.Windows.Forms.ComponentModel.Com2Interop.
n cadrul proiectelor C# putei crea spaii de nume ncuibate prin simpla ncuibare a
blocurilor namespace. Spre exemplu, urmtoarea secven de cod definete clasele
Animale.Mamifere.Caine, Animale.Mamifere.Pisica i Animale.Reptile.Soparla:
namespace Animale
{
namespace Mamifere
{
class Caine
{
}
class Pisica
{
}
}
namespace Reptile
{
class Soparla
{
}
}
}

Domeniul de vizibilitate pentru referirea claselor i a funciilor n alte spaii de nume poate fi
uor extins la spaiile de nume ncuibate. Spre exemplu, codul din clasa Caine poate referi
direct clasa Pisica, ns pentru accesarea clasei Soparla are nevoie s precizeze spaiul de
nume Reptile:
class Caine
{
Pisica mPisica = new Pisica();
Reptile.Soparla mSoparla = new Reptile.Soparla();
}

n general, nu se recomand blocurile de spaii de nume ncuibate, pentru c duc la un cod


care este puternic indentat, reducnd n consecin numrul de caractere vizibile n editorul
de cod. Putei reduce spaiul de indentare a unui bloc de spaiu de nume incluznd n numele
acestuia un caracter punct, ca n exemplul de mai jos:
namespace Animale.Mamifere
{
class Caine
{
}
class Pisisca
{
}
}
namespace Animale.Reptile
{
class Soparla
{
}
}

83

Medii i Tehnologii de Programare curs

4.14.5. Cuvntul cheie global


O potenial problem privitoare la spaiile de nume survine atunci cnd acelai nume apare
la diferite niveluri ale ierarhiei. De exemplu, s presupunem c avei un spaiu de nume
System pe nivelul imediat urmtor spaiului de nume rdcin:
namespace System
{
public class Test
{
static void Test()
{
System.Console.WriteLine("Test");
}
}
}

// Eroare la compilare!

Codul de mai sus duce la apariia unei erori de compilare din cauz c orice referire din
interiorul clasei Test la spaiul de nume System este de fapt o referire la spaiul de nume
definit de utilizator, iar nu spaiul de nume din .NET Framework (dup cum am mai amintit,
este de evitat utilizarea numelui System pentru spaiile de nume create de utilizatori).
Pentru gestionarea acestui gen de probleme C# introduce cuvntul cheie global, care foreaz referirea unui spaiu de nume pornind de la spaiul de nume rdcin, cum se poate
vedea i n exemplul de mai jos:
// Aceast secven de cod refer sigur clasa System.Console din .NET Framework
global::System.Console.WriteLine("Test");

Abilitatea de accesare a unui membru din spaiul de nume global este util cnd membrul ar
putea fi ascuns de o alt entitate cu acelai nume. De exemplu, n codul de mai jos, Console se
refer la TestApp.Console n loc de tipul Console din spaiul de nume System.
using System;
class TestApp
{
// Definirea unei noi clase 'System' pentru a provoca probleme
public class System { }
// Definirea unei constante 'Console' pentru a provoca probleme
const int Console = 7;
const int number = 66;
static void Main()
{
// Eroare! Accesarea constantei TestApp.Console, care nu are o metoda WriteLine
Console.WriteLine(number);
}
}

Utilizarea System.Console va provoca apariia unei erori, deoarece spaiul de nume System este
ascuns de clasa TestApp.System. Totui, putei depi aceast eroare prin utilizarea
global::System.Console, ca n codul de mai jos:
global::System.Console.WriteLine(number);

Atunci cnd identificatorul din stnga este global, cutarea dup identificatorul din dreapta
ncepe de la spaiul de nume global.
class TestClass : global::TestApp

Evident, nu este recomandat crearea propriului spaiu de nume System, i este puin
probabil c vei gsi cod n care s existe aa ceva. Totui, n cadrul proiectelor mari,
probabilitatea de duplicare a unor spaii de nume este mai mare, ns n aceste situaii
folosirea cuvntului cheie global v garanteaz accesarea spaiului de nume rdcin.

84

Elemente de baz n programarea .NET cu C#

n general, se folosete :: pentru referirea unui alias, sau global:: pentru referirea spaiului
de nume global, iar . pentru accesarea tipurilor sau a membrilor.
Este o greeal utilizarea :: mpreun cu un alias care refer un tip n locul unui spaiu de
nume. De exemplu:
using Alias = System.Console;
class TestClass
{
static void Main()
{
// Eroare!
Alias::WriteLine("Hello!");
// OK
Alias.WriteLine("Hello!");
}
}

Reinei c cuvntul global nu este un alias predefinit. Astfel, global.X nu are nicio
semnificaie special, ci capt sens numai cnd este utilizat mpreun cu ::.
Compilatorul va semnala un avertisment dac definii un alias numit global, deoarece global::
se refer ntotdeauna la spaiul de nume global, nu la un alias. De exemplu, urmtoarea linie
de cod va genera avertisment:
using global = System.Collections;

// Warning

4.15. Tratarea erorilor


n lumea .NET, erorile care apar n timpul execuiei aplicaiilor sunt cunoscute sub numele
de excepii. Excepiile ofer o modalitate unitar de semnalare i tratare a erorilor pentru
toate limbajele de programare .NET.

4.15.1. Aruncarea excepiilor


n limbajele de programare premergtoare apariiei .NET faptul c nu exista nicio abordare
unitar (i nici satisfctoare) legat de tratarea erorilor era o problem. Spre exemplu,
funciile din majoritatea DLL-urilor sistem Windows care erau scrise n C raportau erorile
prin intermediul valorii returnate, i chiar aceasta ntr-un mod ce putea produce confuzie (n
unele cazuri, 0 semnifica succes, iar 1 eroare, pe cnd n alte cazuri semnificaia era invers).
Componentele COM returneaz un cod de eroare prin intermediul unei valori HRESULT pe
32 de bii. Alte limbaje de programare, precum C++ i Java, pot utiliza un mecanism de
tratare a erorilor bazat pe excepii.
Pentru interoperabilitatea inter-limbaj, .NET Framework a standardizat o singur modalitate
de semnalare i captare a erorilor bazat pe excepii. Putei s imaginai excepiile ca fiind
condiii neprevzute care apar n timpul executrii aplicaiei sau n momentul n care codul
ruleaz n interiorul .NET Framework. Cnd apare o astfel de situaie, codul arunc (throw)
un obiect excepie pe care o alt secven de cod l poate prinde (catch).
O excepie poate fi prins de ctre cod n aceeai metod n care apare eroarea. Dac nu,
excepia este aruncat codului apelant, problema remedierii erorii cznd n sarcina
acestuia, posibil chiar reluarea operaiei care a produs eroarea. n cazul n care apelantul nu
capteaz eroarea, excepia este aruncat apelantului acestuia, i aa mai departe, pn la
gsirea unei metode care capteaz excepia. n cazul n care nicio metod nu trateaz

85

Medii i Tehnologii de Programare curs

excepia, atunci utilizatorul este ntiinat de apariia erorii prin intermediul unei ferestre de
dialog (din nefericire, o excepie netratat duce la ncheierea prematur a execuiei programului).
Expresia aruncarea unei excepii este chiar potrivit deoarece un obiect excepie este de
fapt transmis napoi apelantului atunci cnd apare o excepie. Codul care prinde excepia
poate examina proprietile obiectului excepie i poate apela metodele acestuia, avnd
astfel la dispoziie mijloacele pentru luarea msurilor necesare: informarea utilizatorului
(descrierea erorii, locul de apariie al acesteia sau o legtur ctre un fiier help) sau
anularea discret a operaiei care a cauzat problema.

4.15.2. Obiectul Exception


Obiectul Exception este definit n .NET Framework avnd numele complet System.Exception.
Niciodat nu va fi aruncat o excepie de acest tip, ci una derivat din aceasta. Putei examina
n Figura 4.16 o parte din excepiile pe care le expune .NET Framework. De exemplu,
operaiile matematice pot arunca un obiect ArithmeticException, OverflowException sau
DivideByZeroException, pe cnd multe funcii matematice pot arunca un obiect
ArgumentOutOfRangeException.

Figura 4.16. Ierarhia celor mai importante obiecte excepie din .NET Framework

Pentru o list complet de obiecte excepie, accesai comanda Exceptions din meniul
Debug. Vei observa o list impresionant cu obiecte de tip excepie (Figura 4.17).

86

Elemente de baz n programarea .NET cu C#

Figura 4.17. Lista complet a obiectelor excepie, mprit pe categorii

S analizm n continuare cele mai importante proprieti i metode comune obiectelor de


tip excepie. Toate proprietile acestora sunt read-only cu excepia proprietilor Source i
HelpLink.
Proprietatea Message reprezint un text descriptiv asociat unei excepii. Spre exemplu,
proprietatea Message asociat excepiei DivideByZeroException returneaz irul de caractere
"Attempted to divide by zero.".
Obiectele de tip Exception motenesc metoda ToString de la clasa System.Object, iar aceasta
returneaz acelai mesaj de eroare care ar fi afiat utilizatorului n fereastra dialog. Acesta
este similar mesajului returnat de proprietatea Message, ns include suplimentar numele
spaiului de nume i al clasei i, n cazul n care n fiierul executabil sunt cuprinse informaii
pentru depanare (versiune Debug), numele metodei i numrul liniei la care a aprut
eroarea:
System.DivideByZeroException: Attempted to divide by zero.
at MyApp.Program.Main() in d:\Work\MyApp\MyApp\Program.cs:line 44

Proprietatea TargetSite returneaz numele i semntura metodei din care a fost aruncat
excepia, exprimat n sintax C#:
Int32 DivideNumber(Int32 x, Int32 y)

Proprietatea StackTrace returneaz un ir de caractere care descrie traseul erorii, de la locul


n care a aprut, pn la locul n care aceasta a fost prins. De exemplu, considerm c
metoda TestProc apeleaz procedura EvalResult care, la rndul ei, apeleaz funcia
DivideNumber. Dac funcia DivideNumber arunc o excepie DivideByZeroException, iar procedura
TestProc este cea care capteaz excepia, valoarea proprietii StackTrace citit n procedura
TestProc va arta astfel:
at MyApp.Program.DivideNumber(Int32 x, I nt32 y)
in d:\Work\MyApp\MyApp\Program.cs:line 91
at MyApp.Program.EvalResult() in
d:\Work\MyApp\MyApp\Program.cs:line 87
at MyApp.Program.TestProc() in
d:\Work\MyApp\MyApp\Program.cs:line 77

Astfel de informaii (nume ale fiierelor surs, nume de funcii, numere ale liniilor de cod)
vor fi accesibile numai n cazul n care aplicaia a fost compilat n mod Debug (include
informaii pentru depanare).
Proprietatea HelpLink seteaz sau returneaz un URN (Uniform Resource Name) sau URL
(Uniform Resource Locator) ctre fiierul de help asociat obiectului excepie, sub forma:
file:///C:/Applications/Bazzal/help.html#ErrorNum42

87

Medii i Tehnologii de Programare curs

4.15.3. Cuvntul cheie throw


Folosind cuvntul cheie throw putei provoca apariia unei erori. Acesta primete numai un
singur parametru: obiectul excepie care va fi aruncat. Exceptnd cazul n care avei deja un
obiect excepie (cum se ntmpl n interiorul unui bloc catch), trebuie s creai un astfel de
obiect i s i setai n mod potrivit proprietile. n cele mai multe cazuri, putei s creai un
obiect excepie ntr-o singur declaraie i s l aruncai:
// Aceast instructiune corespunde unei erori de tip "File not found."
throw new FileNotFoundException();

Atunci cnd creai obiectul excepie, putei s specificai un mesaj mai clar prin transmiterea
unui argument constructorului obiectului excepie:
throw new FileNotFoundException("Initialization file not found");

O clas excepie poate expune mai muli constructori, fiecare dintre acetia permind iniializarea unui anume set de proprieti. De exemplu, constructorul clasei ArgumentException
poate primi ca argument numai mesajul, sau mesajul i numele argumentului care a
provocat excepia:
public void Afisare(string nume, int varsta)
{
if (string.IsNullOrEmpty(nume))
{
throw new ArgumentException("Sir gol sau nul");
}
else if (varsta < 0)
{
throw new ArgumentException("Nu sunt permise valori negative", "varsta");
}
Console.WriteLine("Nume: {0}, varsta: {1}", nume, varsta);
}

O alternativ posibil la utilizarea excepiilor este aceea de verificare n cadrul codului scris
a posibilelor cauze de eroare i afiarea pe ecran a unor mesaje (cu ajutorul metodei
MessageBox.Show), ns acesta este un mod de lucru mai puin profesional. Aruncarea unei
excepii n cadrul unei metode presupune faptul c secvena de cod care va apela metoda
respectiv va trata excepia n cauz, n caz contrar, execuia aplicaiei putnd fi ntrerupt
definitiv prin apariia unui mesaj de eroare.

4.15.4. Blocul trycatchfinally


Dac pn n momentul de fa ai vzut modul de lucru al mecanismului de aruncare a
excepiilor, n continuare vei putea aprecia la justa valoare puterea i flexibilitatea blocului
try...catch...finally.

4.15.4.1. Cuvntul cheie catch


Ori de cte ori executai cod care ar putea arunca vreo excepie trebuie ca acea secven
critic s o includei ntr-un bloc try. Poriunea de cod dintre cuvntul cheie try i prima apariie a cuvntului cheie catch este protejat mpotriva excepiilor, iar dac este aruncat vreo
excepie, C# transmite controlul primului bloc catch, acolo unde putei s examinai proprietile obiectului excepie i s decidei modul de reacie la eroare. Iat un exemplu simplu:
try
{
x = x / y;
// Daca y = 0, urmatoarea linie nu va fi executata niciodata
y = Convert.ToInt32(Math.Pow(10, x));
}

88

Elemente de baz n programarea .NET cu C#

catch (Exception ex)


{
Console.WriteLine("EROARE: {0}", ex.Message);
}

De ndat ce apare o excepie programul sare n blocul catch, execut codul din cadrul
blocului, apoi sare la prima linie de dup blocul try...catch.
Desigur, putei avea mai multe blocuri catch, fiecare dintre acestea filtrnd un tip anume de
excepie:
try
{
x = x / y;
y = Convert.ToInt32(Math.Pow(10, x));
}
catch (DivideByZeroException ex)
{
// Tratarea exceptiilor de tip impartire cu zero
}
catch (OverflowException ex)
{
// Tratarea exceptiilor de tip depire (overflow)
}
catch (Exception ex)
{
// Tratarea celorlaltor tipuri de exceptii
}

C# compar tipul obiectului excepie aruncat cu cele din clauzele catch n ordinea n care
acestea apar i execut primul bloc care corespunde din punct de vedere al tipului excepiei.
Este o idee bun aceea de a avea un bloc final catch care s corespund obiectului
System.Exception, deoarece este sigur c acest cod va fi executat n cazul n care niciun alt bloc
catch anterior nu corespunde tipului excepiei aruncate. O clauz catch pentru obiectul
System.Exception corespunde ntotdeauna oricrui tip de excepie, deoarece toate obiectele
excepie deriv din System.Exception (clauza final catch este din punct de vedere conceptual
similar cu clauza default dintr-un bloc switch).
Deoarece toate blocurile catch sunt evaluate n ordinea n care apar, trebuie testate mai nti
excepiile mai particulare, apoi cele mai generale. Dac includei un test asupra obiectului
System.Exception, acesta trebuie plasat n ultimul bloc catch, deoarece acesta corespunde
oricrei excepii i, ca urmare, niciun alt bloc catch plasat dup acesta nu va fi executat
vreodat. Aceast regul poate fi generalizat, astfel c nu trebuie s prindei un obiect
excepie dup prinderea obiectului de tipul din care acesta este derivat.
Prezena declaraiei unui obiect excepie n blocul catch este opional, ns, n cazul n care o
omitei, nu putei obine detalii privitoare la eroarea tratat.
Motorul de execuie .NET definete cteva excepii care pot s apar doar n circumstane cu
adevrat excepionale (i catastrofale) cum ar fi: StackOverflowException, OutOfMemoryException
i ExecutionEngineException. Chiar dac aceste excepii nu sunt provocate de ctre aplicaia
dumneavoastr, putei totui s le prindei, dei, n asemenea cazuri, nu avei altceva de
fcut dect s ncheiai execuia aplicaiei printr-un mesaj de eroare corespunztor,
deoarece aceste erori las aplicaia ntr-o stare instabil.

4.15.4.2. Cuvntul cheie finally


Uneori putei avea nevoie s executai o secven de cod pentru curare atunci cnd este
aruncat o excepie. De exemplu, dac apare o eroare n timp ce operai cu un fiier vei dori
s nchidei acel fiier. n astfel de cazuri avei nevoie s completai blocul try cu o bloc
finally. Codul situat n blocul finally va fi executat ntotdeauna, indiferent dac codul situat

89

Medii i Tehnologii de Programare curs

n blocul try arunc sau nu o excepie. Blocul finally ruleaz chiar dac codul din blocul catch
arunc o excepie, sau chiar dac metoda este prsit ca urmare a apelului unei comenzi
return.
Iat un exemplu de cod care modific directorul curent i asigur faptul c directorul original
este restaurat nainte de prsirea blocului try:
string curdir = "";
try
{
// Memoreaza directorul curent, apoi il modifica
curdir = Environment.CurrentDirectory;
Environment.CurrentDirectory = "c:\\data";
}
catch (Exception ex)
{
// Tratarea eventualelor erori
}
finally
{
// In orice situatie reface directorul curent
Environment.CurrentDirectory = curdir;
}

Este perfect legal utilizarea unui bloc tryfinally fr un bloc catch. O astfel de secven de
cod poate fi potrivit atunci cnd dorii ca apelantul s prind i s proceseze toate erorile
aprute n metoda curent, dar n acelai timp avei o secven de cod de curare care
trebuie s fie executat indiferent de caz. Un bloc finally poate fi de asemenea util n cazul n
care dorii s furnizai o secven de cod de curare pentru o funcie care conine mai multe
instruciuni de ieire din funcie:
public static int TestFunction(int x, int y)
{
try
{
// ...
if (x > 0)
return 1;
// ...
if (y == 0)
return 2;
// ...
return 3;
}
finally
{
// Acest cod va rula indiferent de calea de iesire din functie
Console.Write("Finally");
}
}

Trebuie menionat faptul c n situaia n care codul din blocul finally arunc o excepie,
blocul este prsit imediat. n consecin, trebuie s v asigurai c nu va aprea nicio eroare
n blocul finally, iar pentru aceasta putei s utilizai un alt bloc try n interiorul blocului
finally.

4.15.5. Re-aruncarea unei excepii


Instruciunea throw este util n special atunci cnd dorii s prindei un subset al tuturor
excepiilor posibile, iar restul s le transmitei mai departe apelantului metodei. Aceasta este
o practic uzual n programare: fiecare poriune de cod trateaz erorile pe care tie s le
trateze, transmindu-le pe celelalte codului apelant. n cazul n care nici un bloc catch nu
corespunde cu excepia curent, excepia i este aruncat n mod automat apelantului. ns,

90

Elemente de baz n programarea .NET cu C#

este bine ca excepia s fie aruncat explicit, astfel nct s nu prei un programator lene
sau distrat:
try
{
// Efectuarea unor operatii aritmetice
}
catch (DivideByZeroException ex)
{
}
catch (OverflowException ex)
{
}
catch (Exception ex)
{
// Aruncarea explicita a exceptiei necunoscute catre apelant
throw;
}

Instruciunea throw fr argumente arunc mai departe obiectul excepie curent i trebuie s
apar ntr-o clauz catch pentru a fi considerat valid.
n unele cazuri, este posibil s dorii aruncarea mai departe a unui tip diferit de obiect
excepie, pentru cteva motive:

Putei s ascundei adevratul motiv al unei probleme aprute sau s ascundei


detalii din mesajele de eroare care expun date critice unor utilizatori maliioi (de
exemplu, numele fiierului n care stocai parole sau alte informaii privitoare la
securitatea unei aplicaii).

Putei traduce o excepie aprut ntr-una mai pe neles pentru codul apelant.

// *** Cod apelat


try
{
// efectuarea unor operatii aritmetice
}
catch (DivideByZeroException ex)
{
// Arunca un obiect exceptie diferit ...
// ... dar trasmite exceptia originala in parametrul InnerException
throw new ArgumentException("Parametri invalizi", ex);
}
// Alte blocuri catch

Apelantul poate testa excepia intern:


// *** Cod apelant
try
{
// apelarea metodei anterioare
}
catch (ArgumentException ex)
{
Console.WriteLine("a aparut o eroare ArgumentException.");
if (ex.InnerException != null)
{
Console.WriteLine("Exceptie interna: " + ex.InnerException.Message);
}
}

4.15.6. Blocul using


n mod normal toate resursele calculatorului necesit adoptarea ablonului clasic alocare
utilizare eliberare. Unele resurse (de exemplu, vectorii) sunt eliberate automat de ctre

91

Medii i Tehnologii de Programare curs

.NET Framework, ns altele (fiiere, conexiuni la baze de date, ferestre etc.) necesit adesea
o operaie explicit de eliberare a resurselor.
Acest ablon este frecvent utilizat, astfel c .NET Framework definete interfaa IDisposable
care ofer o singur metod: Dispose. Iat un exemplu de alocare i eliberare a unui obiect de
tip Brush:
SolidBrush br = new SolidBrush(Color.Red);
// ...
br.Dispose(); // Distrugerea obiectului

Unele tipuri de date (de regul cele care opereaz cu fiiere sau baze de date), dei implementeaz interfaa IDisposable, ofer metoda public Close care apeleaz metoda privat
Dispose.
Pentru prevenirea situaiilor de eroare i, n consecin, a prsirii codului nainte de
dealocarea resurselor, este bine s includei codul care opereaz cu aceste resurse ntr-un
bloc tryfinally:
public string ReadTextFile(string fileName)
{
StreamReader sr = null;
try
{
sr = new StreamReader(fileName);
return sr.ReadToEnd();
}
finally
{
sr.Close();
}
}

C# ofer programatorilor blocul using care poate elibera automat unul sau mai multe obiecte
IDisposable fr nicio aciune explicit din partea dumneavoastr. Iat aceeai secven de
cod transcris prin utilizarea blocului using:
public string ReadTextFile(string fileName)
{
using (StreamReader sr = new StreamReader(fileName))
{
return sr.ReadToEnd();
}
}

Instruciunea using apeleaz metoda Dispose a obiectului ntr-un mod corect i face ca, de
ndat ce este apelat metoda Dispose, acesta s nu mai fie accesibil. ntr-un bloc using,
obiectul este read-only i nu poate fi modificat sau reatribuit.
Instruciunea using asigur faptul c metoda Dispose este apelat chiar dac apare o excepie
la apelarea metodelor obiectului. Putei obine acelai rezultat prin plasarea obiectului ntrun bloc try, iar apelarea metodei Dispose ntr-unul finally; de fapt acesta este modul n care
instruciunea using este tradus de ctre compilator. Precum am mai amintit, orice excepie
va fi raportat codului apelant.

4.15.7. Obiecte excepie personalizate


Uneori o metod trebuie s raporteze o eroare care nu corespunde cu niciunul dintre
obiectele excepie predefinite n .NET. Soluia este aruncarea unei instane a unei clase
excepie definite de utilizator. Prin definiie, o clas excepie reprezint un tip derivat din
System.Exception. Microsoft sugereaz ca tipurile excepie definite de utilizatori s fie derivate
din System.ApplicationException (spre deosebire, excepiile .NET runtime sunt derivate din
System.SystemException), iar numele lor s aib sufixul "Exception".

92

Elemente de baz n programarea .NET cu C#

Toate proprietile unui obiect excepie trebuie s fie read-only, iar apelantul s le poat
iniializa numai prin intermediul constructorilor. Iat un exemplu de clas excepie
UnableToLoadIniFileException care are un mesaj de eroare implicit (poate fi suprascris) i care
permite codului apelant s iniializeze proprietatea InnerException:
public class UnableToLoadIniFileException : System.ApplicationException
{
private const string defaultMessage = "Unable to load initialization file";
// Constructorii cu mai putini parametri apeleaza constructorii cu mai multi parametri
public UnableToLoadIniFileException()
: this(defaultMessage, null)
{
}
public UnableToLoadIniFileException(string message)
: this(message, null)
{
}
public UnableToLoadIniFileException(Exception innerException)
: this(defaultMessage, innerException)
{
}
// Cel mai complet constructor apeleaza constructorul clasei de baza
public UnableToLoadIniFileException(string message, Exception innerException)
: base(message, innerException)
{
}
}

Putei folosi clasa UnableToLoadIniFileException ntr-o instruciune throw i ntr-un bloc catch:
// *** Codul apelant
public void TestCustomException()
{
try
{
LoadIniFile();
}
catch (UnableToLoadIniFileException ex)
{
Console.WriteLine(ex.Message); // "Unable to load initialization file"
}
catch (Exception ex)
{
// Tratarea altor erori
}
}
public void LoadIniFile()
{
try
{
// Incearca deschiderea fisierului ini.
}
catch (Exception ex)
{
// Indiferent cine provoaca eroarea, arunca o exceptie mai particulara
throw new UnableToLoadIniFileException(ex);
}
}

Obiectele excepie personalizate pot avea i alte ntrebuinri, altele dect simpla raportare a
unui mesaj de eroare. Ele pot include metode personalizate care ncearc s rezolve anumite
erori. De exemplu, putei crea clasa DriveNotReadyException avnd o metod ShowMessage, care
afieaz un mesaj de eroare i roag utilizatorul s introduc discul n unitate, apoi s

93

Medii i Tehnologii de Programare curs

rencerce operaia care a provocat eroarea. Introducnd astfel de cod ntr-o clas excepie
facei mai uoar reutilizarea acesteia.

4.16. Convenii de denumire


Urmrirea unui set consistent de convenii de denumire n dezvoltarea, de exemplu, a unei
biblioteci software, permite acesteia s fie utilizat de mai muli dezvoltatori n proiecte
separate. Dincolo de consistena formei, denumirea elementelor de program trebuie s fie
uor de neles i trebuie s ofere informaii despre rolul fiecrui element. Microsoft a definit
un set de convenii de denumire i recomand utilizarea acestora pentru API-urile expuse
public (membri i tipuri publice sau protejate i interfee implementate explicit).
Se recomand ca elementele de program s aib nume sugestive i complete, formate, dac
se poate, din mai multe cuvinte. Pentru diferenierea cuvintelor dintr-un identificator, scriei
cu majuscul prima liter din fiecare cuvnt care compune numele unui identificator. Nu
utilizai n cadrul numelor caracterul underscore (_) nici mcar pentru a separa cuvintele
componente. Exist dou moduri potrivite pentru scrierea cu majuscul a identificatorilor, n
funcie de utilizarea acestuia:

PascalCasing: utilizat pentru toi identificatorii cu excepia numelor parametrilor,


scrie cu majuscul primul caracter din fiecare cuvnt (fiind incluse aici acronime mai
lungi de dou caractere). Un caz special este acela al acronimelor din dou caractere,
n care amndou literele sunt scrise cu majuscul. PascalCasing se utilizeaz pentru
toi membrii publici (metode, proprieti, evenimente, cmpuri), tipuri (clase,
interfee, enumerri) i spaii de nume ale cror denumiri sunt formate din mai
multe cuvinte. Exemple: PropertyDescriptor, HtmlTag, IOStream.

camelCasing: utilizat numai pentru denumirea parametrilor, scrie cu majuscul


primul caracter al fiecrui cuvnt cu excepia primului cuvnt. Exemple:
propertyDescriptor, ioStream, htmlTag.

n denumirea elementelor de program este bine s inei cont de urmtoarele recomandri:


1. Atunci cnd dai nume unor elemente de program, evitai folosirea numelor care
corespund cuvintelor cheie utilizate n majoritatea limbajelor de programare.
Potrivit CLS, toate limbajele .NET trebuie s pun la dispoziie un mecanism care
permite accesul la elementele de program care folosesc acelai nume cu al unui
cuvnt cheie a acelui limbaj. De exemplu, C# folosete n acest sens caracterul @
pentru prefixarea acestor identificatori. Oricum, cel mai bine este s evitai folosirea
cuvintelor cheie ca nume ale elementelor de program.
2. Nu folosii abrevieri sau prescurtri ca parte a numelui unui identificator.
3. Se recomand ca numele claselor i a structurilor trebuie s conin substantive, iar
numele metodelor s conin verbe (ca s exprime mai clar o aciune), ambele
exprimate n PascalCasing.
4. Se recomand prefixarea numelor interfeelor cu caracterul I.
5. Nu prefixai clasele cu nicio combinaie de caractere, de exemplu cu caracterul C.
6. Nu utilizai prefixe pentru numele cmpurilor, de exemplu nu folosii "s_" pentru a
indica un cmp static.
7. ncercai s folosii n terminaia numelor claselor derivate numele clasei de baz.
Acest mod de denumire este uor de interpretat i explic n mod clar relaia dintre
clase. Exemple: ArgumentOutOfRangeException, care este un fel de Exception i
SerializableAttribute, care este un fel de Attribute. Totui, este important utilizarea
cu discernmnt a acestui raionament; de exemplu, clasa Button este un tip Control,
dei Control nu apare n denumirea clasei.

94

Elemente de baz n programarea .NET cu C#

8. Putei da unei proprieti acelai nume cu al tipului ei. De exemplu, urmtoarea


proprietate preia i seteaz o valoare enum de tip Color, astfel c proprietatea este
denumit Color:
public enum Color {...}
public class Control
{
public Color Color
{
get {...}
set {...}
}
}

4.17. Diferene cheie dintre C# i Visual Basic


4.17.1. Cteva caracteristici ale Visual Basic care nu se regsesc n C#

Declararea variabilelor cu cuvntul cheie WithEvents, fapt care permite programatorilor s selecteze mai uor obiectele construite astfel i evenimentele asociate din
editorul de cod.

Utilizarea structurilor With ... End With pentru accesarea rapid a membrilor unui
obiect.

Utilizarea modulelor

Spaiul de nume My.


Spaiile de nume pot fi importate global sau la nivel de proiect, spre deosebire de C#,
n care acestea trebuie s fie importate separat pentru fiecare fiier surs.

Filtrarea excepiilor pe baza unor expresii, nu doar a tipului excepiei, folosind


clauza When ataat blocurilor Catch.

Cu ajutorul sintaxei de prsire a unei bucle, diferit pentru fiecare tip de bucl,
Visual Basic permite, n cazul buclelor de cod ncuibate, prsirea oricreia dintre
acestea (C# pune la dispoziie comanda break pentru prsirea oricrei bucle).

For i As Integer = 1 To 10
Dim j As Integer = 1
Do While j <= 10
' Paraseste bucla For
If Evaluare(i, j) = 0 Then Exit For
' ...
j += 1
Loop
Next

Att operatorul de atribuire i cel de comparare este =.

n Visual Basic proprietile pot primi parametri.


Visual Basic permite modificarea dimensiunii unui vector deja declarat prin
instruciunile Redim i Redim Preserve. Utilizarea cuvntului cheie Preserve duce la
pstrarea elementelor pe care le conine vectorul i dup redimensionarea acestuia.

Comparativ cu C#, Visual Basic ofer multe funcii suplimentare: funcii de conversie
(CInt, CStr, CByte, CDbl, CBool, CByte, CDate, CLng, CCur, CObj), funcii de interaciune
(AppActivate, Beep, CallByName, Choose, Command, Environ, IIf, InputBox, MsgBox, Partition,
Shell, Switch), lucrul cu date calendaristice (DateAdd, DateDiff, DatePart, DateSerial,
DateValue, Year, Month, Day, Hour, Minute, Second, MonthName, Weekday, WeekdayName, TimeSerial,
i TimeValue) etc. Multe dintre aceste funcii pot fi utilizate n C# prin importarea
spaiului de nume Microsoft.VisualBasic.

95

Medii i Tehnologii de Programare curs

4.17.2. Cteva caracteristici ale C# care nu se regsesc n Visual Basic

Permite blocurilor de cod s ruleze cod nesigur prin intermediul cuvntului cheie
unsafe i asigurarea de suport pentru pointeri.
Clase i interfee pariale.

Clase statice (Visual Basic compenseaz prin existena modulelor).

Utilizarea cuvintelor cheie checked i unchecked pentru verificarea depirilor n


operaii aritmetice (Visual Basic ofer n schimb directiva de compilare Option
Strict).

Buclele for pot conine condiii multiple:

for(int i = 0; i < 10 && altaConditie; i++)

96

Controale

5. Controale
Un control reprezint un obiect care are o component grafic. Un control este situat pe un
formular (o fereastr) i interacioneaz cu utilizatorul, furniznd informaii pe care utilizatorul le poate utiliza. Exemple de controale sunt casetele text, etichetele, butoanele, listele
derulante, elementele de meniu, barele cu instrumente i, n general, tot ceea ce se poate
vedea i cu care se poate interaciona ntr-o aplicaie Windows.
O component este similar unui control, cu diferena c nu are nicio component vizual n
timpul rulrii. Atunci cnd adugai o component pe un formular (n modul design), aceasta
nu apare pe suprafaa formularului, ci n component tray, situat sub formular (Figura 5.1).
Putei s selectai componentele, apoi s utilizai panoul de proprieti pentru a le vizualiza
i modifica proprietile. n timpul rulrii componentele sunt invizibile utilizatorului, dei
acestea pot afia unele obiecte vizibile cum ar fi meniuri, ferestre dialog sau pictograme.

Figura 5.1. Componentele sunt plasate n component tray.

Figura 5.2 prezint toolbox-ul asociat cu Visual C#, care afieaz o gam standard de 67 de
controale i componente. Sgeata (arrow tool) din colul stnga sus nu reprezint practic un
control sau o component, ci instrumentul de selecie.

97

Medii i Tehnologii de Programare curs

Figura 5.2. Visual C# ofer o gam larg de controale i componente.

n continuare vor fi descrise diversele tipuri de controale i componente i va fi explicat


modul n care aplicaiile le pot utiliza n modul design i n timpul rulrii pentru a furniza
informaii utilizatorilor i pentru a permite acestora s controleze aplicaia. Va fi explicat de
asemenea modul n care putei lucra cu proprietile, metodele i evenimentele furnizate de
clasa Control. Alte controale derivate din aceast clas motenesc modul de utilizare a
acestor proprieti, metode i evenimente n afara cazului n care acestea sunt suprancrcate.

5.1. Programarea orientat pe evenimente


Programarea orientat pe evenimente (programarea condus de evenimente) este o paradigm a programrii calculatoarelor. Spre deosebire de programele tradiionale, care i urmeaz propriul flux de instruciuni, schimbndu-i cursul numai n puncte de ramificaie
(instruciuni de testare etc.), cursul execuiei unui program orientat pe evenimente este
condus n mare parte de evenimente externe.
Programele orientate pe evenimente sunt formate de obicei dintr-un numr de secvene de
cod numite proceduri eveniment (event handlers), care sunt apelate de ctre un coordonator
(dispatcher) ca rspuns la evenimente externe. Acesta apeleaz procedurile eveniment,
folosind de obicei o coad de ateptare a evenimentelor, care reine evenimentele ce
ateapt s fie procesate (Figura 5.3). n multe cazuri, procedurile eveniment pot declana la
rndul lor alte evenimente, provocnd astfel o cascad de evenimente.

98

Controale

Figura 5.3. Tratarea mesajelor de ctre o aplicaie Windows

Aplicaiile cu interfee grafice sunt de obicei programate astfel nct sunt conduse de
evenimente. Sistemele de operare sunt un alt exemplu clasic de programe conduse de
evenimente pe cel puin dou nivele. La cel mai de jos nivel, handlerele de ntreruperi se
comport ca handlere de evenimente hardware, cu procesorul n rol de coordonator
(dispatcher). Sistemele de operare se comport, de asemenea, ca i coordonatori pentru
procese, transmind datele i ntreruperile soft ctre procese utilizator, care de multe ori
sunt programate ca i handlere de eveniment.

5.2. Controale i componente


Majoritatea controalelor sunt grafice prin natura lor. Butoanele, casetele text i etichetele
furnizeaz n mod grafic intrri i feedback pentru utilizatori. Acestea afieaz date i permit
utilizatorului s comande prin intermediul acestora programul.
Att controalele ct i componentele pot fi create n modul design sau n timpul rulrii.
Prima variant este mai comod i permite modificarea aspectului i a proprietilor controlului sau a componentei fr a necesita scrierea de cod. Totui, pot exista situaii n care este
mai util crearea controalelor n timpul rulrii prin scrierea de cod. De exemplu, dac nu tii
de cte casete text vei avea nevoie n timpul rulrii aplicaiei, nu putei s le creai n modul
design.
Unele controale pot conine la rndul lor alte controale. De exemplu, controalele GroupBox i
Panel pot gzdui alte controale. Acestea se numesc controale container.

99

Medii i Tehnologii de Programare curs

5.2.1. Crearea i distrugerea controalelor


n mod normal vei aduga controale pe un formular n modul design. Totui, uneori este
mult mai convenabil s creai controale noi n timpul rulrii. De exemplu, poate vrei s
afiai interfee diferite pentru fiecare utilizator al unei aplicaii (n funcie de gradul de
autorizare al fiecrui utilizator).
Urmtorul cod arat modul n care un program poate crea un control nou de tip Label. nti
se creeaz un obiect nou de tip Label, iniializat prin folosirea cuvntului cheie new, i se
seteaz proprietile dorite, iar n final controlul este adugat la colecia de controale a
formularului curent.
Label lbl = new Label();
lbl.SetBounds(100, 100, 50, 16);
lbl.Text = "Eticheta";
this.Controls.Add(lbl);

De obicei, un control etichet are doar rol de afiare a unui text, astfel c nu v vei folosi de
evenimentele acestuia. n schimb, alte controale, cum ar fi butoanele sau barele de derulare,
nu ne vor fi de mare folos dac programul nu poate rspunde la evenimentele lor. De
exemplu, dorii s creai pe un formular cte un buton pentru fiecare fiier dintr-un director,
iar la click pe un buton s se deschid fiierul asociat. Dac nu cunoatei dinainte numrul
de fiiere din director, nu vei ti de cte controale vei avea nevoie.
O soluie la aceast problem este utilizarea operatorului += care v permite adugarea unei
proceduri eveniment pentru un control sau component. Urmtoarea secven de cod
ilustreaz acest mod de lucru:
private void Form1_Load(object sender, EventArgs e)
{
Button btn = new Button();
btn.SetBounds(100, 100, 50, 32);
btn.Text = "Mesaj";
this.Controls.Add(btn);
btn.Click += btn_Click;
}
// handlerul de eveniment generat automat
void btn_Click(object sender, EventArgs e)
{
throw new NotImplementedException();
}

Atunci cnd scriei cod pentru adugarea unei noi proceduri eveniment folosind operatorul
+=, mediul Visual Studio v propune, la apsarea tastei TAB, n prima etap asocierea
evenimentului n cauz cu o procedur eveniment (avnd numele compus din numele
controlului i al evenimentului: numeControl_numeEveniment), apoi crearea efectiv a procedurii eveniment respective (vezi Figura 5.4).

Figura 5.4. Oferirea de ajutor din partea Visual Studio pentru inserarea unei proceduri eveniment

Putei utiliza aceeai metod ca procedur eveniment pentru mai multe controale, de
exemplu butoane. n acest caz, codul poate converti parametrul sender ntr-un obiect buton,
putnd astfel s determinai prin proprietile Name sau Text butonul care a fost apsat.
Pentru a terge un control de pe un formular tergei-l din colecia de controale asociat
formularului. Pentru eliberarea resurselor asociate controlului n cauz, setai orice variabil
care se refer la acesta la valoarea null. Iat un exemplu:
this.Controls.Remove(btn);
btn = null;

100

Controale

n acest mod putei s tergei att controalele create dinamic, ct i pe cele create n modul
design. De asemenea, putei s tergei asocierea dintre evenimentul unui control i o
procedur eveniment, prin utilizarea operatorului -=, precum putei vedea n exemplul de
mai jos:
btn.Click -= btn_Click;

5.2.2. Proprieti ale controalelor


O proprietate reprezint o valoare asociat unui control. Adesea, o proprietate corespunde n
mod evident unei caracteristici vizuale a controlului. De exemplu, proprietatea Text
reprezint textul afiat de ctre control, BackColor reprezint culoarea de fundal a
controlului, Top i Left indic poziia controlului .a.m.d.
Putei manipula proprietile unui control att n modul design ct i n timpul rulrii.

Proprieti n modul design


Pentru modificarea proprietilor unui control n modul design deschidei formularul n
Form Designer i selectai controlul printr-un click. Fereastra de proprieti va afia proprietile controlului. Putei observa n Figura 5.5 fereastra de proprieti asociat unui
control de tip buton. Proprietatea Text are valoarea Sterge, iar proprietatea TextAlign (care
determin amplasarea textului pe buton) este setat la valoarea MiddleCenter.
Lista derulant (controlul ComboBox) din partea superioar a ferestrei de proprieti indic
faptul c acest control se numete button1 i este de tip System.Windows.Forms.Button.

Figura 5.5. Fereastra de proprieti v permite modificarea proprietilor unui control n modul design.

Proprieti compuse
Doar cteva proprieti au valori compuse. Proprietatea Location include coordonatele X i Y
ale colului stnga-sus al controlului. Proprietatea Size conine limea i nlimea controlului. Proprietatea Font include numele fontului, dimensiunea acestuia i alte caracteristici
specifice fonturilor (bold, italic etc.).
Fereastra de proprieti afieaz aceste proprieti cu un semn plus (+) n stnga acestora,
prin intermediul cruia putei desfura proprietile respective. Figura 5.6 afieaz aceeai
fereastr de proprieti ca cea din Figura 5.5, ns cu proprietile Font i Location
desfurate.

101

Medii i Tehnologii de Programare curs

Putei modifica toate caracteristicile unei proprieti compuse prin intermediul unei ferestre
dialog afiate la click pe butonul situat n partea dreapt a proprietii compuse. De exemplu,
pentru proprietatea Font va fi afiat fereastra dialog din Figura 5.7.

Figura 5.6. Fereastra de proprieti v permite modificarea proprietilor complexe n modul design.

Figura 5.7. Fereastra dialog care v permite modificarea caracteristicilor unui font.

Proprieti restrictive
Unele proprieti permit valori restrictive. De exemplu, proprietatea Visible poate primi
numai valorile true sau false. Dac dai click pe o asemenea proprietate, v va fi afiat o list
derulant din care putei alege una dintre valorile permise pentru acea proprietate.

102

Controale

Alte proprieti restrictive au asociate valori de tip enumerare. Proprietatea FlatStyle a unui
buton permite selectarea valorilor Flat, Popup, Standard i System. Putei da dublu click pe
valoarea unei proprieti restrictive pentru ciclarea valorilor posibile pe care le poate lua
acea proprietate.
Unele proprieti pot conine referine la alte controale. De exemplu, proprietatea ImageList
reprezint o referin la o component ImageList care conine imaginile pe care controlul le
poate afia.
n fine, alte proprieti restrictive pot afia diferite editoare care permit introducerea n mod
grafic a valorilor unei proprieti. Un astfel de exemplu este proprietatea Anchor, care
permite ancorarea marginilor unui control la marginile containerului, astfel nct controlul
i pstreaz poziia relativ n cazul redimensionrii containerului.

Proprieti colecie
Unele proprieti reprezint colecii de obiecte. De exemplu, un control de tip ListBox
afieaz o list de elemente text. Proprietatea Items a acestuia reprezint o colecie ce
conine acele elemente. Iniial, fereastra de proprieti afieaz valoarea acestei proprieti
ca i (Collection). La apsarea butonului din dreapta proprietii de tip colecie va aprea o
fereastr dialog n care putei edita elementele coleciei.
Alte proprieti pot conine o colecie de obiecte care, la rndul lor, s conin o colecie de
obiecte. De exemplu, controlul ListView are proprietatea Items care reprezint o colecie de
elemente de tip ListViewItem. Fiecare element din colecie reprezint un obiect care are o
proprietate SubItems, care la rndul ei este o colecie (Figura 5.8). La afiarea controlului n
mod detaliat, un obiect din colecia Items reprezint un rnd din afiarea tabelar, iar
proprietatea SubItems reprezint valorile secundare de pe acel rnd.

Figura 5.8. Obiectele din colecia Items a controlului ListView au fiecare cte o proprietate SubItems, care
reprezint de asemenea o colecie.

Accesarea proprietilor n timpul rulrii


Visual C# permite setarea majoritii proprietilor controalelor n modul design, ns
adeseori avei nevoie s le modificai n timpul rulrii.

103

Medii i Tehnologii de Programare curs

O proprietate poate fi vzut ca orice membru public al obiectului de tip control, putnd s o
accesai prin numele controlului urmat de caracterul punct i de numele proprietii. Dac o
proprietate conine o referin la un obiect, putei utiliza proprietile acelui obiect folosind
aceeai sintax:
if (textBox1.Font.Bold)
MessageBox.Show("Bold");
else
MessageBox.Show("Not bold");

Dac o proprietate reprezint o colecie sau un vector, putei s parcurgei ntr-o bucl
valorile din colecie la fel cum parcurgei o colecie sau un vector:
foreach (Object selected_item in lstChoices.SelectedItems())
Debug.WriteLine(selected_item.ToString());

Reinei faptul c unele proprieti ale controalelor sunt read-only, astfel c nu vei putea s
le modificai. Un astfel de exemplu este proprietatea Bottom care este calculat automat n
funcie de alte dou proprieti:
control.Bottom = control.Top + control.Height;

Proprieti utile ale controalelor


n Tabelul 5.9 sunt prezentate succint proprietile implementate de clasa Control. Toate
controalele care motenesc clasa Control motenesc i aceste proprieti, dac nu cumva
suprancarc comportamentul clasei Control.
Proprietate
AllowDrop
Anchor

Descriere
Determin dac controlul permite operaii drag-and-drop.
Determin care dintre marginile controlului sunt ancorate de marginile
controlului container.

AutoSize

Determin dac controlul se redimensioneaz automat n funcie de


coninutul acestuia.
Determin culoarea de fundal a controlului.
Determin imaginea de fundal a controlului.
Determin modul n care este utilizat imaginea de fundal a controlului.
Returneaz distana dintre marginea de sus a controlului container i
marginea de jos a controlului. Proprietatea este read-only. Modificai
proprietile Top i Height pentru modificarea valorii acesteia.

BackColor
BackgroundImage
BackgroundImageLayout
Bottom

Bounds
CanFocus
CanSelect

Determin dimensiunile i locaia controlului.


Determin dac controlul poate primi focalizarea.
Determin dac controlul poate selecta. De exemplu, un TextBox poate
selecta o parte sau tot coninutul text.

Capture
CausesValidation

Determin dac controlul a captat mouse-ul.


Determin dac controlul valideaz alte controale atunci cnd primete
focalizarea.

ClientRectangle

Aceast structur de tip Rectangle reprezint suprafaa client a


controlului.
Aceast structur de tip Size reprezint nlimea i limea controlului.
Indic dac controlul sau unul dintre controalele coninute de acesta a
primit focalizarea. Este read-only.

ClientSize
ContainsFocus

104

ContextMenu
ContextMenuStrip
Controls

Determin meniul context asociat cu controlul.


Determin banda de meniu context asociat cu controlul.
Aceast colecie conine referine la controalele coninute de acest
control.

Cursor

Determin cursorul pe care l va afia controlul atunci cnd mouse-ul


este deasupra lui.

Controale

DataBindings
DefaultBackColor
DefaultFont
DefaultForeColor
DisplayRectangle
Dock
Enabled
Focused
Font
ForeColor
Handle
HasChildren
Height
InvokeRequired

Left
Location
Margin

Returneaz DataBindings asociat cu controlul, utilizat pentru legarea


controlului la o surs de date.
Returneaz culoarea de fundal implicit a controlului.
Returneaz fontul implicit al controlului.
Returneaz culoarea de desenare implicit pe suprafaa controlului.
Returneaz o structur Rectangle care conine suprafaa afiat a
controlului.
Determin marginile controlului printe la care controlul va fi andocat.
Determin dac controlul va interaciona cu utilizatorul.
Indic dac controlul are focalizarea. Este read-only.
Determin fontul asociat controlului.
Determin culoarea de desenare pe suprafaa controlului.
Returneaz handle-ul ferestrei controlului. Este read-only.
Indic dac controlul conine alte controale. Este read-only.
Determin nlimea controlului.
Returneaz true dac codul apelant ruleaz pe un fir de execuie diferit
de firul de execuie al controlului i, ca urmare, trebuie utilizat o
metod invoke pentru a putea interaciona cu controlul.
Determin coordonata X a marginii din stnga a controlului.
Aceast structur Point determin poziia colului stnga-sus a
controlului.
Determin spaiul dintre acest control i marginea altui control din
cadrul unui container.

MaximumSize
MinimumSize
ModifierKeys
MouseButtons

Determin dimensiunea maxim permis pentru acest control.


Determin dimensiunea minim permis pentru acest control.
Indic ce taste speciale (Shift, Ctrl, Alt) sunt apsate. Este read-only.
Indic ce butoane de mouse (stnga, dreapta, mijloc, nici unul) sunt
apsate. Este read-only.

MousePosition

Returneaz o structur Point care returneaz poziia curent a mouseului (punctul (0, 0) este situat n colul stnga-sus al ecranului). Este
read-only.

Name
Padding
Parent
PreferredSize

Determin numele controlului.


Determin spaierea coninutului controlului.
Determin printele care conine controlul.
Returneaz o dimensiune care este suficient de mare pentru a cuprinde
coninutul controlului.
Determin regiunea ferestrei controlului. Aceasta reprezint suprafaa n
care controlul poate desena.

Region
Right

Returneaz distana dintre marginea din stnga a controlului container


i marginea din dreapta a controlului. Este read-only. Modificai
proprietile Left i Width pentru modificarea acestei valori.

Size

Aceast structur Size determin dimensiunea controlului incluznd


suprafeele client i non-client.

TabIndex

Determin poziia controlului n cadrul ordinii de selectare a


containerului su. Dac mai multe controale au acelai TabIndex,
acestea sunt parcurse din fa n spate conform cu ordinea lor de
suprapunere (pe axa Z).
Determin dac utilizatorul poate selecta controlul prin apsarea
succesiv a tastei TAB.
Aceast proprietate poate conine un obiect pe care dorii s l asociai
cu controlul.
Determin textul afiat de control.
Determin coordonata Y a marginii de sus a controlului.

TabStop
Tag
Text
Top

105

Medii i Tehnologii de Programare curs

TopLevelControl

Returneaz cel mai de sus ascendent al controlului. De obicei este cea


mai din afar fereastr care conine controlul. Este read-only.

Visible
Width

Determin dac controlul este vizibil.


Determin limea controlului.
Tabelul 5.9. Proprieti specifice clasei Control

5.2.3. Metode
O metod execut cod asociat cu un control. Metodele pot primi parametri la fel ca orice alt
funcie. Deoarece metodele execut cod, nu le putei apela n modul design, ci putei s le
apelai numai prin cod, n timpul rulrii.

Metode utile ale controalelor


Tabelul 5.10 prezint succint metode utile implementate de clasa Control. Toate controalele
care motenesc clasa Control motenesc i aceste metode, dac nu suprancarc comportamentul clasei Control.
Metoda
void BringToFront ()
bool Contains (Control ctl)

Descriere
Aduce controlul n faa celorlalte controale (pe axa Z).
Returneaz true dac controlul ctl este coninut de acest
control.

Graphics CreateGraphics()

Creeaz un obiect Graphics pe care l putei utiliza pentru


desenare pe suprafaa controlului.

DragDropEffects DoDragDrop
(Object data, DragDropEffects
allowedEffects)
void DrawToBitmap(Bitmap bitmap,
Rectangle targetBounds)

Iniiaz o operaie drag-and-drop.

Form FindForm ()
bool Focus ()
Control GetChildAtPoint (Point pt)

Control GetNextControl(Control ctl,


bool forward)

Size GetPreferredSize (Size


proposedSize)
Type GetType ()

void Hide ()
void Invalidate ()
Object Invoke (Delegate method)
Point PointToClient (Point p)

106

Deseneaz o imagine a controlului (inclusiv controalele


coninute) n obiectul Bitmap n suprafaa indicat de
Rectangle.
Returneaz formularul care conine controlul.
D controlului focalizarea.
Returneaz controlul fiu care conine punctul indicat. Dac
mai multe controale conin punctul, este returnat controlul cel
mai de sus pe axa Z.
Dac forward este true, returneaz urmtorul control n
ordinea de selectare a fiului acestui control dup controlul ctl.
Dac forward este false, returneaz controlul anterior din lista
de selectare. Setai ctl = null pentru a porni de la
nceput/sfrit. Returneaz null cnd ajungei la
nceput/sfrit.
Returneaz dimensiunea unei suprafee dreptunghiulare n
care poate s ncap controlul.
Returneaz un obiect Type care reprezint clasa asociat cu
controlul. Putei utiliza acest obiect pentru a obine informaii
despre clas.
Ascunde controlul prin setarea proprietii Visible pe false.
Invalideaz ntreaga suprafa a controlului i foreaz
redesenarea acestuia (apare evenimentul Paint).
Execut delegatul specificat pe firul de execuie care deine
controlul.
Convertete punctul p din coordonate ecran n sistemul de
coordonate a controlului.

Controale

Point PointToScreen (Point p)

Convertete punctul p din coordonatele controlului n


sistemul de coordonate al ecranului.

Rectangle RectangleToClient
(Rectangle r)

Convertete dreptunghiul r din coordonate ecran n sistemul


de coordonate a controlului.

Rectangle RectangleToScreen
(Rectangle r)

Convertete dreptunghiul r din coordonatele controlului n


sistemul de coordonate al ecranului.

void Refresh ()

Foreaz controlul s i invalideze suprafaa client i imediat


dup aceea controlul se redeseneaz pe el i controalele
coninute.
Scaleaz controlul i controale coninute cu factorul de scalare
specificat.

void Scale (SizeF factor)


void Select ()
bool SelectNextControl(Control ctl,
bool forward, bool tabStopOnly,
bool nested, bool wrap)
void SendToBack()
void SetBounds (int x, int y, int
width, int height)
void Show()
string ToString()

void Update()

Mut focalizarea asupra controlului. Unele controale au


versiuni suprancrcate.
Mut focalizarea asupra urmtorului control coninut
mpreun cu acesta.
Trimite controlul n poziia cea mai din spate pe axa Z.
Seteaz poziia i dimensiunea controlului.
Afieaz controlul prin setarea proprietii Visible pe true.
Returneaz o reprezentare textual a controlului. n general
aceasta reprezint tipul controlului, mpreun proprietatea
Text a acestuia (dac o are).
Duce la redesenarea din partea controlului a regiunilor
invalidate din suprafaa client a lui.

Tabelul 5.10. Metode specifice clasei Control

5.2.4. Evenimente
Un control sau un alt obiect genereaz un eveniment pentru ntiinarea programului despre
apariia unor modificri n anumite circumstane. Adesea aciunea de generare a unui
eveniment se mai numete aruncarea unui eveniment. Clasele specifice controalelor
furnizeaz evenimente relevante pentru scopul pentru care au fost create. De exemplu,
controlul Button furnizeaz un eveniment Click pentru ntiinarea programului despre
apsarea unui buton de ctre utilizator.
Programul rspunde la un eveniment prin crearea unui handler de eveniment care prinde
evenimentul i ntreprinde aciunile potrivite acestuia. Fiecare eveniment i definete propriul format al handlerului i determin parametrii pe care handlerul de eveniment i va
primi. Adesea, aceti parametri ofer informaii suplimentare legate de eveniment.
De exemplu, atunci cnd o parte a formularului este acoperit sau expus, formularul
genereaz evenimentul Paint. Handler-ul evenimentului Paint primete ca parametru un
obiect de tip PaintEventArgs. Proprietatea Graphics a acestui parametru reprezint o
referin la un obiect de tip Graphics pe care programul l poate folosi pentru redesenarea
coninutului formularului.
Unele handlere de eveniment primesc parametri care sunt utilizai pentru trimiterea de
informaii legate de eveniment napoi la obiectul care le-a generat. De exemplu, handlerul
evenimentului FormClosing al unei clase formular are un parametru de tip
FormClosingEventArgs. Acesta reprezint un obiect care are o proprietate Cancel. Dac
aceasta este setat pe true, formularul anuleaz evenimentul FormClosing i formularul
rmne deschis n continuare. De exemplu, handlerul de eveniment poate verifica dac
datele introduse de utilizator sunt formatate corect, n caz contrar programul afind un
mesaj de eroare, iar formularul rmnnd deschis.

107

Medii i Tehnologii de Programare curs

Majoritatea evenimentelor asociate unui control sunt specifice acelui tip de control.
Controalele motenesc un set de evenimente de la clasa de baz Control, ns le pot
suprancrca, modificndu-le astfel comportamentul.

Crearea handlerelor de eveniment n modul design


Exist mai multe modaliti prin care putei s creai handlere de evenimente n modul
design. Dac deschidei un formular n Form Designer i dai dublu-click pe un control, se
deschide editorul de cod i va fi afiat handlerul implicit al acelui control. De exemplu,
pentru un control TextBox va fi deschis handlerul evenimentului TextChanged, pentru un
control Button handlerul evenimentului Click, iar pentru formular handlerul evenimentului
Load.
Pentru crearea unor handlere de eveniment, altele dect cel implicite ale controalelor, din
Form Designer selectai un control sau component, apoi n fereastra de proprieti a
acestuia dai click pe pictograma Events , i dai apoi dublu click pe un eveniment. Editorul
de cod va crea un handler de eveniment, urmnd ca dumneavoastr s scriei codul care
dorii s fie executat la apariia evenimentului respectiv.

Setarea handlerelor de eveniment n timpul rulrii


Ai vzut cum putei s adugai handlere de evenimente n faza de design. n continuare vei
nva cum putei s le asignai n timpul rulrii. nti trebuie s creai un handler de
eveniment. Aici trebuie s fii ateni ca parametrii procedurii s fie dai n mod corect pentru
tipul de handler de eveniment pe care dorii s l creai. De exemplu, pentru un control
TextBox, handlerul evenimentului Click trebuie s primeasc doi parametri avnd tipurile
System.Object i System.EventArgs.
Prin utilizarea operatorilor += i -= putei s adugai sau s tergei handlerul unui
eveniment de la un control. Codul de mai jos ilustreaz modul n care un program poate
comute handlerul de eveniment pe care un buton l execut atunci cnd este apsat.
Atunci cnd RadioButton1 este bifat sau debifat, handlerul evenimentului CheckedChanged
adaug sau terge handlerul de eveniment ButtonHandler1 asociat evenimentului Click
pentru butonul Button1. Similar, cnd RadioButton2 este bifat sau debifat, handlerul
evenimentului CheckedChanged adaug sau terge handlerul de eveniment ButtonHandler2
asociat evenimentului Click pentru butonul Button1.
Handlerele de evenimente ButtonHandler1 i ButtonHandler2 afieaz un mesaj care indic
handlerul de eveniment care este executat. Handler-ul evenimentului Load asociat formularului selecteaz primul buton radio.
private void Form3_Load(object sender, EventArgs e)
{
//Selecteaza radioButton1
radioButton1.Checked = true;
}
private void radioButton1_CheckedChanged(object sender, EventArgs e)
{
//Adauga sau sterge ButtonHandler1
if(radioButton1.Checked)
button1.Click += ButtonHandler1;
else
button1.Click -= ButtonHandler1;
}
private void radioButton2_CheckedChanged(object sender, EventArgs e)
{

108

Controale

//Adauga sau sterge ButtonHandler2


if (radioButton2.Checked)
button1.Click += ButtonHandler2;
else
button1.Click -= ButtonHandler2;
}
private void ButtonHandler1(object sender, EventArgs e)
{
//Afisez un mesaj care indica handlerul de eveniment
MessageBox.Show("ButtonHandler1");
}
private void ButtonHandler2(object sender, EventArgs e)
{
//Afisez un mesaj care indica handlerul de eveniment
MessageBox.Show("ButtonHandler2");
}

Evenimente utile ale controalelor


Tabelul 5.11 prezint evenimente utile implementate de clasa Control. Toate controalele
care motenesc clasa Control motenesc i aceste evenimente, dac nu suprancarc comportamentul clasei Control.
Eveniment
AutoSizeChanged
BackColorChanged
BackgroundImageChanged

Descriere
Apare atunci cnd se modific proprietatea AutoSize a
controlului.
Apare atunci cnd se modific proprietatea BackColor a
controlului.
Apare atunci cnd se modific proprietatea BackgroundImage a
controlului.

BackgroundImageLayoutChanged

Apare atunci cnd se modific proprietatea


BackgroundImageLayout a controlului.

Click

Apare atunci cnd utilizatorul d click pe control. Acest


eveniment se situeaz pe un nivel logic mai nalt dect
evenimentul MouseClick i poate fi declanat de ctre alte
aciuni dect un click de mouse (apsarea tastei Enter sau un
shortcut).
Apare atunci cnd se modific proprietatea ContextMenu a
controlului.
Apare atunci cnd se modific proprietatea ContextMenuStrip a
controlului.

ContextMenuChanged
ContextMenuStripChanged
ControlAdded

Apare atunci cnd este adugat un nou control la colecia de


controale copil coninute de controlul curent.

ControlRemoved

Apare atunci cnd un control este ters din colecia de


controale copil coninute de controlul curent.

CursorChanged

Apare atunci cnd se modific proprietatea Cursor a


controlului.
Apare atunci cnd se modific proprietatea Dock a controlului.
Apare atunci cnd utilizatorul d dublu-click pe control.
Apare atunci cnd utilizatorul elibereaz ceva pe control n
urma unei operaii drag-and-drop. Acest eveniment ar trebui s
prelucreze informaia lsat ntr-un mod corespunztor.

DockChanged
DoubleClick
DragDrop

DragEnter

Apare atunci cnd utilizatorul trage ceva deasupra controlului


ntr-o operaie drag-and-drop.

109

Medii i Tehnologii de Programare curs

DragLeave

Apare atunci cnd utilizatorul prsete suprafaa controlului n


cursul operaiei drag-and-drop.

DragOver

Apare atunci cnd utilizatorul a tras ceva deasupra controlului


ntr-o operaie drag-and-drop. Acest eveniment se declaneaz
n mod repetat pn cnd utilizatorul prsete suprafaa
controlului, elibereaz ceva pe control sau anuleaz operaia.

EnabledChanged

Apare atunci cnd se modific proprietatea Enabled a


controlului.
Apare atunci cnd controlul este selectat. Acest eveniment se
declaneaz naintea evenimentului GotFocus.

Enter
FontChanged
ForeColorChanged
GiveFeedback
GotFocus

Apare atunci cnd controlul primete focalizarea. Acest


eveniment se declaneaz dup evenimentul Enter. n general
este preferat evenimentul Enter.

HelpRequested

Apare atunci cnd utilizatorul cere ajutor pentru control. De


exemplu, dac utilizatorul selecteaz un control TextBox i
apas F1, controlul TextBox declaneaz acest eveniment.

Invalidated
KeyDown

Apare atunci cnd o parte a controlului este invalidat.


Apare atunci cnd utilizatorul apas o tast atunci cnd
controlul are focalizarea.

KeyPress

Apare atunci cnd utilizatorul apas i elibereaz o tast atunci


cnd controlul are focalizarea.

KeyUp

Apare atunci cnd utilizatorul elibereaz o tast atunci cnd


controlul are focalizarea.

Layout

Apare atunci cnd controlul trebuie s i aranjeze controalele


copil. Acest eveniment apare nainte de evenimentele Resize i
SizeChanged i este preferat pentru aranjarea controalelor
copil.
Apare atunci cnd controlul pierde focalizarea. Aceste
eveniment se declaneaz naintea evenimentului LostFocus.

Leave
LocationChanged

LostFocus

MarginChanged
MouseCaptureChanged
MouseClick
MouseDoubleClick

110

Apare atunci cnd se modific proprietatea Font a controlului.


Apare atunci cnd se modific proprietatea ForeColor a
controlului.
Apare n timpul unei operaii drag-and-drop pentru a permite
controlului surs s ntreprind anumite aciuni.

Apare atunci cnd se modific proprietatea Location a


controlului. Acest eveniment se declaneaz dup evenimentul
Move.
Apare atunci cnd controlul pierde focalizarea. Acest eveniment
se declaneaz dup evenimentul Leave. n general, este preferat
evenimentul Leave.
Apare atunci cnd se modific proprietatea Margin a
controlului.
Apare atunci cnd controlul primete sau pierde captarea
mouse-ului.
Apare atunci cnd utilizatorul d click pe control.
Apare atunci cnd utilizatorul d dublu-click pe control.

MouseDown

Apare atunci cnd utilizatorul apas un buton de mouse


deasupra controlului.

MouseEnter
MouseHover
MouseLeave
MouseMove
MouseUp

Apare atunci cnd mouse-ul intr pe suprafaa controlului.


Apare atunci cnd mouse-ul este deasupra controlului.
Apare atunci cnd mouse-ul prsete controlul.
Apare atunci cnd mouse-ul se mic deasupra controlului.
Apare atunci cnd utilizatorul elibereaz un buton de mouse
deasupra controlului.

Controale

MouseWheel

Apare atunci cnd utilizatorul nvrte rotia mouse-ului n timp


ce timp controlul are focalizarea.
Apare atunci cnd controlul este mutat. Aceste eveniment se
declaneaz naintea evenimentului LocationChanged.

Move
PaddingChanged

Apare atunci cnd se modific proprietatea Padding a


controlului.
Apare atunci cnd controlul trebuie s se redeseneze. n mod
normal, programul deseneaz controlul n timpul acestui
eveniment.

Paint

ParentChanged

Apare atunci cnd se modific proprietatea Parent a


controlului.
Apare atunci cnd se modific ceva n timpul unei operaii
drag-and-drop astfel nct controlul surs poate decide
modificarea sau anularea operaiei.

QueryContinueDrag

RegionChanged

Apare atunci cnd se modific proprietatea Region a


controlului.
Apare n timp ce se redimensioneaz controlul. Acest
eveniment se declaneaz dup evenimentul Layout, ns
nainte de evenimentul SizeChanged.
Apare n timp ce se redimensioneaz controlul. Acest
eveniment se declaneaz dup evenimentele Layout i Move.

Resize

SizeChanged
SystemColorsChanged

Apare atunci cnd se modific culorile sistem. De exemplu,


poate dorii s desenai ceva folosind aceeai culoare ca cea
utilizat sistemul de operare. Dac un utilizator modific o
anumit culoare sistem, putei utiliza acest eveniment pentru
actualizarea aplicaiei.
Apare atunci cnd se modific proprietatea TabIndex a
controlului.
Apare atunci cnd se modific proprietatea TabStop a
controlului.
Apare atunci cnd se modific proprietatea Text a controlului.
Apare atunci cnd controlul a terminat cu succes validarea
propriilor date.

TabIndexChanged
TabStopChanged
TextChanged
Validated
Validating
VisibleChanged

Apare atunci cnd controlul ar trebui s i valideze datele.


Apare atunci cnd se modific proprietatea Visible a
controlului.
Tabelul 5.11. Evenimente specifice clasei Control

Secvene de evenimente
n unele situaii sunt generate o serie de evenimente care apar ntr-o anumit ordine.

Evenimente de mouse
Atunci cnd dai click pe un control, apar urmtoarele evenimente n ordinea indicat. Prima
instan a evenimentului MouseMove poate aprea de oricte ori micai mouse-ul ct timp
butonul de mouse este apsat. Evenimentul final MouseMove apare indiferent dac micai
mouse-ul sau nu.
MouseDown
[MouseMove]
Click
MouseClick
MouseUp

111

Medii i Tehnologii de Programare curs

MouseCaptureChanged
MouseMove

Atunci cnd dai dublu-click pe un control, apar urmtoarele evenimente n ordinea indicat:
MouseDown
[MouseMove]
Click
MouseClick
MouseUp
MouseCaptureChanged
MouseMove
MouseDown
DoubleClick
MouseDoubleClick
MouseUp
MouseCaptureChanged
MouseMove

Evenimente de redimensionare
Atunci cnd redimensionai un control, apar urmtoarele evenimente n ordinea indicat.
Aceste evenimente sunt repetate att timp ct redimensionai controlul.
Layout
Resize
SizeChanged

Formularele furnizeaz de asemenea evenimentele ResizeBegin i ResizeEnd care apar


nainte, respectiv dup celelalte evenimente specifice redimensionrii.

Evenimente de mutare
Atunci cnd mutai un control, apar urmtoarele evenimente n ordinea indicat. Aceste
evenimente sunt repetate att timp ct mutai controlul.
Move
LocationChanged

Formularele furnizeaz de asemenea evenimentele ResizeBegin i ResizeEnd care apar


nainte, respectiv dup celelalte evenimente specifice mutrii.

5.3. Controale Windows


Controalele reprezint o parte extrem de important a oricrei aplicaii interactive. Acestea
ofer informaii utilizatorului (controalele Label, ToolTip, TreeView, PictureBox etc.) i organizeaz informaia astfel nct aceasta s fie mai uor de perceput (controalele GroupBox,
Panel, TabControl etc.). Ele permit utilizatorului s introduc date (controalele TextBox,
RichTextBox, ComboBox, MonthCalendar etc.), s selecteze opiuni (controalele
RadioButton, CheckBox, ListBox etc.), s controleze aplicaia (controalele Button, MenuStrip,
ContextMenuStrip etc.) i s interacioneze cu obiecte din afara aplicaiei (componentele
OpenFileDialog, SaveFileDialog, PrintDocument, PrintPreviewDialog etc.). Unele controale i
componente ofer suport pentru alte controale (componentele ContextMenuStrip,
ErrorProvider, ImageList etc.).

112

Controale

5.3.1. Scurt trecere n revist a controalelor


Tabelul 5.12 descrie succint controalele standard oferite de Visual C# .NET.
Control
Pointer
BackgroundWorker
BindingNavigator
BindingSource
Button
CheckBox
CheckedListBox
ColorDialog
ComboBox
ContextMenuStrip
DataGridView
DataSet

DateTimePicker
DirectoryEntry
DirectorySearcher
DomainUpDown
ErrorProvider
EventLog
FileSystemWatcher
FlowLayoutPanel
FolderBrowserDialog
FontDialog
GroupBox
HelpProvider
HScrollBar
ImageList

Label
LinkLabel
ListBox

ListView

Descriere
Acesta este instrumentul de selecie, nu un control.
Execut un task n mod asincron i notific programul principal cnd acesta sa terminat.
Ofer o interfa utilizator pentru navigarea printr-o surs de date (butoane
pentru parcurgerea nregistrrilor, butoane de adugare, tergere .a.m.d.).
ncapsuleaz sursa de date a unui formular i pune la dispoziie metode
pentru navigarea prin date.
Un buton simplu. Cnd un utilizator d click pe el, programul poate efectua
unele aciuni.
O caset pe care utilizatorul o poate bifa sau debifa.
O list de elemente cu casete de bifare pe care utilizatorul le poate bifa sau
debifa.
Permite utilizatorului selectarea unei culori.
O caset text cu o list sau list derulant ataat pe care utilizatorul o poate
folosi pentru introducerea sau selectarea unei valori text.
Un meniu care apare atunci cnd utilizatorul d click dreapta pe un control.
Un control tabelar care permite afiarea unui volum mare de date complexe.
Stocheaz n memorie date avnd proprieti similare unei baze de date
relaionale. Conine obiecte care reprezint tabele care conin nregistrri
(rows) i cmpuri (columns), i poate reprezenta multe concepte ale bazelor
de date, cum ar fi indeci i relaii de tip foreign key.
Permite utilizatorului selectarea n mai multe moduri a unei date
calendaristice i a orei.
Reprezint un nod ntr-o ierarhie de tip Active Directory.
Efectueaz cutri ntr-o ierarhie de tip Active Directory.
Permite utilizatorului derularea unei liste de opiuni prin click pe butoanele
sgeat sus i sgeat jos.
Permite afiarea unui indicator de eroare n dreptul unui control asociat n
cazul apariiei unei erori (de exemplu, validarea unor date).
Ofer acces la jurnalul de evenimente Windows.
Notific aplicaia despre modificri asupra unui director sau fiier.
Afieaz controalele pe care le conine pe rnduri i coloane.
Afiarea unui dialog care permite utilizatorului selectarea unui director.
Afiarea unui dialog care permite utilizatorului s specifice caracteristicile unui
font.
Grupeaz, pentru mai mult claritate, controale aflate n legtur.
Afieaz help pentru controalele care au setat aa ceva, dac utilizatorul
selecteaz controlul i apas F1.
Afieaz o bar de derulare orizontal.
Conine o serie de imagini pe care alte controale le pot utiliza. De exemplu,
imaginile pe care le afieaz un TabControl pe tab-urile proprii sunt stocate
ntr-un control ImageList asociat. Putei extrage i prin cod imagini dintr-un
astfel de control.
Afieaz text pe care utilizatorul nu l poate modifica sau selecta prin
intermediul interfeei grafice n timpul rulrii.
Afieaz o etichet care poate conine hyperlink-uri. Atunci cnd utilizatorul
d click pe un hyperlink, programul poate efectual unele aciuni.
Afieaz o list de elemente text pe care utilizatorul le poate selecta. n
funcie de setrile controlului, utilizatorul poate selecta unul sau mai multe
elemente.
Afieaz o list de elemente ntr-unul din cele patru moduri posibile de

113

Medii i Tehnologii de Programare curs

MaskedTextBox
MenuStrip
MessageQueue
MonthCalendar
NotifyIcon
NumericUpDown
OpenFileDialog
PageSetupDialog
Panel

PerformanceCounter
PictureBox
PrintDialog
PrintDocument
PrintPreviewControl
PrintPreviewDialog
Process
ProgressBar
PropertyGrid
RadioButton

RichTextBox

SaveFileDialog
SerialPort
ServiceController
SplitContainer

StatusStrip
TabControl

TableLayoutPanel

114

vizualizare: LargeIcon, SmallIcon, List, and Details.


O caset text care impune ca textul introdus de utilizator s corespund unui
anumit format (numr de telefon, adres IP etc.).
Reprezint meniurile principale, sub-meniurile i elementele de meniu afiate
pe un formular.
Ofer acces la queue pe un server de Message Queuing.
Afieaz un calendar care permite utilizatorului s selecteze o dat
calendaristic.
Specific o component care afieaz o pictogram n system tray.
Permite utilizatorului modificarea unui numr prin click pe butoanele sgeat
sus i sgeat jos.
Afieaz un dialog care permite utilizatorului selectarea unui fiier pentru
deschidere.
Afieaz un dialog care permite utilizatorului s specifice proprietile pentru
paginile ce urmeaz a fi tiprite.
Control container. Utiliznd proprietile Anchor i Dock ale controlului, putei
face ca controlul s se redimensioneze singur astfel nct controalele copil s
se redimensioneze de asemenea. Controlul mai ofer automat bare de
derulare.
Ofer acces la Windows performance counter.
Afieaz o imagine. Ofer de asemenea o suprafa de desenare foarte util.
Afieaz un dialog standard de tiprire. Utilizatorul poate selecta imprimanta,
paginile care s fie tiprite i setri ale imprimantei.
Reprezint ieirea care s fie trimis la imprimant. Un program poate utiliza
acest obiect pentru a tipri i afia previzualizri ale documentului de tiprit.
Afieaz pe una dintre ferestrele aplicaiei o previzualizare a ceea ce urmeaz
a fi tiprit.
Afieaz o previzualizare a ceea ce urmeaz a fi tiprit ntr-o fereastr
standard.
Permite programului s interacioneze cu procesele, s le porneasc i s le
opreasc.
Indic ntr-un mod vizual progresul unei operaii de durat.
Afieaz informaii despre proprietile unui obiect ntr-un format similar celui
afiat n fereastra de proprieti din Visual Studio.
Permite alegerea unei singure opiuni dintr-un grup de controale de acelai
tip. Atunci cnd un utilizator selecteaz un RadioButton, Visual C#
deselecteaz toate celelalte controale RadioButton din cadrul aceluiai grup.
Grupurile sunt definite n controale container diferite.
Reprezint un control n care utilizatorul poate introduce i edita text.
Controlul ofer formatri mult mai avansate dect cele oferite de un control
TextBox, putnd afia fiiere n format RTF. Controlul permite formatarea
textului la nivel de caractere i paragrafe (alinieri, bullets etc.).
Afieaz un dialog care permite utilizatorului selectarea numelui unui fiier n
care programul s salveze date.
Reprezint un port serial i pune la dispoziie metode pentru controlul, citirea
i scrierea acestuia.
Reprezint un serviciu Windows care permite manipularea serviciilor.
Control container care permite utilizatorului s mute o bar de desprire
vertical sau orizontal care mparte spaiul disponibil ntre dou zone din
cadrul controlului.
Ofer o zon (de obicei n partea de jos a ferestrei) unde aplicaia poate afia
mesaje de stare, pictograme i ali indicatori ai strii aplicaiei.
Control container care afieaz o serie de tab-uri ataate paginilor care au
propriul lor coninut. Utilizatorul d click pe un tab pentru a putea vizualiza
coninutul paginii asociate.
Control container care afieaz controalele pe care le conine n form

Controale

TextBox
Timer
ToolStrip
ToolStripContainer

ToolTip
TrackBar
TreeView
VScrollBar
WebBrowser

tabelar.
Afieaz text pe care utilizatorul l poate modifica n timpul rulrii.
Implementeaz un temporizator care declaneaz un eveniment la intervale
de timp definite de utilizator.
Ofer un container pentru obiecte Windows toolbar (controale Button, Label,
ComboBox, TextBox, ProgressBar etc.).
Ofer panouri pe fiecare parte a ferestrei (acestea pot conine controale de
tip ToolStrip, MenuStrip i StatusStrip) i un panou central (acesta poate
conine orice controale).
Afieaz un text ajuttor dac utilizatorul poziioneaz cursorul de mouse
deasupra controlului asociat.
Permite utilizatorului s deplaseze un cursor de-a lungul unei bare pentru a
selecta o valoare numeric.
Afieaz date ierarhice ntr-o form grafic, arborescent.
Afieaz o bar de derulare vertical.
Permite navigarea prin pagini web din cadrul ferestrei. Controlul afieaz
rezultatele exact ca browserul Internet Explorer. O posibil utilizare a acestui
control este afiarea de help n format web.

Tabelul 5.12. Prezentarea controalelor i componentelor standard oferite de Visual C# .NET.

Chiar dac avei la ndemn attea unelte puternice, nu ntotdeauna este uor s alegei cel
mai potrivit control pentru o anumit situaie. Pentru simplificarea codului de tratare a
erorilor, ar trebui s alegei cel mai restrictiv control care poate s ndeplineasc sarcina
dorit, deoarece cu ct controalele sunt mai restrictive, cu att utilizatorul are mai puine
opiuni de introducere a datelor invalide.

115

Medii i Tehnologii de Programare curs

6. Formulare
Clasa Form din Visual C# este derivat indirect din clasa Control. Lanul complet de
moteniri este urmtorul: Control ScrollableControl ContainerControl Form. Un
formular motenete proprietile, metodele i evenimentele definite de clasa Control, cu
excepia cazului n care acestea sunt suprancrcate. Din multe puncte de vedere, un
formular este doar un alt tip de control.

6.1. Transparen
Obiectul Form ofer, suplimentar fa de obiectul Control, o serie de proprieti pe care le
putei folosi pentru a face o fereastr total sau parial transparent. Proprietatea Opacity
determin opacitatea unei ferestre. n modul design, fereastra de proprieti arat valoarea
acestei proprieti sub form de procentaj, unde 100% semnific faptul c formularul este
complet opac, iar 0% c fereastra este complet transparent. n timpul rulrii trebuie s
tratai valoarea proprietii Opacity ca numr n virgul mobil cu valori ntre 0.0 (complet
transparent) i 1.0 (complet opac).
O aplicaie poate utiliza pentru Opacity valori mai mici de 100% pentru a permite
utilizatorului s vad ce se ntmpl n spatele ferestrei. De exemplu, putei construi o
fereastr parial transparent pentru implementarea unui dialog de cutare, astfel nct
utilizatorul s poat vedea documentul pe msur ce cutarea avanseaz.
Figura 6.1 prezint un formular cu opacitatea 66%. Putei vedea nc marginile ferestrei,
bara de titlu, meniurile i butoanele, ns putei observa de asemenea fereastra de dedesubt.

Figura 6.1. O fereastr cu opacitate 66% permite vizualizarea ferestrei situate dedesubt.

116

Controale

Dac opacitatea este mai mare de 0%, fereastra se comport normal, cu excepia aspectului
imaterial al acesteia, utilizatorii putnd interaciona cu aceasta ca i cu orice alt fereastr.
Dac opacitatea este 0%, fereastra este complet transparent, iar utilizatorul poate interaciona cu ea numai prin intermediul tastaturii (schimbarea focalizrii controalelor cu tasta
TAB, acionarea comenzilor prin combinaii de taste). n orice caz, fereastra nu va detecta
click-urile de mouse.
Dac opacitatea este 1%, fereastra rmne invizibil n continuare, ns recunoate clickurile de mouse.
O a doua proprietate care poate determina transparena unei ferestre este TransparencyKey.
Aceast proprietate reprezint o culoare care indic mediului care parte a ferestrei trebuie
s fie complet transparent. La afiarea ferestrei, suprafeele care au ca fundal aceast
culoare nu vor fi desenate.
Figura 6.2 prezint o fereastr cu proprietatea TransparencyKey setat la culoarea de fundal a
ferestrei. Att fereastra ct i eticheta cu textul Spaiu gol au acelai fundal, astfel c vor fi
transparente la afiare. Evenimentul Paint al ferestrei deseneaz o elips n interiorul
ferestrei.

Figura 6.2. Proprietatea TransparencyKey a unei ferestre permite crearea unor zone complet transparente.

Nu numai c pixelii care nu sunt desenai sunt transpareni, ci de asemenea fereastra nu


rspunde la evenimentele de mouse pe care le primete. Dac utilizatorul d click pe o zon
transparent de pe fereastr, cursorul de mouse trece prin fereastr la aplicaia de dedesubt.
TransparencyKey se aplic att suprafeei ferestrei ct i controalelor de pe fereastr. Aceasta
poate duce la efecte ciudate. De exemplu, dac setai TransparencyKey la culoarea

SystemColors.Control, fereastra, controalele, pn i fundalul marginilor i butoanele de


maximizare, minimizare i nchidere a ferestrei vor disprea. Dac dai click pe poriunile
netransparente ale butoanelor, acoperite de text, butoanele vor funciona normal.
Cea mai frecvent utilizare a proprietii TransparencyKey este aceea de creare a unor
ferestre de diverse forme. Setai pentru formular proprietatea FormBorderStyle la None
pentru ndeprtarea marginilor, a barei de titlu i a butoanelor sistem. Setai apoi
proprietile BackColor i TransparencyKey la o culoare care nu dorii s fie afiat pe
formular. Desenai apoi cu alt culoare forma pe care dorii s o aib formularul.

117

Medii i Tehnologii de Programare curs

Figura 6.3 prezint o fereastr de forma unui smiley. Handler-ul evenimentului Paint al
ferestrei deseneaz imaginea dintr-un fiier bitmap. n acest fel putei construi de exemplu
splash screen-uri1 sau alte ferestre dialog interesante.

Figura 6.3. Proprietatea TransparencyKey permite crearea unor ferestre de diverse forme, precum aceasta.

Aceast fereastr nu prezint nici margini, nici bar de titlu i nici butoane sistem, astfel c
utilizatorul nu o poate muta, redimensiona, maximiza sau nchide (se seteaz proprietatea
FormBorderStyle a formularului la None). Pentru utilizarea acestei ferestre ca splash screen,
adugai un control Timer pentru a face ca fereastra s dispar dup cteva secunde. Pentru
utilizarea ferestrei ca o fereastr obinuit, adugai pe suprafaa ei un buton de nchidere.
Dac utilizai mpreun proprietile Opacity i TransparencyKey, pixelii care corespund cu
TransparencyKey nu sunt afiai, iar ceilali pixeli sunt afiai corespunztor cu valoarea setat
de proprietatea Opacity.

6.2. Aplicaii SDI i MDI


O aplicaie uni-document (SDI Single Document Interface) afieaz numai un singur
document n fiecare fereastr (Figura 6.4). Un exemplu de aplicaie SDI este Microsoft Paint,
care poate gestiona numai o singur imagine la un moment dat. Unele aplicaii SDI pot afia
mai mult de un singur document la un moment dat, ns fiecare ntr-o fereastr separat.
O aplicaie multi-document (MDI Multiple Document Interface) poate afia la un moment
dat mai multe documente n ferestre separate (ferestre copil), acestea fiind cuprinse ntr-o
fereastr mai mare numit fereastr printe (Figura 6.5).

O fereastr de tip splash screen este afiat n timp ce o aplicaie iniializeaz sau ncarc datele necesare,
pregtindu-se de lucru. Aplicaia va nchide fereastra splash screen dup ce iniializarea este complet, sau dup
trecerea unui numr de secunde.

118

Controale

Figura 6.4. O aplicaie SDI afieaz documente separate n ferestre separate

Aplicaiile MDI ofer de obicei unelte pentru gestionarea ferestrelor copil pe care acestea le
conin. Aceste unelte permit utilizatorului minimizarea ferestrelor copil, aranjarea acestora
n cadrul ferestrei printe, .a.m.d. Visual Studio este o aplicaie MDI deoarece poate afia n
cadrul ferestrei principale mai multe ferestre copil (designere de formulare, editoare de cod,
editoare de bitmap, .a.m.d.).

Figura 6.5. O aplicaie MDI afieaz documentele n ferestre copil coninute de fereastra printe

6.2.1. Caracteristici ale aplicaiilor MDI


O fereastr MDI container ofer cteva funcii legate de ferestrele copil. Fereastra container
cuprinde ferestrele i le ine grupate astfel nct acestea pot fi uor de gsit. Dac mutai o

119

Medii i Tehnologii de Programare curs

fereastr copil astfel nct acesta s depeasc marginile ferestrei printe, fereastra printe
va afia n mod automat bare de derulare pentru a putea vizualiza fereastra copil.
Programul va afia o pictogram n taskbar i Task Manager pentru fereastra printe, ns nu
i pentru ferestrele copil. Dac minimizai containerul MDI, toate ferestrele pe care le
conine vor fi ascunse mpreun cu acesta. Dac minimizai ns o fereastr copil, pictograma
acesteia va fi afiat n interiorul containerului, iar nu separat n taskbar. n cazul n care
maximizai o fereastr copil MDI, aceasta va umple suprafaa ferestrei printe.
Un container MDI ofer de asemenea unele metode pentru aranjarea ferestrelor copil. Codul
de mai jos ilustreaz modul n care, din cadrul containerului MDI, pot fi aranjate ferestrele
copil n diverse configuraii:
private void CascadeToolStripMenuItem_Click(object sender, EventArgs e)
{
LayoutMdi(MdiLayout.Cascade);
}
private void TileVerticalToolStripMenuItem_Click(object sender, EventArgs e)
{
LayoutMdi(MdiLayout.TileVertical);
}
private void TileHorizontalToolStripMenuItem_Click(object sender, EventArgs e)
{
LayoutMdi(MdiLayout.TileHorizontal);
}
private void ArrangeIconsToolStripMenuItem_Click(object sender, EventArgs e)
{
LayoutMdi(MdiLayout.ArrangeIcons);
}

Alte comenzi utile pe care le putei aduga unei aplicaii MDI sunt: Minimize All, Restore All,
Maximize All i Close All. Putei implementa aceste comenzi prin parcurgerea coleciei
MdiChildren asociate containerului MDI, precum se poate observa n continuare:
private void CloseAllToolStripMenuItem_Click(object sender, EventArgs e)
{
foreach (Form childForm in MdiChildren)
{
childForm.Close();
}
}
private void minimizeAllToolStripMenuItem_Click(object sender, EventArgs e)
{
foreach (Form childForm in MdiChildren)
{
childForm.WindowState = FormWindowState.Minimized;
}
}
private void maximizeAllToolStripMenuItem_Click(object sender, EventArgs e)
{
foreach (Form childForm in MdiChildren)
{
childForm.WindowState = FormWindowState.Maximized;
}
}
private void restoreAllToolStripMenuItem_Click(object sender, EventArgs e)
{
foreach (Form childForm in MdiChildren)
{
childForm.WindowState = FormWindowState.Normal;
}
}

120

Controale

Multe aplicaii MDI includ un meniu Windows care afieaz o list a ferestrelor copil
deschise. Apsarea uneia dintre aceste comenzi de meniu permite mutarea ferestrei copil
deasupra tuturor celorlalte ferestre coninute de containerul MDI.
Construirea unei liste de ferestre copil este o sarcin uoar n Visual C#. Selectai controlul
principal MenuStrip, iar n fereastra de proprieti a acestuia setai proprietatea
MdiWindowListItem la meniul care dorii s conin lista de ferestre copil. Dup fiecare
operaie de deschidere sau nchiderea unei ferestre copil, Visual C# va actualiza automat
aceast list.
Figura 6.6 arat un meniu care afieaz o list de ferestre copil MDI. Fereastra cu titlul
Program.cs are focalizarea, astfel c lista afieaz o bif n dreptul comenzii de meniu
asociate ferestrei.

Figura 6.6. Proprietatea MdiWindowListItem asociat controlului MenuStrip determin care element de meniu
va afia lista cu ferestrele copil MDI.

Majoritatea aplicaiilor Visual C# utilizeaz SDI, iar la crearea unei noi aplicaii, interfaa
acesteia va fi implicit SDI. Pentru a avea o aplicaie MDI, creai nti o aplicaie nou, apoi
setai proprietatea IsMdiContainer a formularului de start pe true. n Form Designer, acest
formular i va schimba nfiarea, astfel nct va fi evident c este un formular printe MDI.
Ca metod alternativ putei selecta din meniul Project comanda Add Windows Form. n
fereastra dialog ce se va deschide selectai MDI Parent Form i dai ferestrei un nume
rezonabil. Visual C# va aduga un nou formular printe MDI avnd un control meniu care va
include meniuri standard (File, Edit, View, .a.m.d.) i o bar de unelte cu unelte standard
(New, Open, Save, .a.m.d.).
n faza de design, un formular copil MDI are aceeai nfiare cu a unui formular standard.
Pentru a face ca formularul copil s fie afiat n interiorul unui container MDI, trebuie s i
setai acestuia n timpul rulrii proprietatea MdiParent la containerul MDI.
Putei vedea mai jos secvenele de cod adugate automat la comanda de deschidere a unei
noi ferestre copil din fereastra printe MDI. Ferestrele copil nou create vor fi automat afiate
n interiorul containerului MDI i vor fi adugate n lista de ferestre copil deschise.
private void OpenFile(object sender, EventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.InitialDirectory = Application.StartupPath;
openFileDialog.Filter = "Text Files (*.txt)|*.txt|All Files (*.*)|*.*";

121

Medii i Tehnologii de Programare curs

if (openFileDialog.ShowDialog(this) == DialogResult.OK)
{
string FileName = openFileDialog.FileName;
// Aici adaugarea codului pentru afisarea continutului fisierului
// ...
}
}

6.2.2. Evenimente MDI


Evenimentele pentru o fereastr copil MDI apar n general naintea evenimentelor
corespunztoare ale ferestrei printe. De exemplu, dac ncercai s nchidei o fereastr
MDI, toate ferestrele copil vor recepiona evenimentele FormClosing naintea ferestrei
printe. n continuare, ferestrele copil vor recepiona evenimentele FormClosed, iar numai
dup aceea fereastra printe va recepiona evenimentul FormClosed.
Dac handlerul unui eveniment FormClosing seteaz parametrul e.Cancel pe true, operaia
de nchidere a ferestrei este anulat iar fereastra va rmne deschis mai departe. Un
formular poate utiliza acest mecanism pentru garantarea consistenei datelor proprii i a
salvrii corecte a acestora.

6.2.3. MDI Versus SDI


Att aplicaiile MDI ct i cele SDI au fiecare avantajele lor. ntr-o aplicaie SDI, construirea i
nelegerea meniurilor este simpl. Un meniu corespunde numai unui formular, neexistnd
nicio modificare n meniuri odat cu deschiderea sau nchiderea altor ferestre.
Aplicaiile SDI se preteaz situaiilor particulare n care programul opereaz numai cu un
fiier la un moment dat. Exemple de aplicaii SDI sunt: Notepad, Microsoft Paint i alte
aplicaii similare care permit utilizatorului lucrul asupra unui singur fiier. De regul, aceste
programe nu sunt mari consumatoare de resurse, astfel c utilizatorul poate s deschid alte
instane ale acestora n cazul n care dorete s lucreze cu mai multe fiiere odat.
Aplicaiile MDI ajut utilizatorul s afieze la un moment dat mai multe fiiere care au
legtur unele cu altele fr s ncarce inutil desktop-ul. De exemplu, Visual Studio utilizeaz
o interfa MDI pentru a permite utilizatorilor vizualizarea mpreun a tuturor fiierelor
dintr-un proiect. Afiarea n ferestre separate a acestora ar aglomera foarte mult desktop-i
taskbar-ul, i ar face mai dificil pentru utilizator lucrul cu toate aceste documente (cum ar fi,
de exemplu, aplicaia GIMP).
Putei construi de asemenea aplicaii hibride care s afieze cteva containere MDI, fiecare
coninnd un numr de ferestre copil. n practic, acest gen de aplicaii hibride sunt adesea
greoaie i prost concepute. n general ar fi mai simplu de construit aplicaii standard MDI.
Putei s evitai utilizarea de ferestre multiple prin folosirea unor controale care ajut la
afiarea unei cantiti mari de informaii pe un singur formular: ComboBox, ListBox,
TreeView, SplitContainer i alte controale care afieaz cantiti mari de date ntr-un spaiu
limitat, oferind la nevoie bare de derulare.
Controlul TabControl v permite afiarea de date pe pagini multiple, toate situate pe un
singur formular. Utilizarea acestui tip de controale n interiorul unui container MDI duce la
crearea unor aplicaii robuste care permit utilizatorilor s gestioneze cu uurin cantiti
mari de informaii.

122

Controale

6.3. Ferestre Dialog


Utilizarea unui formular ca dialog este relativ simpl. Creai formularul, adugai controalele
de care avei nevoie, apoi unul sau mai multe butoane care s permit utilizatorului
prsirea dialogului. Multe ferestre dialog utilizeaz butoanele OK i Cancel, ns putei
utiliza i alte butoane, cum ar fi Yes, No, Retry .a.
Setai pentru formularul n cauz proprietatea AcceptButton la butonul care dorii s fie
apelat la apsarea tastei Enter, iar proprietatea CancelButton la butonul care dorii s fie
apelat la apsarea tastei Esc.
Proprietatea DialogResult a formularului indic valoarea returnat de dialog. Dac fereastra
dialog este apelat prin metoda ShowDialog(), aceasta va returna o valoare DialogResult.
Metoda ShowDialog() are ca rezultat afiarea modal a ferestrei dialog. O fereastr modal
menine focalizarea asupra ferestrei, astfel nct utilizatorii nu pot s interacioneze cu alte
componente ale aplicaiei ct timp fereastra modal este deschis.
Secvena de cod de mai jos ilustreaz modul n care programul poate s afieze un dialog i
s reacioneze la rezultatul ntors de acesta.
private void button1_Click(object sender, EventArgs e)
{
DialogAngajat dlg = new DialogAngajat();
if (dlg.ShowDialog() == DialogResult.OK)
MessageBox.Show(dlg.txtNume.Text + " " + dlg.txtPrenume.Text);
else
MessageBox.Show("Anulat");
}

Dac utilizatorul apas butonul Cancel sau nchide formularul din meniul sistem, atunci
formularul seteaz automat proprietatea DialogResult la Cancel i se nchide. Dac
utilizatorul apas alt buton, handlerul de eveniment va seta DialogResult la o valoare
corespunztoare. Setarea acestei valori va duce la nchiderea automat a formularului.

123

Medii i Tehnologii de Programare curs

7. Grafic n Visual C# .NET

7.1. Noiuni de baz despre desenare


Visual C# .NET ofer o gam larg de obiecte pentru desenare i pentru controlul atributelor
de desenare. Obiectul Graphics pune la dispoziie metode care permit desenarea i umplerea
de dreptunghiuri, elipse, poligoane, curbe i alte forme. Obiectele Pen i Brush determin
modul de desenare a liniilor (linie continu, ntrerupt sau punctat), respectiv modul de
umplere a unor suprafee (culoare uniform, haur sau gradient de culoare).

7.1.1. O privire de ansamblu asupra desenrii


Ori de cte ori dorii s desenai ceva n Visual C#, trebuie s utilizai un obiect Graphics.
Acest obiect reprezint suprafaa pe care urmeaz s desenai, fie c este operai cu un
formular, un control PictureBox sau o component PrintDocument. Uneori trebuie s creai
un obiect Graphics, alteori acesta v este oferit automat (de exemplu n handler-ul
evenimentului Paint).
Graphics Device Interface+ (GDI+), sau versiunea .NET a rutinelor de desenare GDI, utilizeaz dou clase, Pen i Brush, pentru a determina aspectul a ceea ce ele deseneaz. Un obiect Pen
determin modul n care sunt desenate liniile.
Un obiect Pen seteaz culoarea unei linii, grosimea acesteia, stilul de desenare, terminaiile
capetelor liniei i alte proprieti. Obiectul Pen aplic aceste caracteristici tuturor liniilor
desenate de o rutin GDI+. De exemplu, metoda DrawPolygon() deseneaz o secven de linii,
iar parametrul Pen determin modul de desenare al acestora.
Un obiect Brush determin modul de umplere a suprafeelor. Un obiect Brush seteaz
culoarea de umplere a suprafeei, haura aplicat (un ablon format din linii, puncte, sau alte
forme), gradientul de culoare (trecere gradat de la o culoare la alta) i textura (compus
prin alturarea repetat a unei imagini pe suprafaa dat). Obiectul Brush se aplic rutinelor
GDI+ care au ca efect umplerea unor suprafee nchise: FillRectangle(), FillEllipse() i
FillPolygon().
Etapele unei operaii de desenare a unei forme simple sunt urmtoarele:
1. Obinerea unui obiect Graphics.
2. Definirea unui obiect Pen i desenarea cu ajutorul lui.
3. Definirea unui obiect Brush i umplerea cu ajutorul lui a unor suprafee.
De exemplu, handler-ul evenimentului Paint prezentat n urmtoarea secven de cod
ruleaz atunci cnd este nevoie ca formularul s se redeseneze. Parametrul e.Graphics primit
de handler furnizeaz un obiect Graphics cu ajutorul cruia programul poate s deseneze. La
ncheierea execuiei handler-ului, Visual C# copiaz coninutul desenat n acest obiect
Graphics pe acea parte din formular care trebuie redesenat. Handler-ul de eveniment
creeaz un obiect SolidBrush de culoare portocalie (SolidBrush reprezint o clas derivat
din clasa Brush). Programul utilizeaz pensula pentru umplerea cercului nscris n ptratul
avnd colul stnga sus la coordonatele (10, 10), i laturile de 100 de pixeli. n continuare,
codul creeaz un creion caracterizat prin culoare albastr i grosime de 10 pixeli, utilizat
pentru desenarea conturului aceluiai cerc.

124

Grafic n Visual C# .NET

private void Form1_Paint(object sender, PaintEventArgs e)


{
SolidBrush circleBrush = new SolidBrush(Color.Orange);
e.Graphics.FillEllipse(circleBrush, 10, 10, 100, 100);
Pen circlePen = new Pen(Color.Blue, 10);
e.Graphics.DrawEllipse(circlePen, 10, 10, 100, 100);
}

Ori de cte ori formularul este ascuns (chiar i parial) apoi expus iari, minimizat apoi
restaurat, maximizat sau redimensionat handler-ul evenimentului Paint se execut i
redeseneaz cercul (Figura 7.1).

Figura 7.1. Acest program deseneaz unui cerc umplut cu culoare portocalie, avnd conturul de culoare
albastr i 10 pixeli grosime.

Sunt disponibile cteva versiuni suprancrcate ale metodelor de desenare i umplere


asociate unui obiect Graphics. Majoritatea primesc ca parametru un obiect care definete
forma ce urmeaz a fi desenat. De exemplu, metodele FillEllipse() i DrawEllipse() pot
primi ca parametru un obiect Rectangle care definete dreptunghiul n care va fi nscris
elipsa.
Toate operaiile grafice GDI+ se bazeaz pe aceti pai simpli, ns, pornind de la acetia, pot
exista o mulime de variaii. Obiectul Graphics ofer unele proceduri grafice mai exotice
cum ar fi DrawBezier(), care deseneaz o curb Bzier.

7.1.2. Spaii de nume pentru desenare


nainte de a trece la grafica GDI+, vom poposi puin asupra spaiilor de nume care conin
obiecte grafice. Spaiul de nume System.Drawing este importat automat n aplicaiile nou
create, astfel c nu este nevoie s l importai explicit pentru a lucra cu obiecte precum
Graphics, Pen, Brush, .a.m.d. n orice caz, dac dorii s creai abloane personalizate pentru
linii (de exemplu, linie-punct-linie), gradieni de culoare sau fiiere de tip imagine avansate
(JPEG, GIF, TIFF) trebuie s tii ce spaii de nume s importai n aplicaia dumneavoastr.

System.Drawing
Spaiul de nume System.Drawing conine clasele de baz GDI+ i cele mai importante dintre
acestea. Din aceste clase fac parte Graphics, Pen, Brush, Font, FontFamily, Bitmap, Icon i Image.
Tabelul urmtor descrie cele mai utile clase din System.Drawing.
Clas
Graphics

Descriere
Fr ndoial, acesta este cel mai important obiect utilizat la crearea de grafic. Un
obiect Graphics reprezint suprafaa pe care urmeaz s desenai. Aceasta poate fi un
PictureBox, formular, bitmap n memorie, sau altceva. Obiectul Graphics ofer metodele
pentru desenare de linii dreptunghiuri, elipse .a.m.d.

Pen

Aceast clas reprezint caracteristicile de desenare ale unei linii, incluznd culoarea
liniei, grosimea, stilul liniei .a.m.d.

125

Medii i Tehnologii de Programare curs

Pens

Aceast clas pune la dispoziie un mare numr de creioane predefinite de grosime 1 i


diferite culori. De exemplu, putei utiliza Pens.Blue ca i creion albastru standard.

Brush

Aceast clas reprezint modul n care sunt umplute suprafeele nchise. Ea determin
dac suprafaa este umplut cu culoare uniform, haur, ablon grafic etc.

Brushes

Aceast clas pune la dispoziie un mare numr de pensule simple (solid brushes) de
diferite culori. De exemplu, putei utiliza Brushes.Green pentru umplerea unei suprafee
cu culoare verde.
Aceast clas reprezint o pensul simpl, pe care o vei utiliza atunci cnd avei nevoie
s umplei o suprafa cu o culoare uniform.

SolidBrush
Bitmap

Aceast clas reprezint o imagine bitmap definit pixel cu pixel.

Icon
Metafile

Aceast clas reprezint o iconi Windows similar unui bitmap.


Aceast clas reprezint un obiect grafic de tip metafile care conine operaii grafice pe
care un program le poate nregistra, salva sau ncrca ntr-un/dintr-un fiier i pe care l
poate rula mai trziu.
Aceasta este o clas de baz abstract din care sunt derivate Bitmap, Icon i Metafile.
Unele proceduri pot funciona pentru oricare dintre aceste tipuri de obiecte, astfel c
primesc un parametru Image. (Pe scurt, un bitmap este o imagine tipic. Un icon are n
plus transparen i posibil informaii hot-spot, astfel nct poate reprezenta o iconi
asociat unei ferestre sau un pointer de mouse. Un metafile conine instruciuni de
desenare pe care aplicaiile le pot utiliza pentru scalarea lin a unei imagini.)

Image

Font

Aceast clas reprezint un anume font. Ea definete numele fontului, dimensiunea i


stilul (italic, bold etc.).

FontFamily

Aceast clas reprezint un grup de fonturi (typefaces) avnd caracteristici similare.

Region

Aceast clas definete o form creat din dreptunghiuri i ci (paths), pe care o putei
utiliza n diverse scopuri.
Tabelul 7.2. Clase utile din spaiul de nume System.Drawing.

Spaiul de nume System.Drawing definete de asemenea unele structuri care pot fi utilizate n
vederea desenrii. Tabelul urmtor le descrie pe cele mai utile dintre acestea.
Structur
Color

Point
Size
Rectangle

Descriere
Acest obiect definete o culoare prin specificarea culorilor de baz (rou, verde,
albastru) ca valori cuprinse ntre 0 i 255, plus o valoare alpha care indic transparena
culorii. O valoare 0 pentru alpha semnific un obiect complet transparent, iar o valoare
de 255 semnific unul complet opac.
Acest obiect definete coordonatele X i Y ale unui punct.
Acest obiect definete nlimea i limea.
Acest obiect definete un dreptunghi utiliznd Point i Size.
Tabelul 7.3. Structuri din spaiul de nume System.Drawing.

Procedurile GDI+ care deseneaz pe ecranul monitorului, imprimant sau alte obiecte pe
care se poate desena, utilizeaz structurile Point, Size i Rectangle. Acestea stocheaz
coordonatele integrale i dimensiunile figurilor desenate. Spaiul de nume System.Drawing
definete de asemenea clasele PointF, SizeF i RectangleF pentru lucrul cu valori n virgul
mobil.
Clasa Color ofer un mare numr de culori predefinite. De exemplu, Color.PaleGreen
definete o culoare verde deschis. Putei s utilizai aceste culori predefinite n loc s creai
un nou obiect de tip culoare.

System.Drawing.Drawing2D
Spaiul de nume System.Drawing.Drawing2D conine majoritatea celorlalte obiecte de care
avei nevoie pentru elemente mai avansate de grafic 2D. Unele dintre aceste clase rafineaz

126

Grafic n Visual C# .NET

clasele de baz pentru desenare sau definesc valori pentru aceste clase. De exemplu, clasa
HatchBrush reprezint un tip specializat de pensul care umple o suprafa cu o haur.
Tabelul ce urmeaz descrie cteva dintre cele mai utile clase din acest spaiu de nume.
Clas
HatchBrush

Descriere
Aceast clas definete o pensul care umple o suprafa cu o haur. Ea
definete tipul haurii, culoarea acesteia, i o culoare de fundal.

LinearGradientBrush

Aceast clas definete o pensul care umple o suprafa cu un gradient liniar


de culoare. Implicit, modelul de umplere reprezint o trecere treptat de la o
culoare la cealalt de-a lungul unei linii pe care o definii.

Tabelul 7.4. Dou dintre clasele oferite de spaiul de nume System.Drawing.Drawing2D.

System.Drawing.Text
Spaiul de nume System.Drawing.Text conine numai trei clase. Aceste trei clase ofer o
metod de a afla care sunt fonturile instalate pe sistem sau cele instalate pentru o aplicaie.
Tabelul urmtor descrie cele trei clase.
Clas
FontCollection

Descriere
Este clas de baz pentru clasele derivate InstalledFontCollection i
PrivateFontCollection i ofer o metod care returneaz un ir de obiecte
FontFamily.

InstalledFontCollection

Este o clas derivat din clasa FontCollection. Metoda Families a acestei


clase returneaz un ir ce conine obiecte FontFamily care reprezint
fonturile instalate pe sistem.

PrivateFontCollection

Este de asemenea derivat din clasa FontCollection. Obiectele de tipul


acestei clase reprezint fonturi instalate de o aplicaie. Programul poate
utiliza acest obiect pentru a instala fonturi numai pentru uz propriu, nu i
pentru restul sistemului. Aceast clas ofer metode pentru instalarea i
listarea fonturilor aplicaiei.

Tabelul 7.5. Clasele din spaiul de nume System.Drawing.Text

Pentru listarea fonturilor sistemului, un program trebuie s creeze o instan a clasei


InstalledFontCollection i s utilizeze metoda Families() pentru obinerea unui ir de
obiecte de tip FontFamily instalate. Dup aceasta, programul poate parcurge acest ir pentru
listarea fonturilor. Acest lucru poate fi observat n secvena de cod de mai jos:
private void Form1_Load(object sender, EventArgs e)
{
// Obtine colectia de fonturi instalate
InstalledFontCollection installedFonts = new InstalledFontCollection();
// Obtine sirul de familii de fonturi a sistemului
FontFamily[] fontFamilies = installedFonts.Families;
// Afiseaza familiile de fonturi
foreach (FontFamily fontFamily in fontFamilies)
listFonts.Items.Add(fontFamily.Name);
listFonts.SelectedIndex = 0;
}

n Figura 7.6 putei observa rezultatul obinut n urma rulrii codului de mai sus.

127

Medii i Tehnologii de Programare curs

Figura 7.6. Un obiect InstalledFontCollection permite accesarea unui ir de obiecte FontFamily care reprezint
fonturile instalate pe sistem.

Spaiul de nume System.Drawing.Text definete de asemenea enumerarea TextRenderingHint.


Anti-aliasing este un proces care utilizeaz pixeli de diferite nuane pentru a face ca
marginile coluroase i curbele s aib o nfiare mai neted. Putei seta proprietatea
TextRenderingHint a unui obiect de tip Graphics pentru a-i preciza programului dac trebuie
s utilizeze anti-aliasing pentru reprezentarea mai fin a textului.
Figura 7.7 arat rezultatul afirii de text cu i fr anti-aliasing, mult mrit pentru a
evidenia diferena. Putei observa modul n care versiunea care utilizeaz anti-aliasing
folosete diverse tonuri de gri pentru ca textul s apar mai neted.

Figura 7.7. Anti-aliasing (deasupra) are ca efect afiarea mai neted a caracterelor.

Graphics
De fiecare dat cnd desenai n Visual C# .NET, avei nevoie de un obiect Graphics. Un obiect
Graphics reprezint o suprafa de desenare, indiferent c este un formular, un control
PictureBox, Bitmap n memorie, un metafile, sau imprimant.
Clasa Graphics ofer multe metode pentru desenarea de figuri i umplerea de suprafee. Ea
include de asemenea proprieti i metode care modific rezultatele operaiilor grafice. De
exemplu, metodele de transformare v permit operaii de scalare, translatare, i rotire a
elementelor grafice.

128

Grafic n Visual C# .NET

Seciunile ce urmeaz descriu proprieti i metode ale clasei Graphics pentru desenare,
umplere, respectiv de modificare a rezultatelor acestora.

Metode de desenare
Obiectul Graphics ofer o multitudine de metode pentru desenare de linii, dreptunghiuri,
curbe i alte figuri. Tabelul de mai jos descrie o parte dintre aceste metode.
Metod
DrawArc
DrawBezier
DrawBeziers
DrawClosedCurve

Descriere
Deseneaz un arc de elips.
Deseneaz o curb Bzier.
Deseneaz o serie de curbe Bzier.
Deseneaz o curb nchis care unete o serie de puncte, unind punctul final
cu cel iniial.

DrawCurve

Deseneaz o curb care unete o serie de puncte. Este similar cu


DrawClosedCurve, cu excepia c nu unete punctul final cu cel iniial.

DrawEllipse

Deseneaz o elips. Pentru a desena un cerc, desenai o elips la care


nlimea s fie egal cu limea.

DrawIcon
DrawImage

Deseneaz o iconi pe suprafaa de desenare a obiectului Graphics.


Deseneaz un obiect Image pe suprafaa de desenare a obiectului Graphics.
Bitmap reprezint o subclas a clasei Image, astfel c putei utiliza aceast
metod pentru a desena un bitmap.

DrawLine
DrawLines

Deseneaz o linie.
Deseneaz o serie de linii conectate. Dac avei nevoie s desenai o serie de
lini conectate, aceast metod este mult mai rapid dect utilizarea repetat a
metodei DrawLine.
Deseneaz un obiect de tip GraphicsPath.
Deseneaz un sector de elips.
Deseneaz un poligon. Aceast metod este similar cu DrawLines, cu
excepia faptului c unete punctul iniial cu cel final.

DrawPath
DrawPie
DrawPolygon
DrawRectangle
DrawRectangles

DrawString

Deseneaz un dreptunghi.
Deseneaz o serie de dreptunghiuri. Dac avei nevoie s desenai o serie de
dreptunghiuri, aceast metod este mult mai rapid dect apelarea repetat a
metodei DrawRectangle.
Deseneaz text pe suprafaa de desenare.
Tabelul 7.8. Cteva metode ale obiectului Graphics.

Alte metode i proprieti ale clasei Graphics


Tabelul urmtor descrie cteva dintre cele mai utile proprieti i metode ale obiectelor de
tip Graphics, altele dect acelea pentru desenare sau umplere de forme.
Proprietate/Metod
Clear

Descriere
Cur obiectul Graphics i l umple cu o culoare specific. De exemplu,
handler-ul evenimentului Paint asociat unui formular poate utiliza
sintaxa e.Graphics.Clear(this.BackColor) pentru curarea
suprafeei formularului prin utilizarea culorii de fundal.

Dispose

Elibereaz resursele ocupate de obiectul Graphics. Putei utiliza aceast


metod pentru eliberarea resurselor unui obiect de care nu mai avei
nevoie mai repede dect ar fi el eliberat de ctre colectorul de gunoaie.

129

Medii i Tehnologii de Programare curs

FromHdc

FromHwnd
FromImage

MeasureCharacterRanges

Creeaz un nou obiect Graphics pornind de la handler-ul unui context


dispozitiv. (Un context dispozitiv reprezint o structur care definete
atributele unui obiect grafic: creion, culoare, umplere, .a.m.d. De obicei,
putei utiliza procedurile de desenare GDI+ i s ignorai DC-urile.
Acestea sunt mai utile dac avei nevoie s utilizai funcii GDI mai
vechi).
Creeaz un nou obiect Graphics pornind de la handler-ul unei ferestre
(hWnd).
Creeaz un nou obiect Graphics pornind de la un obiect Image. Aceasta
este o modalitate uzual pentru a face ca un obiect Graphics s
manipuleze un bitmap.
Returneaz un ir de obiecte Region care arat locaia la care va fi
desenat fiecare caracter dintr-un string.

MeasureString

Returneaz o structur SizeF care d dimensiunea unui string desenat


ntr-un obiect Graphics folosind un anume font.

PageScale

Determin cu ct sunt scalate comenzile de desenare. De exemplu, dac


setai aceast proprietate la 2, atunci fiecare coordonat i msurtoare
este scalat cu un factor de 2 de la origine.

ResetTransformation

Reseteaz matricea de transformare a obiectului la matricea identitate,


astfel nct desenul nu este transformat.

Restore
RotateTransform

Restaureaz obiectului Graphics la o stare salvat prin metoda Save.


Adaug o rotaie la transformarea curent a obiectului. Aceast metod
rotete toate elementele desenate cu un unghi dat.

Save

Salveaz starea curent a obiectului ntr-un obiect GraphicsState, astfel


nct putei ulterior s o refacei prin apelul metodei Restore.

ScaleTransform

Adaug o transformare de scalare la transformarea curent a obiectului


Graphics. Aceasta scaleaz toate desenele cu un factor specific pe axele
X i Y.

SmoothingMode

Determin dac procedurile de desenare folosesc anti-aliasing la


desenarea de linii i curbe.

TextRenderingHint
Transform

Determin dac textul este desenat cu anti-aliasing i hinting.


Preia sau seteaz matricea de transformare a obiectului Graphics.
Aceast matrice reprezint toate scalrile, translatrile i rotaiile
aplicate obiectului.
Aplic transformarea curent unui ir de puncte.
Adaug o transformare de translaie transformrii curente a obiectului
Graphics. Aceasta deplaseaz toate desenele cu o distan specificat
pe axele X i Y.

TransformPoints
TranslateTransform

Tabelul 7.9. Alte metode i proprieti ale obiectelor de tip Graphics.

7.1.3. Evenimente de desenare


Atunci cnd o parte a unui control trebuie redesenat, se genereaz un eveniment Paint.
Handler-ul evenimentului Paint primete un parametru e de tip PaintEventArgs. Proprietatea Graphics a acestui parametru conine o referin la un obiect Graphics pe care handlerul de eveniment l-ar putea utiliza pentru redesenarea controlului. Acest obiect Graphics are
setat clipping region1 la partea din control care trebuie redesenat. Decuparea obiectului
Graphics face ca desenarea s fie mai rapid deoarece ignorarea comenzilor de desenare din
afara clipping region este mai rapid dect desenarea lor propriu-zis.

Clipping se refer la acea optimizare n care calculatorul deseneaz numai acea regiune care este vizibil
utilizatorului.

130

Grafic n Visual C# .NET

Handler-ul evenimentului Paint nu se execut atunci cnd fereastra este micorat. n acest
caz nu sunt expuse zone noi, astfel c nu se declaneaz nici un eveniment Paint.
Atunci cnd fereastra este micorat se declaneaz numai handler-ul evenimentului Resize.
Cnd fereastra este mrit, se declaneaz evenimentul Resize i este desenat toat
fereastra. Apoi este declanat evenimentul Paint care redeseneaz prile nou expuse.
Pentru imagini simple, aceasta nu este o problem. Pentru imagini complexe ns acesta
poate consuma mult timp pentru desenare, iar utilizatorul poate observa o ntrziere vizibil
a desenrii sau o plpire a imaginii.
Visual C# ofer o strategie alternativ care permite unei ferestre s se redeseneze numai o
singur dat atunci cnd este expus sau redimensionat. Precum se poate observa n codul
de mai jos, nti setai proprietatea ResizeRedraw a ferestrei pe true pentru a indica faptul c
fereastra ar trebui s se redeseneze atunci cnd este redimensionat. Apoi folosii metoda
SetStyle() a ferestrei pentru a seta pe true modul AllPaintingInWmPaint. Acesta precizeaz
limbajului Visual C# faptul c fereastra realizeaz toate operaiile de desenare n handler-ul
evenimentului Paint. Acum, dac fereastra este redimensionat, Visual C# declaneaz
suplimentar evenimentul Paint dup evenimentul Resize, astfel c programul poate face
desenarea numai la evenimentul Paint.
private void Form1_Load(object sender, EventArgs e)
{
this.ResizeRedraw = true;
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.Clear(this.BackColor);
e.Graphics.DrawRectangle(Pens.Black, 0, 0,
this.ClientSize.Width - 1, this.ClientSize.Height - 1);
e.Graphics.DrawLine(Pens.Black, 0, 0,
this.ClientSize.Width - 1, this.ClientSize.Height - 1);
e.Graphics.DrawLine(Pens.Black, this.ClientSize.Width - 1, 0,
0, this.ClientSize.Height - 1);
}

O alt modalitate de reducere a timpului de desenare este de a desena n interiorul unui


bitmap, apoi de a seta proprietatea Image a controlului PictureBox la acesta. Atunci cnd o
parte a controlului PictureBox este expus, imaginea este automat reafiat, fr a mai fi
nevoie de handler-ul evenimentului Paint.

7.2. Pensule i creioane


Dup Graphics, Pen i Brush sunt cele mai importante dou clase grafice. De fiecare dat cnd
efectuai o operaie grafic care nu manipuleaz direct pixelii unei imagini, utilizai obiecte
Pen sau Brush.
Creioanele (Pen) controleaz caracteristicile liniilor. Ele determin culoarea, grosimea, stilul i capetele liniei.
Pensulele (Brush) controleaz caracteristicile suprafeelor umplute. Ele pot umple o
suprafa cu culoare uniform, haur, imagine, sau diferite tipuri de gradieni de
culoare.
Aceast seciune descrie n detaliu creioanele i pensulele, artnd cum putei utiliza aceste
clase pentru a desena i umple tot felul de forme interesante.

131

Medii i Tehnologii de Programare curs

7.2.1. Pen
Obiectul Pen determin modul n care sunt desenate liniile. El determin culoarea, grosimea,
stilul i modul de mbinare i capetele liniilor.
Un program poate crea explicit obiecte Pen, ns adesea va fi utilizat unul dintre cele peste
280 de creioane predefinite de clasa Pen. De exemplu, codul urmtor deseneaz un
dreptunghi folosind o linie roz avnd un pixel grosime:
myGraphics.DrawRectangle(Pens.HotPink, 10, 10, 50, 50);

Creioanele sunt scalate prin transformrile aplicate unui obiect Graphics, astfel c rezultatul
nu va fi obligatoriu de un pixel grosime. Dac obiectul Graphics aplic o transformare care
scaleaz cu un factor de 10, linia rezultat va fi de grosime 10.
O soluie la aceast problem este crearea unui obiect nou Pen setnd grosimea acestuia la
0.1, dup cum se poate observa n codul urmtor. Grosimea este scalat la 0.1 * 10 = 1.
myGraphics.DrawRectangle(new Pen(Color.HotPink, 0.1f), 10, 10, 50, 50);

O alt soluie este crearea unui creion cu grosimea 0. ntotdeauna liniile care au specificat
grosimea 0 sunt desenate de procedurile GDI+ cu grosime de un pixel.
Tabelul urmtor descrie unele dintre cele mai utile proprieti i metode ale clasei Pen.
Proprietate sau Metod
Brush
Color
CustomEndCap
CustomStartCap
DashPattern

DashStyle

EndCap

Descriere
Determin pensula folosit pentru umplerea liniilor.
Determin culoarea liniilor.
Permite definirea captului final al liniilor.
Permite definirea captului iniial al liniilor.
Un ir de valori Single care specific un ablon particular care determin
stilul de desenare al liniilor. Valorile din ir indic numrul de pixeli
desenai, omii, desenai, omii .a.m.d. Aceste valori sunt scalate dac
creionul nu are grosimea de un pixel.
Determin stilul liniilor. Aceast valoare poate fi Dash (linie), DashDot
(linie-punct), DashDotDot (linie-punct-punct), Dot (punct), Solid sau
Custom. Dac setai proprietatea DashPattern, aceast valoare este
setat la Custom. Liniuele i distanele dintre ele sunt scalate dac
creionul nu are grosimea de un pixel.
Determin capetele utilizate la sfritul liniilor. Aceast valoare poate fi:
ArrowAnchor, DiamondAnchor, Flat, NoAnchor, Round, RoundAnchor,
Square, SquareAnchor, Triangle i Custom. Dac LineCap este Custom, ar
trebui s utilizai un obiect CustomLineCap pentru definirea capetelor.
Figura 7.11 arat valorile standard ale LineCap.

LineJoin

Determin modul n care sunt mbinate liniile de ctre metodele GDI+


care deseneaz linii conectate. De exemplu, metodele DrawPolygon i
DrawLines utilizeaz aceast proprietate. Aceast valoare poate fi Bevel,
Miter i Round. Figura 7.12 arat aceste valori.

SetLineCap

Aceast metod primete parametri care permit specificarea


proprietilor StartCap, EndCap i LineJoin ale creionului simultan.

StartCap
Width

Determin capetele utilizate la nceputul liniilor.


Grosimea creionului. Aceast valoare este scalat dac creionul este
transformat de ctre propria transformare sau de transformarea aplicat
obiectului Graphics care l folosete.
Tabelul 7.10. Proprieti i metode utile ale clasei Pen

132

Grafic n Visual C# .NET

Figura 7.11. Enumerarea LineCap determin modul n care sunt desenate capetele unei linii.

Figura 7.12. Enumerarea LineJoin determin modul n care sunt mbinate liniile.

7.2.2. Brush
Obiectul Brush determin modul n care sunt umplute suprafeele atunci cnd le desenai
utiliznd metodele FillClosedCurve(), FillEllipse(), FillPath(), FillPie(), FillPolygon(),
FillRectangle() i FillRectangles() ale obiectului Graphics. Tipuri diferite de pensule umplu
suprafee cu culori uniforme, abloane de hauri i gradieni de culoare.
Clasa Brush nsi este o clas abstract, astfel c nu putei crea instane ale clasei Brush. n
schimb, putei crea instane ale uneia din clasele derivate SolidBrush, TextureBrush,
HatchBrush, LinearGradientBrush i PathGradientBrush. Tabelul urmtor descrie sumar aceste
clase.
Clas
SolidBrush
TextureBrush
HatchBrush
LinearGradientBrush
PathGradientBrush

Descriere
Umple suprafee cu o singur culoare uniform
Umple suprafee cu o imagine repetat afiat
Umple suprafee cu un ablon repetat de haur
Umple suprafee cu un gradient liniar de dou sau mai multe culori
Umple suprafee cu un gradient de culoare care urmrete o cale
Tabelul 7.13. Clase derivate din clasa Brush.

SolidBrush
O pensul SolidBrush umple o suprafa cu o culoare uniform. Aceast clas este extrem de
simpl. Ea are un singur constructor care primete un parametru care specific culoarea
pensulei. Singura proprietate util este Color, care determin culoarea pensulei.
private void Form1_Paint(object sender, PaintEventArgs e)
{
// pensula creata de utilizator
SolidBrush redBrush = new SolidBrush(Color.Red);
e.Graphics.FillRectangle(redBrush, 10, 10, 200, 100);
// pensula predefinita
Brush blueBrush = Brushes.Blue;

133

Medii i Tehnologii de Programare curs

e.Graphics.FillRectangle(blueBrush, 10, 120, 200, 100);


}

TextureBrush
O pensul TextureBrush v d control deplin asupra fiecrui pixel din interiorul suprafeei
umplute. Putei s v construii propriile imagini pentru a fi utilizate ca abloane de hauri,
ns n general este mai simplu s utilizai clasa HatchBrush.

HatchBrush
HatchBrush este o clas relativ simpl. Cele mai utile trei proprieti sunt BackgroundColor,
ForegroundColor i HatchStyle. ForegroundColor i BackgroundColor determin culorile utilizate
de pensul. HatchStyle poate primi una dintre cele 54 de valori. Figura 7.14 listeaz valorile
posibile pentru HatchStyle i afieaz mostre pentru fiecare.

Figura 7.14. Enumerarea HatchStyle determin modul n care HatchBrush umple o suprafa.

Codul de mai jos arat modul n care un program poate umple un dreptunghi cu un
HatchBrush. Creeaz o pensul folosind stilul LargeGrid cu culoare albastr i fundal albastru
deschis. Apeleaz metoda FillRectangle() pentru a umple un dreptunghi cu aceast pensul,
apoi apeleaz DrawRectangle() pentru desenarea unui contur negru n jurul acestuia (vezi
Figura 7.15).
private void Form1_Paint(object sender, PaintEventArgs e)
{
HatchBrush myBrush = new HatchBrush(HatchStyle.LargeGrid, Color.Blue, Color.LightBlue);
e.Graphics.FillRectangle(myBrush, 10, 10, 200, 200);
e.Graphics.DrawRectangle(Pens.Black, 10, 10, 200, 200);
}

134

Grafic n Visual C# .NET

Figura 7.15. Umplerea unui dreptunghi cu o pensul HatchBrush

135

Medii i Tehnologii de Programare curs

8. Baze de date n Visual C# .NET


n industrie, majoritatea aplicaiilor nu pot fi construite fr s interacioneze cu o baz de
date. Bazele de date servesc scopului de stocare a datelor astfel nct acestea s poat fi
extrase ulterior (prin interogri SQL sau prin aplicaii de baze de date).
n Visual Studio .NET controalele i componentele puse la dispoziie pentru lucrul cu baze de
date permit utilizatorului s interacioneze cu aplicaia, aceasta afind date ctre utilizator,
iar mediul de programare controlnd aplicaia. Controalele i componentele specializate aduc
datele din baza de date ctre aplicaie, permind acesteia s trimit napoi date ctre baza de
date.
Programarea cu baze de date este un subiect vast, cu anevoie de acoperit ntr-un singur
capitol. Acest capitol i propune prezentarea modului de lucru cu bazele de date i descrierea
unor controale, componente i obiecte utile oferite de Visual C# pentru lucrul cu bazele de
date.

8.1. Conectarea automat la baza de date


Visual Studio .NET ofer controale i instrumente care fac uoar conectarea la baza de date.
Pentru a construi un program simplu cu baze de date, vom crea un proiect nou de tip Windows
Forms Application. Apoi, din meniul Project, alegem comanda Add New Data Source, care va
afia un dialog pentru configurarea conectrii la baza de date, precum se poate observa n
Figura 8.1.

Figura 8.1. Dialogul pentru configurarea sursei datelor

Visual Studio .NET permite utilizarea bazelor de date, a serviciilor web i a obiectelor n
aplicaia noastr. Ceea ce vom selecta noi n continuare, pentru a prelua datele dintr-o baz de

136

Baze de date n Visual C# .NET

date, este opiunea Database, dup care vom trece la pasul urmtor, alegerea unui model de
baz de date, precum se poate observa n dialogul din Figura 8.2.

Figura 8.2. Alegerea unui model de baz de date.

Dac n cadrul unor proiecte anterioare am creat conexiuni la baze de date, putem s le
selectm din lista derulant (Figura 8.3). Dac dorim s crem o noua conexiune, vom apsa
butonul New Connection, caz n care va aprea dialogul din Figura 8.4.

Figura 8.3. Alegerea conexiunii la o baz de date

137

Medii i Tehnologii de Programare curs

Figura 8.4. Fereastra dialog pentru crearea unei noi conexiuni la baza de date.

Dac baza noastr de date este n alt format dect cel implicit (n acest exemplu, Microsoft
Access Database), vom apsa butonul Change, caz n care va aprea o fereastr de dialog
(Figura 8.5) din care putem selecta unul din tipurile de baze de date existente, cum ar fi
Microsoft Access, o surs ODBC, SQL Server sau Oracle.

Figura 8.5. Dialogul pentru selectarea tipului de baz de date.

Dup ce am selectat tipul de baz de date dorit, ne vom ntoarce la fereastra Add Connection.
Coninutul acestei ferestre va diferi n funcie de tipul de baz de date selectat.
Pentru baza de date Microsoft Access trebuie s introducem numele fiierului sau s apsm
butonul Browse (vezi Figura 8.4) pentru a gsi i selecta fiierul de baz de date. Dac este
necesar, vom introduce suplimentar numele de utilizator i parola pentru accesul la baza de
date.
La ntoarcerea n fereastra Data Source Configuration Wizard, selectm noua conexiune, aa
cum este prezentat n Figura 8.6. Tot aici putem vizualiza irul de conectare la baza noastr de
date.

138

Baze de date n Visual C# .NET

Figura 8.6. Conexiunea la baza de date i vizualizarea irului de conectare

La pasul urmtor, vom fi informai c baza noastr de date este un fiier local i vom fi ntrebai
dac vrem s o adugm la proiectul nostru (Figura 8.7). Dac selectm Yes, baza de date va
fi inclus n proiect i va aprea n fereastra Project Explorer. Dac dorim s distribuim baza
de date mpreun cu aplicaia noastr, este mai convenabil s gestionm baza de date i codul
Visual C# mpreun. Totui, n acest caz exist un inconvenient (o setare implicit): ori de cte
ori proiectul va fi compilat, baza de date va fi copiat din locaia original n directorul
aplicaiei, suprascriind-o pe cea existent i existnd astfel riscul de a pierde ultimele date
adugate. Acest neajuns se poate remedia prin setarea, din Solution Explorer, pentru fiierul
de baz de date, a proprietii Copy to Output Directory la valoarea Copy if newer (Figura
8.8).

Figura 8.7. Dialogul care apare la selectarea unei baze de date dintr-un fiier local

Figura 8.8. Setarea corespunztoare a proprietilor bazei de date

139

Medii i Tehnologii de Programare curs

n continuare vom fi ntrebai dac dorim s salvm informaiile despre conectare n fiierul
de configurare al aplicaiei noastre. Dac lsm selectat aceast opiune atunci aceste
informaii vor fi adugate n fiierul app.config. (Figura 8.9)

Figura 8.9. Salvarea irului de conectare la baza de date

Mai jos este prezentat coninutul fiierului app.config unde sunt stocate informaiile despre
conectarea la baza de date.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
</configSections>
<connectionStrings>
<add name="WindowsFormsApplication1.Properties.Settings.CatalogConnectionString"
connectionString="Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\Catalog.accdb"
providerName="System.Data.OleDb" />
</connectionStrings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>

Fereastra urmtoare conine informaii despre obiectele din baza de date. n acest exemplu,
baza de date conine dou tabele: Studenti i Note. Putem desfura informaiile despre tabele,
afiate arborescent, pentru a vedea ce cmpuri conin i, eventual, pentru a selecta numai o
parte dintre acestea (vezi Figura 8.10).

140

Baze de date n Visual C# .NET

Figura 8.10. Selectarea tabelelor i a cmpurilor din baza de date

Dup ncheierea wizard-ului (comanda Finish) la aplicaia noastr vor fi adugate cteva
obiecte. Fereastra Solution Explorer (Figura 8.11) afieaz dou obiecte: baza de date
Catalog.accdb i fiierul CatalogDataSet.xsd care descrie sursa de date.

Figura 8.11. Obiectele adugate n fereastra Solution Explorer

Dac dam dublu click pe fiierul *.xsd, Visual C# va deschide un editor (Figura 8.12) care va
afia tabele mpreun cu cmpurile lor i relaiile definite ntre tabele (dac exist aa ceva).

141

Medii i Tehnologii de Programare curs

Figura 8.12. Tabele definite i relaia dintre ele.

Linia trasat ntre cele 2 obiecte, avnd la un capt o pictogram cheie, iar la cellalt simbolul
infinit, indic faptul ca relaia dintre tabele este de tip one-to-many. n acest exemplu, cmpul
IDStudent din tabelul Studenti mpreun cu cmpul IDStudent din tabelul Note formeaz o
relaie de tip foreign key. Aceasta nseamn c fiecare valoare IDStudent din tabelul Note
trebuie s corespund unei singure valori IDStudent din tabelul Studenti. Dac se efectueaz
dublu click pe link-ul de relaionare (sau click dreapta), editorul va afia fereastra din Figura
8.13.

Figura 8.13. Detaliile privitoare la relaia dintre tabelele Studenti i Note

n partea de jos a tabelelor afiate n Figura 8.12, se pot observa dou obiecte de tip data
adapter care conin etichetele Fill, GetData(). Aceste obiecte vor fi folosite mai trziu n
aplicaie pentru a muta datele din/n baza de date.

142

Baze de date n Visual C# .NET

n plus, wizard-ul a adugat n fereastra Data Sources un nou obiect DataSet (vezi Figura 8.14).
Dac fereastra Data Sources nu este vizibil, se poate selecta din meniul View > Other
Windows > Data Sources.
n Figura 8.14 este prezentat dataset-ul afiat sub form arborescent, fiind vizibile tabelele
i cmpurile acestora. Se poate observa c tabelul Note este listat sub tabelul Studenti,
deoarece exist o relaie printe-copil ntre cele dou.

Figura 8.14. Fereastra Data Sources.

Este nevoie de multe cuvinte i figuri pentru descrierea acestui proces, dar, utiliznd wizardul, aceast operaiune devine foarte rapid. Dup ce am creat legtura la sursa de date putem
construi pentru aplicaia noastr o interfa simpl fr nici un efort. Trebuie doar s tragem
pe formularul nostru cu draganddrop obiectele din fereastra Data Sources.
Dac facem click pe unul dintre tabelele afiate n Data Sources apoi l tragem cu drag-anddrop peste un formular, Visual C# creeaz automat controalele BindingNavigator i
DataGridView, precum i alte componente utile pentru afiarea datelor din tabel (vezi Figura
8.15)

Figura 8.15. Afiarea datelor sub form tabelar

n loc s afim tot tabelul pe formular, putem s tragem numai anumite cmpuri din tabel. n
acest caz, Visual C# adaug controale pe formular pentru a reprezenta coloanele.
Dac selectm un tabel din fereastra Data Sources, va aprea un meniu drop down care ne
ofer posibilitatea de a alege stiluri diferite de afiare, aa cum se poate observa n Figura 8.16.
De exemplu, dac setam stilul de afiare la Details i apoi tragem tabelul pe formularul noastru,
Visual C# va afia datele din tabel utiliznd o afiare detaliat a cmpurilor, precum se poate
vedea n Figura 8.17.

143

Medii i Tehnologii de Programare curs

Figura 8.16. Meniul drop down obinut n urma efecturii click dreapta pe tabel

Figura 8.17. Afiare n stil Details a datelor din tabel

Similar, se poate schimba modul de afiare pentru orice cmp din tabelul nostru. Se selecteaz
cmpul din fereastra Data Sources, iar din meniul drop down care apare putem selecta
controlul n care s fie afiate pe formular datele din acel cmp (vezi Figura 8.18). Atunci cnd
tragei cmpul sau tabelul pe un formular pentru construirea interfeei aplicaiei, Visual C# va
utiliza acest tip de control pentru afiarea valorilor cmpului.

Figura 8.18. Asocierea unui cmp cu un control la afiarea n modul Details

8.2. Obiecte create automat


Atunci cnd un tabel sau un cmp (coloan) este tras prin drag-and-drop din fereastra Data
Sources pe o interfa, Visual C# face mai mult dect s plaseze un control DataGridView pe
interfa. El creeaz, de asemenea, o mulime de alte controale i componente. Dintre acestea
cele mai importante sunt DataSet, TableAdapter, BindingSource i BindingNavigator (vezi
Figura 8.19)

144

Baze de date n Visual C# .NET

Figura 8.19. Visual C# folosete componentele DataSet, TableAdapter, TableAdapterManager, BindingSource i


BindingNavigator pentru a opera cu datele din baza de date.

Programul stocheaz datele ntr-un obiect de tip DataSet. Un obiect DataSet reprezint o baz
de date. Acesta conine obiecte de tip DataTable, care reprezint tabelele din baza de date.
Fiecare obiect DataTable conine obiecte DataRow, care reprezint nregistrrile din baza de
date, iar fiecare obiect DataRow conine obiecte DataColumn, care reprezint cmpurile din
tabele.
Obiectele de tip TableAdapter sunt utilizate pentru comunicaia dintre aplicaie (mai precis,
un obiect DataSet) i o baz de date. Acestea ofer metode pentru efectuarea operaiilor
asupra bazei de date (cum ar fi selectare, inserare, modificare sau tergere). Un TableAdapter
se conecteaz la o baz de date, execut interogri SQL sau proceduri stocate i poate returna
fie un tabel nou, populat cu datele returnate, fie un obiect DataTable existent, populat cu datele
returnate. Obiectele TableAdapter sunt utilizate de asemenea pentru a trimite date actualizate
de la aplicaia curent napoi la baza de date.
TableAdapterManager reprezint o component care ofer funcii de salvare a datelor n
tabele relaionate. TableAdapterManager utilizeaz relaiile de tip foreign-key, care
relaioneaz tabelele, pentru determinarea ordinii corecte de trimitere a comenzilor Insert,
Update sau Delete de la un DataSet ctre o baz de date fr nclcarea regulilor definite prin
intermediul foreign-key-urilor din baza da date.
Obiectul BindingSource ncapsuleaz toate datele din DataSet i ofer funcii pentru controlul
acestora din cadrul programului. Aceste funcii efectueaz aciuni cum ar fi: mutarea datelor,
adugarea sau tergerea elementelor, etc.
BindingNavigator ofer o interfa grafic pentru ca utilizatorul s poat controla
BindingSource.
Figura 8.20 ilustreaz legturile dintre obiectele DataSet, TableAdapter, BindingSource i
BindingNavigator.

145

Medii i Tehnologii de Programare curs

Figura 8.20. Legtura dintre obiecte DataSet, TableAdapter, BindingSource i BindingNavigator

Chiar i aceste obiecte, lucrnd mpreun, nu fac totul pentru ca informaiile s fie afiate de
program. Cnd creeaz aceste obiecte, Visual C# adaug, de asemenea, la formularul nostru
codul prezentat mai jos. Event handler-ul Form1_Load() face ca TableAdapter-ul s copieze
toate datele din baza de date n DataSet, iar studentiBindingNavigatorSaveItem_Click() se
execut n momentul cnd utilizatorul face click pe comanda Save din BindingNavigator.
Aceast metod face ca TableAdapter-ul s salveze orice modificare a tabelului Studenti n
baza de date.
private void studentiBindingNavigatorSaveItem_Click(object sender, EventArgs e)
{
this.Validate();
this.studentiBindingSource.EndEdit();
this.tableAdapterManager.UpdateAll(this.catalogDataSet);
}
private void Form1_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'catalogDataSet.Studenti' table.
// You can move, or remove it, as needed.
this.studentiTableAdapter.Fill(this.catalogDataSet.Studenti);
}

Visual C# creeaz toate acestea automat, iar dac rulm programul vom vedea toate
informaiile din baza de date afiate, avnd posibilitatea de a le manipula. Aplicaia obinut
nu este perfect, n sensul c, printre altele, nu exist nicio validare a datelor, lsnd
utilizatorul s nchid aplicaia fr s salveze modificrile fcute n baza de date. Este totui
un nceput bun, pentru att de puin efort depus.

8.3. Alte obiecte pentru lucrul cu baze de date


Dac dorim s crem un program care s afieze i s modifice datele din baza de date, cel
descris anterior este destul de bun. n acest caz, vom permite ca Visual Studio s implementeze
automat partea de conectare la baza de date, utilizatorul nefiind nevoit s aprofundeze
detaliile lucrului cu baze de date. De asemenea, putem crea propriile noastre obiecte DataSet,
TableAdapter, BindingSource i BindingNavigator pentru construirea propriilor aplicaii
pentru lucrul cu baze de date.
Dac este nevoie s manipulm direct din cod datele din baza de date, nu are sens s crem
toate aceste obiecte. Dac, de exemplu dorim s modificm o nregistrare, nu are sens s crem
obiecte DataGridView, BindingNavigator i BindingSource.
Pentru cazuri ca acestea, Visual C# pune la dispoziie alte cteva tipuri de obiecte care pot fi
folosite pentru a interaciona cu baza de date. Aceste obiecte se mpart n urmtoarele
categorii:

146

Baze de date n Visual C# .NET

DataContainer: stocheaz datele, dup ce acestea au fost ncrcate din baza de date n
aplicaie, similar DataSet-urilor. La aceste obiecte pot fi legate controale, pentru
afiarea automat a datelor i manipularea bazei de date.

Connection: ofer informaii care i permit programului conectarea la o baz de date.


DataAdapter: permit mutarea datelor ntre baza de date i containerul de date.

Command: ofer instruciuni pentru manipularea datelor. Un obiect de tip Command


poate selecta, insera, modifica sau terge date din baza de date. De asemenea, poate
executa proceduri stocate n baza de date.

Clasele de tip DataContainer i DataAdapter sunt generice i lucreaz cu diferite tipuri de baze
de date, n timp ce obiectele de tip Connection i Command sunt specifice anumitor tipuri de
baze de date. De exemplu, obiectele de conectare OleDbConnection, SqlConnection,
OdbcConnection i OracleConnection pot lucra cu OLE DB (Object Linking and Embedding
DataBase), SQL Server incluznd MSDE (MicroSoft Data Engine), ODBC (Open DataBase
Connectivity), respectiv baze de date Oracle.
Obiectele SQL Server i Oracle pot lucra doar cu baze de date care fac parte din acelai brand,
dar ele sunt mai complete i mai potrivite pentru baze de date SQL, respective Oracle.

8.4. O privire de ansamblu asupra datelor


O aplicaie folosete trei obiecte de baz pentru a muta datele n/din baza da date: o
conexiune, un adaptor de date i un container de date cum ar fi DataSet. Obiectul de tip
Connection definete conexiunea la baza de date. Acesta conine informaii despre baza de
date cum ar fi numele, locaia, nume de utilizator i parol, necesare pentru accesarea datelor
i informaii despre provider-ul bazei de date.
Adaptorul de date definete o mapare de la baza de date la DataSet. Aceasta determin ce tip
de date sunt selectate din baza de date i care coloane din baza de date vor fi mapate pe
coloanele din DataSet.
Obiectele de tip DataSet stocheaz datele n interiorul aplicaiei. Acestea pot stoca unul sau
mai multe tabele i pot defini sau fora relaii ntre tabele. De exemplu, baza de date folosit
anterior n acest capitol are un tabel Note care conine un cmp IDStudent. Valoarea din acest
cmp trebuie s se regseasc n valorile din tabelul Studenti, cmpul IDStudent. Aceasta
reprezint o constrngere de tip foreign key. Obiectul DataSet poate reprezenta aceast
constrngere i semnala o eroare dac programul ncearc s creeze o nregistrare n tabelul
Note cu o valoare a cmpului IDStudent care nu apare n tabelul Studenti.
Odat iniializat conexiunea mpreun cu obiectele DataAdapter i DataSet, programul poate
apela metoda Fill() a obiectului DataAdapter pentru copierea datelor din baza de date n
DataSet. Mai trziu se poate apela metoda Update() pentru copierea oricror modificri ale
nregistrrilor din DataSet napoi n baza de date (Figura 8.21)

Figura 8.21. Obiectele de tip Connection, Data adapter i DataSet sunt folosite pentru mutarea datelor n/din
baza de date.

147

Medii i Tehnologii de Programare curs

Dac se compar Figura 8.21 cu Figura 8.20 se vor observa cteva similitudini. Ambele metode
folosesc un adaptor pentru a tranzita datele ntre baza de date i DataSet. La o prim privire
ar prea c n Figura 8.20 nu se folosete un obiect conexiune, dar de fapt obiectul
TableAdapter conine intern un obiect conexiune pentru accesarea bazei de date.
O diferen major este faptul c n Figura 8.20 se folosete un BindingSource i un
BindingNavigator pentru a-i permite utilizatorului s controleze BindingSource i s parcurg
nregistrrile.

8.5. Obiecte de tip Connection


Aceste obiecte sunt responsabile de conectarea aplicaiei la baza de date. Ele permit unui
DataAdapter s mute datele n/din DataSet.
Dei, la nivel primar, ofer aceleai proprieti, exist unele diferene ntre obiectele
OleDbConnection, SqlConnection, OdbcConnection i OracleConnection.
Unele obiecte de tip Connnection pot lucra cu mai multe tipuri de baze de date. De exemplu,
obiectul OleDbConnection poate lucra cu orice tip de baz de date care suport conexiuni
ODBC. n general, obiectele Connection care lucreaz cu un tip specific de baze de date (cum
ar fi SqlConnection sau OracleConnection) ofer cele mai bune performane.
Tabelul 8.22 descrie cteva dintre cele mai folosite proprieti puse la dispoziie de clasele
OleDbConnection i SqlConnection.
Proprietate
ConnectionString
ConnectionTimeout

Descriere
Stringul care definete conectarea la baza de date
Timpul pe care obiectul l ateapt pentru a se conecta la baza de date. Dac
acest timp expir, se abandoneaz conectarea i se semnaleaz eroare.

Database
DataSource

Returneaz numele bazei de date curente.


Returneaz numele bazei de date curente sau numele serverului.

Provider

(Doar pentru OleDbConnection) Returneaz numele provider-ului bazei de date


OLEDB (de exemplu Microsoft.Jet.OLEDB.4.0).

ServerVersion

Returneaz numrul versiunii serverului bazei de date. Valoarea este valabil


doar cnd conexiunea este deschis i se exprim sub forma 04.00.0000.
Returneaz starea conexiunii. Poate lua valorile Closed, Connecting, Open,
Executing (execut o comand), Fetching i Broken (conexiunea a fost deschis i
apoi ntrerupt; se poate nchide i redeschide apoi conexiunea).

State

Tabelul 8.22. Proprieti utile ale obiectelor Connection

Proprietatea ConnectionString include mai multe cmpuri separate prin punct i virgul.
Textul urmtor arat o valoare tipic a proprietii ConnectionString pentru o conexiune
OleDbConnection care va accesa o baz de date Access.
Jet OLEDB:Global Partial Bulk Ops=2;
Jet OLEDB:Registry Path=;
Jet OLEDB:Database Locking Mode=1;
Data Source="D:\Work\Angajati.mdb";
Mode=Share Deny None;Jet OLEDB:Engine Type=5;
Provider="Microsoft.Jet.OLEDB.4.0";
Jet OLEDB:System database=;
Jet OLEDB:SFP=False;
persist security info=False;
Extended Properties=;
Jet OLEDB:Compact Without Replica Repair=False;
Jet OLEDB:Encrypt Database=False;
Jet OLEDB:Create System Database=False;

148

Baze de date n Visual C# .NET

Jet OLEDB:Dont Copy Locale on Compact=False;


User ID=Admin;
Jet OLEDB:Global Bulk Transactions=1;

Multe dintre cmpurile separate prin punct i virgul sunt opionale i pot fi omise. Ar fi destul
de complicat s ne amintim care sunt cmpurile obligatorii i care sunt cele opionale, ns,
din fericire, nu este necesar. n loc s compunem noi proprietatea ConnectionString, putem
lsa Visual C# s o alctuiasc pentru noi. Pentru aceasta, afim fereastra Server Explorer
(meniul View > Server Explorer), precum se poate observa n Figura 8.23.

Figura 8.23. Fereastra Server Explorer

Urmtorul fragment de cod ilustreaz crearea, deschiderea, folosirea i nchiderea unui obiect
OleDbConnection.
using System.Data.OleDb;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
// ...
private void Form1_Load(object sender, EventArgs e)
{
// Creeaza conexiunea.
OleDbConnection conn = new OleDbConnection(@"Provider=Microsoft.ACE.OLEDB.12.0;
Data Source=D:\Work\Catalog.accdb;
Persist Security Info=True;User ID=Admin;Password=;");
// Deschide conexiunea.
conn.Open();
// ...
// Inchide conexiunea.
conn.Close();
conn.Dispose();
}
}
}

Tabelul 8.24 prezint cele mai des folosite metode propuse de clasele OleDbConnection i
SqlConnection.
Metoda
BeginTransaction

Descriere
ncepe o tranzacie cu baza de date i returneaz un obiect de tip tranzacie. O
tranzacie asigur faptul c toate comenzile dintr-o secven de comenzi sunt
executate, n caz contrar operaia fiind anulat.

ChangeDatabase
Close
CreateCommand

Modific baza de date curent.


nchide baza de date curent.
Creeaz un obiect de tip comand care poate executa unele aciuni asupra bazei
de date, cum ar fi selectarea de nregistrri, crearea de tabele, modificarea unor
nregistrri, etc.
Deschide o conexiune cu valorile specificate n proprietatea ConnectionString

Open

Tabelul 8.24. Metode utile ale obiectelor Connection.

149

Medii i Tehnologii de Programare curs

Cele mai utile evenimente ale obiectelor de tip Connection sunt InfoMessage i StateChange.
Evenimentul InfoMessage apare cnd provider-ul de baz de date semnaleaz o avertizare sau
un mesaj de informare. Programul poate citi mesajul i, n consecin, poate efectua o aciune
sau, pur i simplu, l afieaz utilizatorului. Evenimentul StateChange apare cnd se modific
starea conexiunii la baza de date.
Metodele Fill() i Update() ale unui obiect DataAdapter deschid automat o conexiune,
efectueaz aciunile, apoi nchid conexiunea, astfel nct utilizatorul nu este nevoit s
gestioneze conexiunile. De exemplu, cnd programul apeleaz metoda Fill(), adaptorul
deschide rapid o conexiune, copiaz datele din baza de date n DataSet i apoi nchide
conexiunea.

8.6. Obiecte de tip DataAdapter


Un obiect de tip DataAdapter transfer datele ntre o conexiune i un DataSet. Metodele cele
mai importante ale acestui obiect sunt Fill() i Update(), care mut datele n i din DataSet.
Un DataAdapter ofer, de asemenea, alte proprieti i metode care pot fi folositoare. Tabelul
8.25 prezint cele mai folositoare proprieti ale obiectelor de tip DataAdapter.
Proprietate
DeleteCommand
InsertCommand
SelectCommand
TableMappings

UpdateCommand

Descriere
Obiectul de tip Command pe care obiectul DataAdapter l folosete pentru a
terge nregistrri.
Obiectul de tip Command pe care DataAdapter-ul l folosete pentru a insera
nregistrri.
Obiectul de tip Command pe care DataAdapter-ul l folosete pentru a selecta
nregistrri.
O colecie de obiecte DataTableMapping care determin modul n care vor fi
mapate tabelele din baza de date n DataSet. Fiecare obiect are o colecie
ColumnMappings care va determina modul n care vor fi mapate coloanele din
tabele n tabelele din DataSet.
Obiectul de tip Command pe care DataAdapter-ul l folosete pentru a modifica
nregistrri.
Tabelul 8.25. Proprieti utile ale obiectelor DataAdapter.

Exist mai multe modaliti de creare a obiectelor de tip Command. De exemplu, dac pentru
construirea adaptorului folosim Data Adapter Configuration Wizard, atunci wizardul creeaz
automat aceste obiecte (vom vedea n continuare cum). Putem selecta adaptorul i expanda
obiectele de tip Command n fereastra Properties, pentru a le vizualiza proprietile.
Data Adapter Configuration Wizard v ajut la setarea proprietilor unui nou adaptor de date
sau a unuia existent. Un adaptor de date conine comenzi SQL pe care aplicaia le poate utiliza
pentru citirea datelor dintr-o baz de date ntr-un DataSet i scrierea lor napoi. Wizard-ul
poate opional s creeze o conexiune de date care permite adaptorului s comunice cu o baz
de date.
O alt modalitate de creare a acestor comenzi este folosirea unui obiect CommandBuilder.
Dac atam un astfel de obiect adaptorului, acesta va folosi obiectul CommandBuilder pentru
a genera comenzile de care are nevoie, n mod automat.
Urmtoarea secven de cod ilustreaz modul n care un program poate asocia un obiect de
tip OleDbCommandBuilder la un OleDbDataAdapter. Cnd se apeleaz metoda Update(),
adaptorul folosete obiectul CommandBuilder, dac este necesar, pentru a efectua comenzi de
inserare, modificare sau tergere asupra bazei de date. Metoda Debug.WriteLine() va afia
textul comenzilor generate n mod automat.

150

Baze de date n Visual C# .NET

private void Form1_Load(object sender, EventArgs e)


{
// Ataseaza un command builder la adaptorul de date si afiseaza comenzile generate.
OleDbConnection con = new OleDbConnection(@"Provider=Microsoft.ACE.OLEDB.12.0;
Data source=D:\Work\temp\Catalog.accdb;User ID=Admin;Password=;");
con.Open();
OleDbDataAdapter dataAdapter = new OleDbDataAdapter(
new OleDbCommand("SELECT * FROM Studenti", con));
OleDbCommandBuilder cmdBuilder = new OleDbCommandBuilder(dataAdapter);
Debug.WriteLine(cmdBuilder.GetDeleteCommand().CommandText);
Debug.WriteLine(cmdBuilder.GetInsertCommand().CommandText);
Debug.WriteLine(cmdBuilder.GetUpdateCommand().CommandText);
}

Textul urmtor afieaz rezultatele obinute. Obiectul de tip CommandBuilder genereaz


aceste comenzi pe baza interogrii "SELECT * FROM Studenti" care a fost ncrcat n DataSet.
DELETE FROM Studenti WHERE ((IDStudent = ?) AND ((? = 1 AND Nume IS NULL) OR (Nume = ?)) AND
((? = 1 AND Prenume IS NULL) OR (Prenume = ?)))
INSERT INTO Studenti (Nume, Prenume) VALUES (?, ?)
UPDATE Studenti SET Nume = ?, Prenume = ? WHERE ((IDStudent = ?) AND ((? = 1 AND Nume IS
NULL) OR (Nume = ?)) AND ((? = 1 AND Prenume IS NULL) OR (Prenume = ?)))

Proprietatea TableMappings a adaptorului, permite modificarea felului n care adaptorul


mapeaz datele din baza de date n DataSet. De exemplu, am putea face o copie a tabelului
Studenti din baza de date n DataSet, numita Tineri. De obicei, nu este nevoie s modificm
numele tabelului sau a coloanelor, totui aceste modificri se pot face interactiv n modul
design mult mai uor dect n cod, astfel c, de obicei, aceste valori se vor lsa nemodificate.
Pentru a crea un data adaptor n modul design, trebuie s deschidem un formular, selectm
din meniul Toolbox opiunea Data i apoi dublu click pe controlul DataAdapter (dac nu apare
controlul DataAdapter n ToolBox, atunci facem click dreapta pe ToolBox, selectm meniul
Choose Items, iar de acolo selectm adaptorul dorit, de exemplu, OleDbDataAdapter).
La crearea unui DataAdapter va aprea Data Adapter Configuration Wizard (vezi Figura 8.26).
Primul pas este similar celui descris anterior pentru configurarea unei noi conexiuni. Selectm
o conexiune deja existent sau apsm butonul New Connection pentru una nou.

Figura 8.26. Data Adapter Configuration Wizard ne ajuta s definim un adaptor nou

La apsarea butonului Next va aprea un dialog ca cel din Figura 8.27. De aici putem selecta
metoda cu care adaptorul va opera asupra bazei de date i va determina modul n care datele
vor fi selectate, inserate sau modificate n baza de date. Dac selectm opiunea Use SQL

151

Medii i Tehnologii de Programare curs

Statements, atunci adaptorul va lucra cu instruciuni simple SQL. Dac selectm opiunea
Create new stored procedures, adaptorul va genera noi proceduri stocate n baza de date.
Pentru ca wizardul s foloseasc proceduri stocate existente, selectm opiunea Use existing
stored procedures. n Figura 8.27 prima opiune este singura disponibil pentru un
OleDbDataAdapter ataat unei baze de date Access, aa cum am folosit n acest exemplu.

Figura 8.27. Selectarea unei metode prin care adaptorul va opera asupra bazei de date

Dac selectm Use SQL Statements i apsm butonul Next, va aprea dialogul din Figura
8.28.

Figura 8.28. Generarea interogrii SQL

Dac avem experien n lucrul cu interogrile SQL, atunci putem introduce manual o
interogare SQL pe care adaptorul o va folosi cnd va selecta datele din baza de date. n caz
contrar, putem da click pe butonul Query Builder (vezi Figura 8.29), apoi vom selecta
tabelele din baza de date care conin nregistrrile pe care vrem s le folosim i dm click pe
butonul Add. Dup ce am selectat tabelele nchidem dialogul Add Table. Coloanele din al
doilea panou pot fi utilizate pentru determinarea modului n care sunt sortate cmpurile. n al
treilea panou este afiat comanda SQL pe care o construim. Putem da click pe butonul

152

Baze de date n Visual C# .NET

Execute Query pentru rularea interogrii SQL i afiarea rezultatelor n partea de jos. Cnd
am terminat, apsm butonul OK.

Figura 8.29. Putem utiliza instrumentul Query Builder pentru definirea datelor pe care le va folosi adaptorul.

Dup ce apsm butonul Next, Data Adapter Configuration Wizard va afia un sumar similar
celui din Figura 8.30. Acest sumar descrie aciunile pe care wizard-ul le va executa i pe cele
pe care nu le va executa. n funcie de interogarea folosit pentru selectarea datelor, wizardul s-ar putea s nu genereze toate comenzile de selectare, modificare, inserare sau tergere a
nregistrrilor. De exemplu, dac interogarea cuprinde mai multe tabele, wizard-ul nu va fi
capabil s i dea seama cum s modifice nregistrrile, aa c nu va genera comenzi de
inserare, modificare sau tergere.

Figura 8.30. Sumarul generat de Data Adapter Configuration Wizard

153

Medii i Tehnologii de Programare curs

Cnd apsm comanda Finish, wizard-ul creeaz un nou adaptor i un nou obiect de tip
conexiune care va fi asociat adaptorului. Se vor seta proprietile DeleteCommand, InsertCommand,
SelectCommand i UpdateCommand ale adaptorului n concordan cu conexiunea la baza de date
pe care am selectat-o. De asemenea, se genereaz mapri iniiale ale tabelelor pentru a
transforma valorile din baza de date n valori pentru DataSet.
Configurarea unui adaptor de date este unul din paii necesari pentru utilizarea unui DataSet
n cadrul aplicaiei. Dup rularea wizard-ului, vei mai avea nevoie s adugai separat un
DataSet la aplicaia dumneavoastr i s scriei cod care s furnizeze pentru adaptorul de date
o modalitate de lucru cu DataSet-ul.

n versiunile anterioare ale Visual Studio, adaptoarele de date erau utilizate pentru
comunicarea dintre aplicaie i o baz de date. Dei adaptoarele de date sunt nc o
component de baz a .NET Framework Data Providers (ADO .NET), componentele
TableAdapter, generate automat de ctre designer, simplific procesul de
manipulare a datelor ntre o aplicaie i o baz de date.

8.7. Obiecte de tip Command


Clasele obiectelor de tip Command (OleDbCommand, SqlCommand, OdbcCommand i
OracleCommand) definesc comenzile pentru manipularea datelor dintr-o baz de date.
Acestea pot fi interogri SQL sau alte comenzi, cum ar fi INSERT, UPDATE, DELETE sau
CREATE TABLE.
Proprietatea Connection a obiectului furnizeaz conexiunea la baza de date pe baza creia se
vor executa comenzile. Proprietatea CommandText ofer textul SQL pe baza cruia se vor executa
comenzile.
Proprietatea CommandType va stoca tipul comenzii coninut de obiectul de tip Command. Acesta
poate fi:

StoredProcedure (CommandText va conine numele procedurii stocate)

TableDirect (CommandText va conine numele unuia sau mai multor tabele din care vor
fi furnizate datele)

Text (CommandText va conine comanda SQL).

n colecia Parameters a obiectului de tip Command vor fi stocai parametrii care vor defini
orice valoare necesar pentru a executa comanda. De exemplu, codul urmtor creeaz un
obiect de tip OleDbCommand care va executa comanda SQL "INSERT INTO Studenti (IDStudent,
Nume, Prenume) VALUES (?, ?, ?)". Semnele de ntrebare marcheaz locul parametrilor care
vor fi adugai mai trziu. Apoi se vor aduga n cod dou obiecte noi de tip OleDbParameter
la colecia Parameters a comenzii. Cnd n cod se invoca metoda ExecuteNonQuery(), adaptorul
nlocuiete semnele de ntrebare cu valorile parametrilor n ordinea n care apar n colecia
Parameters. n acest exemplu, valoarea din txtID.Text nlocuiete primul semn de ntrebare,
valoarea din txtNume.Text nlocuiete al doilea semn de ntrebare, iar valoarea txtPrenume.Text
al treilea semn de ntrebare.
private void btnAdauga_Click(object sender, EventArgs e)
{
// Deschide conexiunea
string conString = @"Provider=Microsoft.ACE.OLEDB.12.0;
Data source=D:\Work\Catalog.accdb;User ID=Admin;Password=;";
OleDbConnection connStudenti = new OleDbConnection(conString);
connStudenti.Open();

154

Baze de date n Visual C# .NET

// Creeaza un obiect Command pentru inserarea datelor


OleDbCommand cmd = new OleDbCommand(@"INSERT INTO Studenti(IDStudent,Nume,Prenume)
VALUES (?, ?, ?) ", connStudenti);
// Adauga parametrii pentru obiectul comanda
cmd.Parameters.Add(new OleDbParameter("IDStudent", txtID.Text));
cmd.Parameters.Add(new OleDbParameter("FirstName", txtNume.Text));
cmd.Parameters.Add(new OleDbParameter("LastName", txtPrenume.Text));
// Execut comanda
try
{
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
// Afiseaza datele
AfisareValori(connStudenti);
// Inchide conexiunea
connStudenti.Close();
connStudenti.Dispose();
}

Obiectele de tip Command ofer cteva metode utile (vezi Tabelul 8.31), dintre care trei
pentru executarea unor comenzi SQL.
Metod
ExecuteNonQuery()
ExecuteScalar()

ExecuteReader()

CreateParameter()
Prepare()

Descriere
Execut o comand care nu este o interogare i care nu returneaz nici o valoare.
Execut o comand i returneaz prima coloan din prima nregistrare gsit.
Este util atunci cnd se execut comenzi care returneaz o singur valoare (de
exemplu, "SELECT COUNT * FROM Studenti").
Execut o interogare SQL i returneaz un obiect de tip DataReader (de exemplu,
OleDbDataReader). Programul poate folosi acest obiect pentru a naviga printre
nregistrrile returnate.
Adaug obiecte noi la colecia Parameters a obiectului.
Compileaz comanda ntr-o form n care va fi executat mai rapid de baza de
date.
Tabelul 8.31. Metode utile ale obiectelor de tip Command

8.8. Obiectul DataSet


DataSet este cel mai important obiect folosit pentru stocarea n memorie a datelor dintr-o baz
de date. El ofer toate instrumentele pentru construirea, ncrcarea, manipularea i salvarea
datelor, ntr-un mod similar celui folosit la bazele de date relaionate. Un DataSet poate stoca
tabele multiple cu relaii complexe printe-copil i chei unice. Acesta ofer metode pentru
combinarea DataSet-urilor, cutarea de nregistrri care ndeplinesc un anumit criteriu, sau
pentru salvarea datelor n diferite moduri (baz de date relaionat sau fiier XML). Din multe
puncte de vedere, putem spune c un DataSet este o baz de date stocat n memorie, iar nu
pe disc.
Unul dintre cele mai rspndite moduri folosire a unui DataSet este ncrcarea, la pornirea
programului, a datelor dintr-o baz de date relaional i folosirea unor controale pentru
afiarea nregistrrilor. Utilizatorul va putea manipula datele interactiv, iar la sfrit, cnd

155

Medii i Tehnologii de Programare curs

programul i ncheie execuia, modificrile vor fi salvate n baza de date. Alte variante sunt
ncrcarea datelor dintr-un XML, respectiv construirea unui DataSet n memorie, fr
utilizarea unei baze de date. Programul poate folosi controale pentru a se conecta la DataSet
iar utilizatorul va putea vizualiza i manipula date complexe.
Secvena de cod prezentat n continuare creeaz i iniializeaz un DataSet i ncepe prin
crearea unui nou DataSet numit Catalog. Este creat apoi un DataTable numit Studenti, care
este adugat la colecia de tabele a DataSet-ului. Sunt adugate la coloanele obiectului
DataTable noi coloane: Nume, Prenume i IDStudent. Se seteaz apoi pe true proprietatea
Unique a coloanei IDStudent, astfel nefiind permise valori duplicate n coloana IDStudent.
Se creeaz apoi un vector de obiecte de tip DataColumn n care se introduc referinele ctre
coloanele Nume i Prenume. Acest vector este folosit pentru crearea unei constrngeri
UniqueConstraint adugat la colecia Constraints a tabelului. Prin aceasta se asigur c fiecare
pereche de Nume+Prenume este unic.
n mod similar se creeaz tabelul Note avnd coloanele IDStudent, Disciplina i Nota, apoi se
adaug o constrngere UniqueConstraint, astfel nct fiecare pereche IDStudent+Nota s fie
unic.
Este adugat o relaie ntre tabelul Studenti, coloana IDStudent i tabelul Note, coloana
IDStudent, dup care cele dou tabele sunt populate cu cteva nregistrri.
n final, programul ataeaz tabelele la dou controale DataGridView pentru afiarea
rezultatelor. Utilizatorul poate folosi controalele DataGridView pentru examinarea i
modificarea datelor, ca i cum ar fi fost ncrcate din baza de date.
private void Form1_Load(object sender, EventArgs e)
{
// Creeaza DataSet-ul.
DataSet dsCatalog = new DataSet("Catalog");
// Creeaza tabelul Studenti.
DataTable dtStudenti = dsCatalog.Tables.Add("Studenti");
// Adauga coloane la tabelul Studenti.
dtStudenti.Columns.Add("IDStudent", typeof(int));
dtStudenti.Columns.Add("Nume", typeof(string));
dtStudenti.Columns.Add("Prenume", typeof(string));
// Face campul IDStudent unic.
dtStudenti.Columns["IDStudent"].Unique = true;
// Face campul combinat Nume+Prenume unic.
DataColumn[] colNumePrenume = { dtStudenti.Columns["Nume"],
dtStudenti.Columns["Prenume"] };
dtStudenti.Constraints.Add(new UniqueConstraint(colNumePrenume));
// Creeaza tabelul Note.
DataTable dtNote = dsCatalog.Tables.Add("Note");
// Adauga coloane la tabelul Note.
dtNote.Columns.Add("IDStudent", typeof(int));
dtNote.Columns.Add("Disciplina", typeof(string));
dtNote.Columns.Add("Nota", typeof(int));
// Face campul combinat IDStudent/Disciplina unic.
DataColumn[] colStudentDisciplina = { dtNote.Columns["IDStudent"],
dtNote.Columns["Disciplina"] };
dtNote.Constraints.Add(new UniqueConstraint(colStudentDisciplina));
// Creeaza o relatie intre doua tabele prin campul IDStudent.
dsCatalog.Relations.Add("Studenti_Note", dtStudenti.Columns["IDStudent"],
dtNote.Columns["IDStudent"]);

156

Baze de date n Visual C# .NET

// Adauga cateva date ale studentilor.


dtStudenti.Rows.Add(new object[] { 1, "Popescu", "Ion" });
dtStudenti.Rows.Add(new object[] { 2, "Buga", "Cristina" });
dtStudenti.Rows.Add(new object[] { 3, "Popa", "Andrei" });
dtStudenti.Rows.Add(new object[] { 4, "Dumitru", "Ana" });
// Adauga si cateva note aleatoare.
Random nota = new Random();
dtNote.Rows.Add(new object[] { 1, "MTP",
dtNote.Rows.Add(new object[] { 2, "MTP",
dtNote.Rows.Add(new object[] { 3, "MTP",
dtNote.Rows.Add(new object[] { 4, "MTP",

nota.Next(5,
nota.Next(5,
nota.Next(5,
nota.Next(5,

10)
10)
10)
10)

});
});
});
});

// Ataseaza tabelele la controale DataGridView.


grdStudenti.DataSource = dtStudenti;
grdNote.DataSource = dtNote;
}

Tabelul 8.32 descrie cele mai folositoare proprieti ale obiectelor DataSet.
Proprietate
CaseSensitive

Descriere
Determin dac string-urile din DataTable sunt comparate case sensitive.

DataSetName

Numele DataSet-ului. Dac vom folosi reprezentarea XML, aceast


proprietate va seta numele elementului rdcin.

DefaultViewManager

Returneaz un obiect DataViewManager pe care l putem folosi pentru crea o


vizualizare personalizat a datelor din DataSet care s permit filtrare, cutare
i navigare.
Determin dac sunt respectate constrngerile la operaiile de actualizare a
datelor.

EnforceConstraints
HasErrors

Returneaz true dac sunt erori n vreunul din tabelele din DataSet.

Prefix

Returneaz sau seteaz un prefix XML ca alias pentru spaiul de nume al


DataSet-ului.
O colecie de obiecte de tip DataRelation care reprezint relaii printe-copil
ntre coloanele din diferite tabele.

Relations
Tables

O colecie de obiecte de tip DataTable care reprezint tabelele stocate n


DataSet.
Tabelul 8.32. Proprieti utile ale obiectelor DataSet.

Tabelul 8.33 descrie cele mai folosite metode ale obiectelor DataSet.
Metoda
AcceptChanges

Descriere
Opereaz toate modificrile care au fost fcute de la ncrcarea datelor sau de
cnd s-a apelat ultima oar AcceptChanges.

Clear
Clone

terge toate nregistrrile din toate tabelele din DataSet.


Efectueaz o copie a DataSet-ului, incluznd structura tabelelor, relaiile i
constrngerile, ns fr a include datele.
Efectueaz o copie a DataSet-ului, incluznd structura tabelelor, relaiile i
constrngerile, incluznd i datele.
Efectueaz o copie a DataSet-ului, n care vor fi copiate doar nregistrrile care
au fost modificate de la ncrcarea datelor sau de la ultima apelare a metodei
AcceptChanges().
Returneaz un string coninnd reprezentarea XML a datelor stocate n
DataSet.
Returneaz schema XML pentru reprezentarea XML a datelor stocate n
DataSet.
Returneaz true dac tabelele din DataSet conin modificri.
Adaug un DataSet, DataTable sau ir de obiecte DataRow la DataSet.
Citete datele din XML n DataSet.

Copy
GetChanges

GetXml
GetXmlSchema
HasChanges
Merge
ReadXml

157

Medii i Tehnologii de Programare curs

ReadXmlSchema
RejectChanges
WriteXml

Citete schema XML n DataSet.


Anuleaz toate modificrile fcute de cnd s-a ncrcat DataSet-ul sau de la
ultima apelare a metodei AcceptChanges().
Scrie datele din DataSet ntr-un XML.

WriteXmlSchema

Scrie structura DataSet-ului ntr-un fiier sub forma unei scheme XML.
Tabelul 8.33. Metode utile ale obiectelor DataSet.

Cteva dintre aceste metode sunt coninute i de ctre alte obiecte. De exemplu, metoda
HasChanges() returneaz true dac un tabel din DataSet conine modificri. Obiectele
DataTable i DataRow au de asemenea metoda HasChanges() care returneaz true dac acestea
conin modificri. Alte metode de acest fel ar mai fi AcceptChanges(), Clear(), Clone(), Copy(),
GetChanges() i RejectChanges().

8.9. Obiectul DataTable


Clasa DataTable reprezint datele dintr-un tabel din DataSet. Un obiect DataTable conine
obiecte de tip DataRow, pentru reprezentarea nregistrrilor, obiecte de tip DataColumn care
definesc coloanele tabelului, obiecte de tip Constraints i obiecte care reprezint relaiile
dintre tabele. Clasa DataTable ofer de asemenea metode i evenimente pentru manipularea
nregistrrilor.
Tabelul 8.34 descrie cele mai folosite proprieti ale obiectului DataTable.
Proprietate
CaseSensitive
ChildRelations

Descriere
Determin dac string-urile din DataTable sunt comparate case sensitive
O colecie de obiecte de tip DataRelation care definete relaii printe-copil,
unde tabelul este printele.

Columns

O colecie de obiecte de tip DataColumn care definete coloanele tabelului


(numele coloanei, tipul de date, valoarea implicita, lungime maxim etc.)

Constraints

O colecie de obiecte de tip Constraints care reprezint constrngerile asupra


bazei de date. ForeignKeyConstraint cere ca unele valori dintr-un tabel s fie
prezente n alt tabel. UniqueConstraint cere ca o valoare s fie unic ntr-un
tabel.
DataSet-ul care conine obiectul DataTable.
Returneaz un obiect DataView unde putem sorta i filtra sau cuta n
nregistrrile din tabel.

DataSet
DefaultView
HasErrors
MinimumCapacity

Returneaz true dac una din nregistrrile din DataTable conine o eroare.
Dimesiunea iniial a tabelului.

ParentRelations

O colecie de obiecte de tip DataRelation care definete relaii printe-copil,


unde tabelul este copilul.

Prefix

Spaiul de nume pentru reprezentarea XML a datelor din DataTable.

PrimaryKey
Rows
TableName

Un vector de coloane care funcioneaz ca chei primare ale tabelului.


O colecie de obiecte DataRow care conine nregistrrile din tabel.
Numele tabelului.
Tabelul 8.34. Proprieti utile ale obiectelor DataTable

Cele mai folosite metode ale obiectelor DataTable sunt prezentate n Tabelul 8.35:
Metoda
AcceptChanges()
Clear()

158

Descriere
Accept toate modificrile care au fost fcute de la ncrcarea datelor sau de la
ultima apelare a metodei AcceptChanges().
terge toate nregistrrile din DataTable.

Baze de date n Visual C# .NET

Clone()

Efectueaz o copie a DataTable, incluznd tabelele, relaiile i constrngerile,


fr a include ns datele.

Compute()

Calculeaz valoarea unei expresii folosind nregistrrile care satisfac condiiile


de filtrare.
Creeaz o copie a DataTable, incluznd tabelele, relaiile i constrngerile
incluznd datele.
Efectueaz o copie a DataTable, n care vor fi copiate doar nregistrrile
modificate.
Returneaz un ir de obiecte DataRow care conin erori.
Copiaz datele dintr-un DataRow n DataTable.
Caut i actualizeaz o anumit nregistrare. Dac nu este gsit nicio
nregistrare care s corespund valorilor transmise ca parametri, este creat o
nou nregistrare folosind valorile respective.

Copy()
GetChanges()
GetErrors()
ImportRow()
LoadDataRow()

NewRow()

Creeaz un obiect nou de tip DataRow care are aceeai schem cu a tabelului.

RejectChanges()

Anuleaz toate modificrile fcute de la ncrcarea datelor sau de la ultimul


apel al metodei AcceptChanges().

Select()

Returneaz un vector de obiecte DataRow care ndeplinesc criteriul de filtrare.


Tabelul 8.35. Metode utile ale obiectelor DataTable

Evenimentele cele mai folosite pentru obiectele DataTable sunt prezentate n Tabelul 8.36.
Eveniment
ColumnChanged

RowChanged

Descriere
Apare dup ce o valoare a fost modificat ntr-o anumit coloan dintr-o
nregistrare.
Apare n timp ce o valoare este modificat ntr-o anumit coloan dintr-o
nregistrare.
Apare dup ce o nregistrare a fost modificat cu succes.

RowChanging
RowDeleted
RowDeleting

Apare n timp ce este modificat o nregistrare.


Apare dup ce o nregistrare a fost tears.
Apare nainte ca o nregistrare s fie tears.

ColumnChanging

Tabelul 8.36. Evenimente utile ale obiectelor DataTable

159

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