Sunteți pe pagina 1din 52

Noiuni introductive n .

NET i C#
CUPRINS CURS 2-9 INTRODUCERE N C#.................................................................................................................................................. 2 PROGRAMAREA ORIENTAT PE OBIECTE - OOP (OBJECT ORIENTED PROGRAMMING).................................. 2 CLASE I OBIECTE ..................................................................................................................................................... 4 ORGANIZAREA CLASELOR I COMPORTAMENTUL ACESTORA ........................................................................... 5 MOTENIRE SIMPL SAU MULTIPL ........................................................................................................................ 6 COMPUNERE SAU MOTENIRE ................................................................................................................................ 9 CREAREA UNEI CLASE............................................................................................................................................... 9 TRANSMITEREA ARGUMENTELOR CTRE METODE............................................................................................ 15 CREAREA DE OBIECTE ............................................................................................................................................ 20 TIPURI DE DATE N .NET FRAMEWORK.................................................................................................................. 26 TIPURI FUNDAMENTALE .......................................................................................................................................... 26 TIPURI PRIMITIVE...................................................................................................................................................... 26 TIPURI REFERIN I TIPURI VALOARE ................................................................................................................ 27 TIPURI AUXILIARE..................................................................................................................................................... 33 TIPURI SEALED ......................................................................................................................................................... 33 TIPURI IMUTABILE..................................................................................................................................................... 34 CASTINGUL I CONVERSIA OBIECTELOR I TIPURILOR PRIMITIVE .................................................................. 34 CASTINGUL NTRE TIPURI PRIMITIVE..................................................................................................................... 35 CASTINGUL OBIECTELOR........................................................................................................................................ 35 CONVERSIA TIPURILOR PRIMITIVE N OBIECTE I INVERS................................................................................. 36 COMPARAREA OBIECTELOR................................................................................................................................... 36 DECLARAREA VARIABILELOR ................................................................................................................................. 36 OPERATORI ............................................................................................................................................................... 37 INSTRUCIUNI N C#................................................................................................................................................. 38 NAMESPACES ........................................................................................................................................................... 38 DELEGAI I EVENIMENTE ...................................................................................................................................... 39 COMPILATORUL C# .................................................................................................................................................. 42 OPTIMIZARE .............................................................................................................................................................. 42 ASSEMBLY-URI.......................................................................................................................................................... 43 PREPROCESOR ........................................................................................................................................................ 43 RESURSE................................................................................................................................................................... 43 DIVERSE .................................................................................................................................................................... 44 COLECII DE DATE ................................................................................................................................................... 44 INTERFEE N SYSTEM.COLLECTIONS .................................................................................................................. 45 IENUMERATOR I IDICTIONARYENUMERATOR .................................................................................................... 45 INTERFAA IENUMERABLE...................................................................................................................................... 46 ICOLLECTION ............................................................................................................................................................ 46 ILIST............................................................................................................................................................................ 47 IDICTIONARY ............................................................................................................................................................. 47 HASHTABLE............................................................................................................................................................... 48 DE REINUT ........................................................................................................................................................... 52

Curs M I- 2-3-4-5-6-7-8

Copyright by EBS Romania S.R.L.

Pagina 1 din 52

Noiuni introductive n .NET i C#


Introducere n C#.
Programare orientat pe obiecte o Clase i obiecte; o Modificatori de acces; o Constructori i destructori; o Metode. Overload, override, virtual; o Proprieti i indexatori; o Conceptul de motenire n C#. Compunere i motenire; o Interfee; o Clase concrete i abstracte; Tipuri de date n .NET Framework Tipuri fundamentale o Tipuri primitive o Tipuri referin i tipuri valoare Tipuri auxiliare o Tipuri sealed o Tipuri imutabile Casting; Declararea variabilelor; Operatori; Instruciuni n C#; Namespaces; Evenimente i Delegai; Compilatorul C#. Rularea programelor. Tablouri, Liste i Colecii o Array, ArrayList, BitArray o Colecii de date o Interfee n System.Collections C# (se pronun C arp) este un limbaj de programare simplu, modern, orientat obiect i Type-Safe (acces securizat la proprietile obiectelor). Programatorilor cu experien n C sau C++ le va fi foarte familiar. C# combin productivitatea nalt a limbajelor RAD (Rapid Application Development ) i facilitile oferite de C++. Programarea orientat pe obiecte - OOP (Object oriented programming) Programarea obiectual aduce cu siguran multe beneficii. S-a fcut mult vlv n jurul acestui concept, multora li se pare greu de neles, aa cum greu de ptruns este i utilitatea unei astfel de abordri. Dar pentru un programator care a creat prima aplicaie mai complex, beneficiile devin evidente. Programarea obiectual este de fapt a face ordine, a aduce claritate i limpezime, a face uor de neles, a crea perspective pentru dezvoltri ulterioare ntr-o activitate care devine tot mai complex i dinamic, cum este aceea de dezvoltare de aplicaii. n acest curs vor fi prezentate conceptele de baz ale OOP (Object-oriented programming), exemple create n C#, ncercndu-se o familiarizare cu acest stil de programare ca pas nainte fa de programarea procedural. Alan Kay a descris cinci caracteristici de baz ale Smalltalk-ului, primul limbaj de succes orientat obiect i unul din limbajele care stau la bazele C#. Aceste caracteristici reprezint chintesena programrii orientate obiect:
Curs M I- 2-3-4-5-6-7-8 Copyright by EBS Romania S.R.L. Pagina 2 din 52

Noiuni introductive n .NET i C#


1. Orice este un obiect. Un obiect este vzut ca o variabil oarecare, care stocheaz date, dar unui obiect i se pot adresa cereri de a executa anumite operaii asupra lui nsui. n teorie, poi lua orice component a problemei care se vrea rezolvat (cini, cldiri, servicii) i s o reprezini ca un obiect. 2. Un program este o colecie de obiecte, care i spun unul altuia ce s fac prin trimiterea de mesaje. Pentru a face o cerere la un obiect, trebuie s-i trimii un mesaj. Mai exact, mesajele pot fi vzute ca cereri de apel al unei funcii care aparine acelui obiect. 3. Fiecare obiect dispune de propria lui memorie construit din alte obiecte. Altfel spus, poi crea un nou tip de obiect prin crearea unui pachet care conine alte obiecte existente. Altfel, se pot crea programe de o complexitate ridicat, ascuns n spatele simplicitii obiectelor. 4. Fiecare obiect are un tip. Cu alte cuvinte fiecare obiect este o instan a unei clase, unde cuvntul clasa este sinonim cu cuvntul tip. Cea mai important caracteristic distinct a unei clase este: Ce mesaje i se pot trimite? 5. Toate obiectele de un anumit tip pot primi aceleai mesaje. Aceasta de fapt se subnelege, deoarece dac un obiect de tip Cerc este de asemenea i un obiect de tip forma geometric, atunci obiectul cerc sigur va accepta mesaje de tip forma geometric. Booch ofer chiar o descriere i mai succint a unui obiect:
An object has state, behaviour and identity (Un obiect are stare, comportament i identitate)

Acest lucru nseamn c un obiect poate avea date interne (de unde rezult starea lui), metode (care dau comportamentul obiectului) i fiecare obiect poate fi delimitat fa de oricare alt obiect, altfel spus fiecare obiect are o adres unic n memorie. Programarea orientat obiect este un concept remarcabil chiar dac n realitate nu este foarte modern, el aprnd ideatic nc din anii 70! Ideea central este destul de simpl i clar: organizai programele n aa fel, nct s oglindeasc modul cum sunt organizate obiectele din lumea real. Un program este privit n general ca o list de instruciuni care i spun calculatorului ce are de fcut. Un program este considerat de OOP drept un set de obiecte care lucreaz mpreun cu scopul de a ndeplini o sarcin. S lum ca exemplu un model practic extrem de ntlnit n aceste zile - construirea unui PC din diferite componente separate (plac de baz, plac video, procesor, etc.). Intern, fiecare dintre aceste componente poate fi extrem de complicat i complex, dar cel ce asambleaz ntregul nu are nevoie s tie exact detaliile de funcionare intern a fiecrei componente, ci doar cteva date foarte concrete: se vor potrivi aceste componente la nivel fizic? vor putea lucra mpreun din punct de vedere funcional aceste componente? Odat cunoscute interaciunile dintre componente, realizarea sistemului final va fi destul de simpl. Programarea orientat obiect se muleaz perfect pe exemplul anterior: programul nostru final se compune din mai multe componente obiecte care trebuie s interacioneze cu succes. Un obiect este un element independent al unui program, care reprezint un set de caracteristici corelate i este proiectat pentru a realiza anumite sarcini. Obiectele mai sunt numite i instane.

Curs M I- 2-3-4-5-6-7-8

Copyright by EBS Romania S.R.L.

Pagina 3 din 52

Noiuni introductive n .NET i C#


Clase i Obiecte O clas este un model (ablon) folosit pentru a crea mai multe obiecte cu aceleai caracteristici. Clasele nglobeaz toate caracteristicile unui anumit set de obiecte. Atunci cnd scriem un program ntr-un limbaj OOP, nu definim obiecte, ci clase de obiecte, acestea fiind modelele dup care se genereaz obiectele. Atunci cnd programul ruleaz din aceste clase sunt create obiecte, acestea fiind apoi folosite. Sarcina programatorului este de a crea seturile corecte de clase pentru ca programul s se comporte corespunztor. n practic, nici mcar nu trebuie pornit de la zero cu construcia claselor, deoarece .NET Framework SDK conine un grup de clase care implementeaz caracteristicile de baz de care au n general nevoie programatorii. Aceste grupe de clase se numesc biblioteci. O bibliotec de clase este un grup de clase proiectate pentru a fi folosite mpreun cu alte programe. Odat cu avansarea n programarea C#, se poate crea un set complet nou de clase care s aib definite anumite interaciuni ntre ele; acestea pot fi folosite pentru a se alctui eventual o bibliotec proprie de clase care poate fi reutilizat mai trziu n alte programe. Aceast capacitate de reutilizare este unul dintre avantajele majore ale programrii orientate obiect. ntre programatorii care lucreaz cu obiecte se disting programatori care creeaz clase i programatori de tip client, care folosesc aceste clase n aplicaiile proprii, pentru acetia fiind important s dispun de o suit de clase ct mai complete. Creatorii de clase ar trebui s expun n clasele pe care le construiesc doar elementele de care au nevoie programatorii client. De ce? Pentru c tot ceea ce este ascuns nu poate fi folosit din exterior i acele poriuni de cod pot fi schimbate fr a afecta utilizatorii clasei. Stabilirea acestui domeniu de vizibilitate se realizeaz prin folosirea unor modificatori de acces: PUBLIC, PRIVATE, PROTECTED i INTERNAL. Cnd o clas se definete ca fiind de tip PUBLIC, poate fi accesat de oricine, pe cnd dac este definit PRIVATE nu este accesibil dect intern. Modificatorul PROTECTED acioneaz ca i private, cu deosebirea c aceast clas este accesibil i din clasele derivate (subclase), iar o clas definit INTERNAL este accesibil din orice alt clas care face parte din acelai namespace. n C#, dac nu este specificat nici un modificator de acces, cel implicit este INTERNAL. Proprietile reprezint parametri individuali care difereniaz o clas de obiecte de o alta i care determin modul de prezentare, starea i alte caliti ale clasei. ntr-o clas proprietile sunt definite de variabile. Fiecare obiect poate avea valori diferite ale variabilelor sale; acestea se numesc variabile de instan. O variabil de instan este un element de informaie care definete proprietarul unui anumit obiect. Clasa obiectului definete ce fel de proprietate este i fiecare instan i pstreaz propria sa valoare pentru acea proprietate. Variabilele de instan mai sunt denumite i variabilele obiectului. Fiecrei proprieti a unei clase i corespunde o singur variabil; putem schimba proprietatea unui obiect modificnd aceast variabil. Variabilele de instan pot lua o valoare atunci cnd se creeaz un obiect ce rmne neschimbat pe toat durata lui de existen sau pot lua diferite valori pe msur ce obiectul este folosit. O alt proprietate este folosit pentru descrierea ntregii clase de obiecte, nu numai a unui singur obiect al clasei. Aceste proprieti sunt coninute n variabile de clas. O asemenea variabil se mai numete i STATIC. O variabil de clas este un element de informaie care definete proprietatea unei ntregi clase. Variabila se aplic nsi clasei i tuturor instanelor ei, deci este stocat o singur valoare, indiferent de cte obiecte ale clasei au fost create. Indexatorii sunt elemente care pot identifica un element ntr-o colecie. Am putea crede, la o prim vedere, c un astfel de rol l pot avea doar variabilele de tip ntreg (cum sunt indicii unui vector). Indexatori pot fi ns i string-urile i alte elemente.

Curs M I- 2-3-4-5-6-7-8

Copyright by EBS Romania S.R.L.

Pagina 4 din 52

Noiuni introductive n .NET i C#


De exemplu, n colecia de coloane a unei tabele putem identifica o anumit coloan i prin numele ei: DataTable.Columns[2] sau DataTable.Columns["Prenume"]. n definirea unei clase, un indexator se definete la fel ca o proprietate, cu diferena c numele acestei proprieti este ntotdeauna this:
public object this[int index] { get { if (!ValidIndex(index)) throw new Exception("Index in afara intervalului valid"); else return GetNode(index).Value; } set { if (!ValidIndex(index)) throw new Exception("Index in afara intervalului valid"); else GetNode(index).Value = value; } }

Comportamentul unei clase este modul n care clasele de obiecte pot face ceva cu ele nsele sau cu alte obiecte. Comportamentul unei clase determin ce obiecte ale clasei i modific proprietile, precum i ce fac ele atunci cnd alte obiecte le cer s fac ceva. Comportamentul unei clase de obiecte este determinat cu ajutorul metodelor. Metodele sunt grupuri de instruciuni dintr-o clas de obiecte, care acioneaz asupra acesteia sau asupra altor clase sau obiecte. Ele sunt folosite pentru a realiza diferite sarcini, n acelai fel n care n alte limbaje de programare se folosesc funciile. Obiectele comunic unele cu altele folosind metodele. O clas sau un obiect poate apela metode dintr-o alt clas sau obiect pentru mai multe motive: pentru a raporta o modificare unui alt obiect; pentru a comunica altui obiect s modifice ceva n legtur cu el; pentru a cere unui obiect s fac ceva. Aa cum exist variabile de instan i de clas, exist i metode de instan i de clas. Metodele de instan, numite i simplu metode, acioneaz asupra unui obiect al clasei. Dac o metod efectueaz schimbri doar asupra unui obiect individual, ea trebuie s fie o metod de instan. Metodele de clas acioneaz asupra clasei nsi. Organizarea claselor i comportamentul acestora Motenirea reprezint unul dintre cele mai importante concepte ale programrii OOP, avnd un efect direct asupra modului de proiectare i scriere a claselor noastre C#. Motenirea este un mecanism care permite unei clase s moteneasc comportamentul i atributele unei alte clase. Prin motenire, o clas dobndete imediat tot comportamentul unei clase existente. Din acest motiv, noua clas poate fi creat prin simpla specificare a diferenelor fa de clasa existent. Prin motenire, toate clasele sunt aranjate ntr-o ierarhie strict cele pe care le crem i cele provenite din biblioteca .NET Framework sau din alte biblioteci. O clas care motenete alt clas este denumit subclas sau clas derivat, iar clasa care i ofer motenirea se numete superclas sau clas de baz.
Curs M I- 2-3-4-5-6-7-8 Copyright by EBS Romania S.R.L. Pagina 5 din 52

Noiuni introductive n .NET i C#


O clas poate avea o singur superclas, poate avea ns un numr nelimitat de subclase. Subclasele motenesc toate proprietile i comportamentul superclaselor lor. n vrful ierarhiei de clase C# se afl clasa Object toate clasele motenesc aceast unic superclas. Object reprezint cea mai generica clas din ierarhie, care definete comportamentul i proprietile motenite de toate clasele din biblioteca .NET Framework . Fiecare clas aflat mai jos n ierarhie devine din ce n ce mai adaptat unui scop precis. O ierarhie de clase definete conceptele abstracte la vrful ierarhiei; aceste concepte devin din ce n ce mai concrete odat cu coborrea spre subclase. n mod normal, cnd crem o nou clas C#, dorim ca ea s prezinte toate caracteristicile unei clase existente, cu unele modificri. n paragrafele urmtoare vor fi definite 3 clase (FormaGeometric, Cerc i Cilindru), unde clasa Cerc a motenit clasa FormaGeometric, iar clasa Cilindru a motenit clasa Cerc, fiecare implementnd proprieti noi. Deci clasa Cerc este o subclas a clasei FormaGeometric, dar n acelai timp i o superclas pentru clasa Cilindru (exemplu suprascriere constructor). Subclasarea reprezint crearea unei noi clase, care motenete o clas existent. Singurul lucru care trebuie fcut n subclas este definirea diferenelor n comportament i proprieti fa de superclas. Cnd clasa noastr definete un comportament complet nou i nu este o subclas, atunci ea motenete direct clasa Object. Acest lucru i permite acesteia s se integreze corect n ierarhia claselor C#; n practic, dac definim o clas care nu specific o superclas, atunci C# presupune automat c noua clas motenete direct clasa Object. Atunci cnd crem un nou obiect, C# pstreaz urma fiecrei variabile definite pentru acel obiect i a fiecrei variabile definite pentru fiecare clas a obiectului. n acest fel, toate clasele se combin pentru a forma un model al obiectului curent, iar fiecare obiect i completeaz informaiile corespunztoare acestei situaii. Metodele se comport n acelai fel: noile obiecte au acces la toate metodele clasei i superclaselor de care aparin. Acest lucru este determinat dinamic, atunci cnd o metod este folosit ntr-un program aflat n execuie. Dac apelm o metod a unui anumit obiect, interpretorul C# verific mai nti clasa obiectului pentru a gsi acea metod. Dac metoda nu este gsit, interpretorul o caut n superclasa clasei i aa mai departe pn la gsirea definiiei metodei. Problema se complic atunci cnd o subclas definete o metod cu acelai nume, tip de rezultat i argumente care sunt definite i ntr-o superclas. n acest caz se folosete definiia metodei care este gsit prima (ncepnd din partea de jos a ierarhiei i mergnd n sus). Astfel, ntr-o subclas putem crea o metod cu acelai nume, tip de rezultat i argumente ca ale metodei din superclas; aceasta procedur se numete anulare prin suprascriere sau simplu suprascriere. Motenire simpl sau multipl Forma de motenire folosit n C# este denumit motenire simpl, deoarece fiecare clas C# poate avea o singur superclas. n alte limbaje de programare, i n C++, clasele pot avea mai multe superclase, motenind variabile i metode combinate din toate aceste superclase. Aceast form de motenire este denumit motenire multipl i ofer mijloace de creare a unor clase care cuprind aproape orice comportament imaginabil. Totui, acest lucru complic mult definiia clasei i a codului necesar pentru producerea acesteia. C# simplific acest concept permind doar motenirea simpl. Motenirea simpl face ca relaiile ntre clase i comportamentul pe care aceste clase l implementeaz s devin uor de neles i de proiectat. Ea poate fi ns restrictiv, mai ales atunci cnd avem un comportament similar care trebuie duplicat pe diferite ramuri ale ierarhiei de clase. C# rezolv aceast problem a comportamentului partajat prin folosirea interfeelor.
Curs M I- 2-3-4-5-6-7-8 Copyright by EBS Romania S.R.L. Pagina 6 din 52

Noiuni introductive n .NET i C#


O interfa este o colecie de metode care indic faptul c o clas are un anumit comportament suplimentar fa de ceea ce motenete de la superclasele sale. Tehnic vorbind, o interfa C# nu conine nimic altceva dect definiii de metode abstracte i constante, fr variabile de instan sau implementri de metode. Dac, de exemplu, avem clasele Articol, Autoturism i Strung, acestea vor putea fi privite la un moment dat din punct de vedere al unui contabil ca mijloace fixe. Toate acestea vor avea metode de calcul amortizare, reevaluare, etc. Pentru a rezolva aceast problem vom defini o interfa IMijlocFix cu metodele specifice, n felul urmtor:
public interface IMijlocFix { void CalculAmortizare(); void ModifcValoare(int suma); }

n definiiile claselor amintite vom specifica faptul c aceste clase implementeaz i interfaa IMijlocFix:
class Articol: IMijlocFix { void IMijlocFix.CalculAmortizare { // Cod specific pentru implementarea metodei n clasa Articol } void IMijlocFix.ModificValoare(int suma) { // cod specific pentru implementarea metodei n clasa Articol } }

n acelai mod se vor implementa metodele specifice interfeei i n celelalte clase. Este de reinut faptul c n definirea unei interfee nu se specific nimic referitor la coninutul metodelor i c o clas care implementeaz o interfa trebuie s conin n mod obligatoriu codul pentru implementarea fiecrei clase din interfa. O clas poate moteni (implementa) mai multe interfee, dar poate deriva o singur clas de baz (motenire simpl). Pentru definirea unor caracteristici comune ale unui set (sau unei ierarhii) de obiecte utilizeaz n multe situaii clasele abstracte. O clas abstract este o clas care conine doar definiii i care se vrea doar o clas de baz (superclas) pentru alte clase. O astfel de clas se definete folosind modificatorul abstract. Acest modificator poate defini clase, metode i proprieti. Clasele abstracte au urmtoarele caracteristici: O clas abstract nu poate fi instaniat; O clas abstract poate conine metode abstracte; Unei clase abstracte nu i se poate folosi modificatorul sealed, care determin ca o clas s nu poat fi motenit; O subclas derivat din clasa abstract trebuie s implementeze toate metodele abstracte motenite. O metod abstract nu conine implementri, care la rndul lor conin doar declaraii. O metod abstract este implicit i o metod virtual. Unei metode definite abstracte nu i se mai pot asocia urmtoarele cuvinte cheie: static, virtual sau override. De exemplu:
public abstract void MetodaMea();
Curs M I- 2-3-4-5-6-7-8 Copyright by EBS Romania S.R.L. Pagina 7 din 52

Noiuni introductive n .NET i C#


Metoda abstract va fi implementat doar n clasele derivate prin suprascriere. O clas abstract care implementeaz o interfa poate transpune n metode abstracte metodele interfeei. n urmtorul exemplu clasa SubClasa motenete clasa abstract SuperClasa. Clasa abstract conine o metod abstract MetodaMea i dou proprieti abstracte GetX() i GetY().
// claseAbstacte.cs abstract class SuperClasa // Clas Abstract { protected int x = 100; protected int y = 150; public abstract void MetodaMea(); // Metod Abstract public abstract int GetX // Proprietate Abstract { get; } public abstract int GetY // Proprietate Abstract { get; } } class SubClasa: SuperClasa { public override void MetodaMea() { x++; y++; } public override int GetX // suprascrierea proprietii { get { return x+10; } } public override int GetY // suprascrierea proprietii { get { return y+10; } } public static void Main() { SubClasa Clasa1 = new SubClasa(); Clasa1.MetodaMea(); Console.WriteLine("x = {0}, y = {1}", Clasa1.GetX, Clasa1.GetY); Console.Read(); } } /* Output x = 111, y = 161
Curs M I- 2-3-4-5-6-7-8 Copyright by EBS Romania S.R.L. Pagina 8 din 52

Noiuni introductive n .NET i C#


*/

Pentru a nelege conceptele de interfa i clas abstract (care n Visual Basic se definesc cu MustInherit) este necesar s facem cteva lmuriri suplimentare: o clas abstract poate conine i metode care nu sunt abstracte (deci poate conine cod pentru implementarea metodelor); dac se dorete suprascrierea unei astfel de metode ea trebuie declarat virtual; un obiect poate deriva o singur clas abstract, dar poate moteni mai multe interfee; dac modificm o clas abstract, toate modificrile se vor transfera automat n toate subclasele derivate. Acest fapt este util atunci cnd vom crea componente care au mai multe versiuni; modificarea unei interfee cere n mod obligatoriu modificarea tuturor claselor care motenesc interfaa respectiv (dac apare o metod nou este obligatorie implementarea ei n toate clasele care motenesc interfaa); interfeele sunt utile n special atunci cnd dorim s transpunem un anumit comportament unor obiecte foarte diferite (vezi exemplul de la interfee), obiecte care nu pot avea n ierarhia de moteniri o clas abstract comun (de ex. pentru dou clase de tip Tractor i Camion metodele comune pot fi descrise ntr-o clas de baz comun Autovehicol). Compunere sau motenire Comparai urmtoarele dou definiii:
class oLista { private int x; public ArrayList aList; } class oLista:ArrayList { private int x; }

n primul caz am creat o clas nou prin compunere, n al doilea am creat o clas prin motenire. Care ar fi diferenele ntre cele dou abordri? Iat cteva: prin motenire avem acces la detaliile interne de implementare ale clasei printe (elementele declarate protected), acest lucru nefiind posibil prin compunere; prin compunere se pot crea clase noi nglobnd funcionalitile mai multor clase, ceea ce nu este posibil prin motenire (motenire simpl); un obiect dintr-o clas compus poate fi nlocuit la run-time cu alt obiect de acelai tip; Crearea unei clase Precum am observat deja, o clas se definete folosind cuvntul cheie class. Acest cuvnt a fost pentru prima dat folosit n limbajul orientat obiect Simula-67.
public class Stiri { // corpul clasei }

Curs M I- 2-3-4-5-6-7-8

Copyright by EBS Romania S.R.L.

Pagina 9 din 52

Noiuni introductive n .NET i C#


n mod prestabilit, toate clasele motenesc clasa Object, care este superclasa tuturor claselor din ierarhia C#. Dac clasa este o subclas, folosim urmtoarea sintax pentru a indica superclasa noii clase:
public class StiriSportive: Stiri { // corpul clasei }

Atunci cnd crem o clas care motenete o superclas, trebuie precizat comportamentul noii clase, care o face s difere de superclasa sa. Acest comportament este definit prin specificarea variabilelor i metodelor noii clase. Variabilele de instan sunt declarate i definite asemntor celor locale. Principala diferen const n localizarea acestora n cadrul clasei, n afara metodelor, ca n exemplul de mai jos:
public class Dinozaur: Reptile { String culoare; String sex; bool flamand; int varsta; }

Pentru a obine valoarea unei variabile de instan vom folosi notaia cu punct. n aceast notaie, variabila de instan sau de clas este format din dou pri: obiectul, n partea stng a punctului i variabila, n partea dreapt. De exemplu, dac avem un obiect atribuit variabilei clientulMeu i acel obiect posed o variabil denumit totalFactura, atunci ne vom referi la aceast variabil astfel:
clientulMeu.totalFactura;

Aceast form de accesare a variabilelor este o expresie (deoarece ntoarce o valoare) n care de ambele pri ale punctului se afl tot expresii. Acest lucru nseamn c putem insera mai multe variabile de instan. Dac variabila totalFactura refer ea nsi un obiect, care posed propria variabil de instan numit rezervat, putem s ne referim la aceasta astfel:
clientulMeu.totalFactura.rezervat;

Expresiile cu punct sunt evaluate de la stnga spre dreapta, aa nct se va ncepe cu variabila din clientulMeu, totalFactura, care refer un alt obiect cu variabila rezervat. n final vom obine valoarea variabilei rezervat . Atribuirea unei valori acelei variabile se face pur i simplu prin utilizarea operatorului de atribuire:
clientulMeu.totalFactura.rezervat=true;

n continuare avem un exemplu simplu de accesare a variabilelor prin notaia cu punct:


public class DefinirePuncte { static void Main(string[] args) { System.Drawing.Point pozitie=new System.Drawing.Point(4,13); Console.WriteLine("Pozitia de inceput:"); Console.WriteLine("X egal "+pozitie.X); Console.WriteLine("Y egal "+pozitie.Y); Console.WriteLine("\nSe muta in (7,6)"); pozitie.X=7; pozitie.Y=6;
Curs M I- 2-3-4-5-6-7-8 Copyright by EBS Romania S.R.L. Pagina 10 din 52

Noiuni introductive n .NET i C#


Console.WriteLine("Pozitia finala:"); Console.WriteLine("X egal "+pozitie.X); Console.WriteLine("Y egal "+pozitie.Y); Console.Read();

} }

Variabilele de clas se aplic unei clase n ntregul su, nefiind stocate individual n obiectele (instanele) clasei. Variabilele de clas folosesc la comunicarea ntre diferite obiecte ale aceleiai clase sau pentru pstrarea unor informaii comune la nivelul ntregii clase. Pentru a declara o variabil de clas se folosete cuvntul cheie static, ca mai jos:
static int suma; static final int maxObiecte=10;

n cazul variabilelor de instan, fiecare nou instan primea o copie a variabilelor de instan definite n clas. Fiecare instan poate modifica apoi valorile acestor variabile fr a afecta alte instane. n cazul variabilelor de clas exist o singur copie a acesteia. Modificarea valorii sale este vizibil n toate instanele clasei. S lum de exemplu urmtoarea definiie de clas:
class MembruFamilie { static String numeFamilie="Popescu"; String prenume; int varsta; }

Instanele clasei noastre posed propriile valori pentru prenume i vrst, ns variabila de clas numeFamilie are o valoare comun pentru toi membrii familiei. Dac se modific valoarea acestei variabile, toate instanele clasei MembruFamilie vor fi afectate. Pentru accesarea acestor variabile de clas se folosete aceeai notaie cu punct. Pentru a obine sau modifica valoarea unei variabile de clas n partea stng a punctului folosim numele clasei. Dac folosim numele instanei, compilatorul va semnala o eroare:
class MembruFamilie { static String numeFamilie="Popescu"; String prenume; int varsta; public static void Main() { MembruFamilie tata=new MembruFamilie(); Console.WriteLine("Numele "+tata.numeFamilie); // Eroare: Static member 'exemple.MembruFamilie.numeFamilie' cannot be accessed with an instance reference; qualify it with a type name instead Console.WriteLine("Numele "+MembruFamilie.numeFamilie); } }

Variabilele sunt folositoare atunci cnd avem nevoie s pstrm informaii ce vor fi modificate pe parcursul rulrii programului. Dac valoarea nu se schimb niciodat pe parcursul execuiei programului, putem folosi un tip special de variabil, numit constant.
Curs M I- 2-3-4-5-6-7-8 Copyright by EBS Romania S.R.L. Pagina 11 din 52

Noiuni introductive n .NET i C#


O constant, denumit i variabil constant, este o variabil a crei valoare nu se modific niciodat. Constantele se folosesc pentru definirea valorilor comune pentru toate metodele unui obiect, cu alte cuvinte, pentru denumirea unor valori ce nu se vor schimba n cadrul obiectului. n C# putem crea constante pentru toate tipurile de variabile: de instan, de clas sau locale. Pentru a declara o constant folosim cuvntul cheie final nainte de declararea variabilei i atribuim valoarea iniial pentru variabila respectiv, ca n exemplele de mai jos:
final float pi=3.1415; final bool debug=false; final int telefon=8675309;

Constantele pot fi folositoare la denumirea diferitelor stri ale unui obiect sau la testarea acestor stri. Folosirea constantelor uureaz de cele mai multe ori nelegerea programului. Metodele definesc comportamentul unui obiect aciunile efectuate la crearea obiectului sau pe parcursul duratei sale de via. Clasele i obiectele ofer un cadru de lucru. Variabilele de instan i de clas ofer o modalitate de a defini ceea ce reprezint aceste clase i obiecte. Doar metodele pot defini comportamentul unui obiect, lucrurile pe care este capabil s le realizeze sau modul cum interacioneaz cu alte clase sau obiecte. O metod cuprinde patru pri: modificatori de acces; tipul obiectului sau tipul de date primitiv returnat de metod; numele metodei; o list de parametri; corpul metodei; Mai jos putem vedea o definiie general a unei metode:
modificator tipRetur numeMetoda(tip1 argument1, tip2 argument2, ) { // corpul metodei }

- modificator - poate fi unul din cuvintele cheie: public sau private. - tipRetur - poate fi un tip primitiv, un nume de clas sau cuvntul cheie void, atunci cnd metoda nu returneaz o valoare. n cazul n care metoda returneaz un obiect tablou, trebuie folosite parantezele ptrate fie dup tipRetur fie dup lista de parametri:
Private int[] creareDomeniu(int inf, int sup) { // corpul metodei }

Lista de parametri a metodei este un set de definiii de variabile, separate prin virgula i ncadrate ntre paranteze rotunde. Aceti parametri devin variabile locale n corpul metodei, primind valori la apelarea metodei. n afara cazurilor cnd este declarat cu tipul de retur void, o metod returneaz la terminarea sa o valoare de un anumit tip. Aceast valoare trebuie specificat explicit n punctele de ieire ale metodei, prin cuvntul cheie return. Mai jos avem un exemplu de clas care definete o metod care preia doi ntregi i creeaz un tablou care conine toate numerele ntregi aflate ntre cele dou limite:

Curs M I- 2-3-4-5-6-7-8

Copyright by EBS Romania S.R.L.

Pagina 12 din 52

Noiuni introductive n .NET i C#


public class ClasaDomeniu { private int[] creareDomeniu(int inf,int sup) { int[] tabl=new int[(sup-inf)+1]; for (int i=0;i<tabl.Length;i++) { tabl[i]=inf++; } return tabl; } [STAThread] public static void Main(string[] argumente) { int[] unTablou; ClasaDomeniu unDomeniu=new ClasaDomeniu(); unTablou=unDomeniu.creareDomeniu(1,10); Console.Write("Tabloul: [ "); for (int i=0;i<unTablou.Length;i++) { Console.Write(unTablou[i]+" "); } Console.Write("]"); } }

Metoda Main() a clasei apeleaz metoda creareDomeniu() pentru crearea unui domeniu mrginit inferior, respectiv superior, de valorile 1 i 10, dup care folosete un ciclu for pentru a afia valorile noului tablou . O aplicaie C# const n una sau mai multe clase ce pot avea orice dimensiune dorim. Singurul element de care avem neaprat nevoie pentru a rula o aplicaie C# este o clas care s serveasc drept punct de plecare pentru restul programului C#. Clasa de pornire a aplicaiei are nevoie de un singur lucru: o metod Main() care este prima metod apelat. Semntura metodei Main() arat astfel:
public static void Main(string[] argumente) {
// corpul metodei

public nseamn c metoda este disponibil altor clase i obiecte. Aceast declaraie poate lipsi; static nseamn c metoda Main() este o metod de clas; void nseamn c metoda Main() nu returneaz nici o valoare; aici poate fi i tipul int; Main() preia un parametru care este un tablou de iruri i se folosete pentru argumentele din linia de comand. Acest parametru poate lipsi; Pentru a transmite argumente unui program C# acestea trebuie adugate la execuie dup numele programului:
ProgramulMeu argument1 argument2

Pentru a transmite argumente care conin spaii acestea trebuie ncadrate de ghilimele. Atunci cnd o aplicaie este rulat cu argumente, C# le memoreaz sub forma unui tablou de iruri, pe care l transmite metodei Main() a aplicaiei. Pentru a putea trata aceste argumente drept altceva dect iruri trebuie mai nti s le convertim.
Curs M I- 2-3-4-5-6-7-8 Copyright by EBS Romania S.R.L. Pagina 13 din 52

Noiuni introductive n .NET i C#


Apelarea unei metode a unui obiect este asemntoare referirii variabilelor de instan: folosim notaia cu punct. Obiectul a crui metod o apelm este n stnga punctului, iar numele metodei i a argumentelor sale n dreapta:
clientulMeu.adaugInFactura(codProdus, pret);

Toate metodele sunt obligatoriu urmate de paranteze cu sau fr argumente. Dac metoda apelat returneaz un obiect care posed la rndul lui metode, putem imbrica metodele la fel ca la variabile. Urmtorul exemplu apeleaz metoda discutCuDirectorul(), care este definit n obiectul returnat de metoda anuleazToateComenzile(), care a fost definit n obiectul clientulMeu:
clientulMeu.anuleazToateComenzile().discutCuDirectorul();

Exemplificm folosirea unor metode definite n clasa String:


class VerificareSir { public static void Main(string[] argumente) { string str="In viata mea urmatoare, voi crede in reincarnare"; Console.WriteLine("Sirul este: "+str); Console.WriteLine("Lungimea sirului este:"+str.Length); Console.WriteLine("Subsirul de la 9 la 11: "+str.Substring(9,11)); Console.WriteLine("Indexul caracterului u: "+str.IndexOf("u")); Console.WriteLine("Indexul inceputului "+"subsirului \"voi\": " + Console.WriteLine("Sirul scris cu litere mari: "+str.ToUpper()); Console.Read();

str.IndexOf("voi"));

Metodele de clas, ca i variabilele de clas, se aplic unei clase n ntregul su i nu instanelor sale. Metodele de clas sunt utilizate de obicei drept metode de uz general, care nu pot opera direct asupra unei instane a clasei, dar se potrivesc conceptual n cadrul clasei. Metodele de clase pot fi de asemenea folositoare pentru adunarea unor metode generale ntr-un singur loc De exemplu, bibliotecile .NET Framework conin o clas denumit Math, care conine un set larg de operaii matematice definite ca metode de clase: Math.Abs(); Math.Sqrt(); Math.Asin(); Math.Round();
double radical=Math.Sqrt(10); Console.WriteLine("Radical din 10 este: {0}",radical); Console.WriteLine("Cel mai mare dintre x si y este:" +Math.Max(255,268));

Pentru a defini metode de clas se folosete cuvntul cheie static, poziionat n faa definiiei metodei, la fel ca n cazul definirii variabilelor de clas. De exemplu, metoda de clas Max(), folosit n exemplul precedent, ar putea avea urmtoarea semntur:
public static int Max(int arg1, int arg2) { // corpul metodei }

Platforma .NET Framework conine clase de mpachetare (wrapper) pentru fiecare dintre tipurile de baz. Lipsa cuvntului cheie static din faa numelui unei metode face ca aceasta s fie o metod de instan.

Curs M I- 2-3-4-5-6-7-8

Copyright by EBS Romania S.R.L.

Pagina 14 din 52

Noiuni introductive n .NET i C#


Cuvntul cheie this. n corpul unei definiii de metod putem s ne referim la obiectul curent obiectul a crui metod a fost apelat. Aceasta poate avea scopul de a folosi variabilele de instan ale obiectului su de a transmite obiectul curent ca argument unei alte metode. Pentru a referi obiectul curent n astfel de cazuri se folosete cuvntul cheie this acolo unde n mod normal s-ar folosi numele unui obiect. Acest cuvnt cheie se refer la obiectul curent i poate fi folosit oriunde poate aprea un obiect: n notaia cu punct, ca argument al unei metode, ca valoare de retur pentru metoda curent .a.m.d . Mai jos avem un exemplu de folosire a lui this:
t=this.x; // variabila de instana x pentru acest obiect this.resetDate(this); // apeleaza metoda resetDate() definita in clasa curenta si transmite obiectul curent return this; // returneaza obiectul curent

n multe cazuri s-ar putea s nu fie nevoie s utilizm explicit cuvntul cheie this, deoarece este presupus. De exemplu, putem s ne referim att la variabilele de instan ct i la apelurile de metode definite n clasa curent prin simpla folosire a numelui lor, deoarece this este implicit folosit n aceste referine:
t=x; // variabila de instan x pentru acest obiect resetDate(this);// apeleaz metoda resetDate() definit n clasa curent i transmite obiectul curent

Deoarece this este o referin a instanei curente a clasei, trebuie s o folosim doar n cadrul corpului unei definiii de metod de instan . Metodele de clas, declarate prin cuvntul cheie static, nu pot folosi this. Domeniul de vizibilitate este acea parte a programului n care o variabil sau o alt informaie poate fi folosit. Dac acea parte a programului care definete domeniul de vizibilitate al unei variabile i termin execuia, variabila nu mai exist. O variabil cu domeniu de vizibilitate local poate fi folosit doar n cadrul blocului n care a fost definit. Variabilele de instan i de clas posed un domeniu de vizibilitate extins la ntreaga clas, deci ele pot fi accesate de oricare dintre metodele din cadrul clasei. Atunci cnd referim o variabil n cadrul unei metode, C# verific existena definiiei acesteia mai nti n domeniul de vizibilitate local, dup aceea n domeniul exterior imediat urmtor i, n cele din urm, n domeniul metodei curente. Dac variabila nu este local, C# verific existena unei definiii a acesteia ca variabil de instan sau de clas n clasa curent. Dac nu se gsete definiia variabilei n clasa curent se caut pe rnd n fiecare superclas. Transmiterea argumentelor ctre metode Atunci cnd apelm o metod cu parametri de tip obiect, obiectele sunt transmise n corpul metodei prin referin. Orice vom face cu obiectele n cadrul metodei le va afecta direct. Aceste obiecte pot fi tablouri i alte obiecte coninute n tablouri. Atunci cnd transmitem un tablou ca argument ntr-o metod i coninutul lui se modific, este afectat tabloul original. Pe de alt parte tipurile de date primitive sunt transmise prin valoare. Relaia dintre variabilele de instan i cele de clas este comparabil cu diferena dintre modurile de lucru ale metodelor de instan i de clas. n alte limbaje, numele metodei numit i funcie, subrutin sau procedur este suficient pentru a o distinge de celelalte metode din program. n C#, n aceeai clas, putem folosi mai multe metode cu acelai nume, dar care difer prin valoarea returnat sau prin lista de parametri. Aceast practic este denumit suprancrcarea metodei (overloading). Metodele cu acelai nume se difereniaz ntre ele prin dou caracteristici: numrul argumentelor pe care le preiau; tipul datelor sau obiectelor fiecrui argument.
Curs M I- 2-3-4-5-6-7-8 Copyright by EBS Romania S.R.L. Pagina 15 din 52

Noiuni introductive n .NET i C#


Aceste dou caracteristici definesc semntura metodei. Folosirea mai multor metode cu acelai nume i semnturi diferite se numete suprancrcare. Suprancrcarea metodelor elimin nevoia de a defini metode complet diferite care s fac n principiu acelai lucru. Suprancrcarea face de asemenea posibil comportarea diferit a metodelor, n funcie de argumentele primite. Pentru a crea o metod suprancrcat ntr-o clas vom defini metode diferite, cu acelai nume ns cu liste de argumente diferite. Diferena poate consta n numrul de argumente, n tipul de argumente sau ambele. C# permite suprancrcarea metodelor att timp ct lista de argumente este unic pentru acelai nume de metod. Menionm c C# nu ia n considerare tipul valorii returnate pentru a face diferenierea metodelor suprancrcate. Dac ncercm s crem dou metode care difer doar prin tipul valorii de retur, vom obine o eroare nc de la compilare. n plus, numele variabilelor pe care le alegem pentru fiecare argument nu au importan tot ceea ce conteaz este numrul i tipul acestora. n continuare vom detalia un exemplu de metod suprancrcat. Vom crea nti o clas care definete o form rectangular cu patru variabile de instan pentru a preciza colurile din stnga-sus i dreapta-jos ale unui dreptunghi: x1, y1, x2, y2.
public class DreptunghiulMeu { int x1=0; int y1=0; int x2=0; int y2=0; }

Atunci cnd este creat o nou instan a clasei noastre, toate valorile vor fi iniializate cu 0. n continuare vom defini o metod care preia patru argumente ntregi i returneaz obiectul rectangular. Deoarece argumentele au acelai nume ca i variabilele de instan, n cadrul metodei vom folosi cuvntul cheie this pentru a referi variabilele de instan:
public DreptunghiulMeu ConstruireDreptunghi(int x1, int y1, int x2, int y2) { this.x1=x1; this.y1=y1; this.x2=x2; this.y2=y2; return this; }

O alt variant ar fi folosirea obiectelor Point n locul coordonatelor individuale. Pentru a implementa aceast variant putem suprancrca metoda noastr, astfel nct lista de argumente s conin dou obiecte Point:
public DreptunghiulMeu ConstruireDreptunghi(Point stangaSus, Point dreaptaJos) { x1=stangaSus.X; y1=stangaSus.Y; x2=dreaptaJos.X; y2=dreaptaJos.Y; return this; }

O alt modalitate de a defini un dreptunghi este de a folosi coordonatele colului din stnga-sus, mpreun cu valorile nlimii i limii sale:
public DreptunghiulMeu ConstruireDreptunghi(Point stangaSus, int l, int h) {
Curs M I- 2-3-4-5-6-7-8 Copyright by EBS Romania S.R.L. Pagina 16 din 52

Noiuni introductive n .NET i C#


x1=stangaSus.X; y1=stangaSus.Y; x2=(x1+l); y2=(y1+h); return this; }

Pentru a finaliza exemplul crem nc o clas, afiareDreptunghi(), care urmeaz s afieze coordonatele dreptunghiului i o metod Main(), care s apeleze toate aceste metode:
using System.Drawing; public class DreptunghiulMeu { int x1=0; int y1=0; int x2=0; int y2=0; public DreptunghiulMeu ConstruireDreptunghi(int x1, int y1, int x2, int y2) { this.x1=x1; this.y1=y1; this.x2=x2; this.y2=y2; return this; } public DreptunghiulMeu ConstruireDreptunghi(Point stangaSus, Point dreaptaJos) { x1=stangaSus.X; y1=stangaSus.Y; x2=dreaptaJos.X; y2=dreaptaJos.Y; return this; } public DreptunghiulMeu ConstruireDreptunghi(Point stangaSus, int l, int h) { x1=stangaSus.X; y1=stangaSus.Y; x2=(x1+l); y2=(y1+h); return this; } public void AfisareDreptunghi() { Console.Write("Dreptunghiul meu: <"+x1+", "+y1); Console.WriteLine(", "+x2+", "+y2+">"); } public static void Main(string[] argumente) { DreptunghiulMeu Dreptunghi=new DreptunghiulMeu(); Console.WriteLine("Apelam construireDreptunghi cu Dreptunghi.ConstruireDreptunghi(25,25,50,50); Dreptunghi.AfisareDreptunghi(); Console.WriteLine("***");
Curs M I- 2-3-4-5-6-7-8 Copyright by EBS Romania S.R.L. Pagina 17 din 52

coordonatele 25,25,50,50: ");

Noiuni introductive n .NET i C#


Console.WriteLine("Apelam construireDreptunghi cu punctele (10,10), Dreptunghi.ConstruireDreptunghi(new Point(10,10), new Point(20,20)); Dreptunghi.AfisareDreptunghi(); Console.WriteLine("***"); Console.Write("Apelam construireDreptunghi cu 1 punct (10,10),"); Console.WriteLine(" latime 50 si inaltime 50: "); Dreptunghi.ConstruireDreptunghi(new Point(10,10), 50, 50); Dreptunghi.AfisareDreptunghi(); Console.WriteLine("***"); Console.Read(); (20,20): ");

} }

Atunci cnd avem mai multe metode (din suprancrcarea uneia) i acestea fac lucruri asemntoare, ntr-o metod putem apela o alta. De exemplu, n cazul de mai sus, metoda construireDreptunghi, care primete ca argumente dou obiecte Point, poate fi nlocuit cu o versiune mult mai scurt:
public DreptunghiulMeu ConstruireDreptunghi(Point stangaSus, Point dreaptaJos) { return ConstruireDreptunghi(stangaSus.X, stangaSus.Y, dreaptaJos.X, dreaptaJos.Y); }

Suprascrierea metodelor (overriding) nseamn crearea unei definiii diferite pentru o metod care a mai fost definit n superclas. Atunci cnd apelm metoda unui obiect, C# caut definiia metodei respective n clasa obiectului. Dac nu o gsete, caut mai sus n ierarhia de clase pn cnd gsete o definiie. Procesul de motenire a metodelor ne permite s definim i s folosim repetat metode n subclase fr a fi nevoie s replicm codul. Totui, pot exista cazuri cnd dorim ca un obiect s rspund acelorai metode, dar s aib un comportament diferit la apelarea acestora. n acest caz, metoda se poate suprascrie. Pentru a suprascrie o metod, definim ntr-o subclas o metod cu aceeai semntur ca a unei metode dintr-o superclas. Astfel, atunci cnd metoda este apelat, metoda din subclas este gsit prima i executat n locul celei din superclas. Pentru ca o metod s poat fi suprascris ea trebuie s fie declarat abstract, virtual sau s fie suprascris n superclas. Deci, dac o clas conine mai mult de o definiie, un ir de metode abstracte, i dorim ca metodele scrise n clas s poat fi suprascrise n eventualii descendeni, va trebui ca metodele acestea s fie declarate virtuale (cuvntul cheie virtual). Pentru a suprascrie o metod, trebuie s crem n practic o metod cu aceeai semntur (nume, tip, valoare returnat, list de argumente) ca a metodei din superclas. Mai jos crem un exemplu pentru a ilustra suprancrcarea unei metode:
class AfisareClasa { protected int x=0; protected int y=0; public void AfisareDate() { Console.WriteLine("x este "+x+" si y este "+y); Console.WriteLine("Sunt o instana a clasei "+this.GetType().Name); Console.Read(); } }

Curs M I- 2-3-4-5-6-7-8

Copyright by EBS Romania S.R.L.

Pagina 18 din 52

Noiuni introductive n .NET i C#


Crem n continuare i o subclas a clasei de mai sus, cu o singur diferen, subclasa conine i variabila z:
class AfisareSubClasa: AfisareClasa { int z=3; public static void Main(string[] argumente) { AfisareSubClasa obiect=new AfisareSubClasa(); obiect.AfisareDate(); }

Deoarece subclasa nu definete o metod afiareDate(), C# o caut n superclas i o gsete acolo pentru a o putea executa. Aceast metod ns nu afieaz i variabila de instan z. S crem o nou subclas care s suprascrie metoda afiareDate():
class AfisareSubClasa2: AfisareClasa { int z=3; public void AfisareDate() { Console.WriteLine("x este "+x+" si y este "+y+" iar z este "+z); Console.WriteLine("Sunt o instana a clasei "+this.GetType().Name); Console.ReadLine(); } public static void Main(string[] argumente) { AfisareSubClasa2 obiect=new AfisareSubClasa2(); obiect.AfisareDate(); } }

Acum, dup iniializarea obiectului AfiareSubClasa2 i apelarea metodei afiareDate() va fi apelat versiunea existent n subclas i nu cea din superclasa AfiareDate. Compilatorul semnaleaz c metoda din clasa printe nu va mai fi vizibil, deoarece este ascuns de implementarea din clasa curent i sugereaz folosirea cuvntului cheie new n faa metodei:
new public void AfisareDate() { }

De obicei exist dou motive pentru care se face suprascrierea unei metode implementate deja de o superclas: pentru a nlocui complet definiia metodei originale; pentru a extinde funcionalitatea metodei originale. n multe cazuri practice, comportamentul metodei originale trebuie doar completat i nu nlocuit definitiv, mai ales n cazurile cnd se realizeaz acelai tip de aciuni i n metoda original i n cea care o suprascrie. Prin apelarea metodei originale n cadrul metodei de suprascriere putem aduga numai nsuirea suplimentar. Pentru a apela metoda original n cadrul metodei de suprascriere folosim cuvntul cheie base. n acest fel apelul metodei este transferat mai sus n cadrul ierarhiei de obiecte:
public void metodaMea (string a, string b) {
Curs M I- 2-3-4-5-6-7-8 Copyright by EBS Romania S.R.L. Pagina 19 din 52

Noiuni introductive n .NET i C#


//cod sursa base.metodaMea(a,b); //cod sursa

Cuvntul cheie base este asemntor cuvntului cheie this, deoarece este o denumire generic pentru superclasa clasei curente. l putem folosi oriunde am putea folosi i this, ns base refer superclasa, nu clasa curent. S ne amintim de cele dou metode afiareDate() diferite, folosite anterior. n loc s copiem majoritatea codului metodei superclasei n subclas, putem modifica metoda superclasei, astfel nct ulterior s se poat aduga cu uurin o caracteristic suplimentar:
// din afisare clasa public void AfisareDate() { Console.WriteLine("x este "+x+" si y este "+y); Console.WriteLine("Sunt o instana a clasei "+this.GetType().Name); Console.Read(); }

Cnd suprascriem metoda afiareDate() n subclas, putem apela metoda original i aduga doar codul suplimentar:
// din AfisareSubClasa2 new public void AfisareDate() { base.AfisareDate(); Console.WriteLine("z este "+z);}

Crearea de obiecte

n cele mai multe situaii vom folosi clasele pentru a crea instane i vom lucra cu aceste instane. n exemplele precedente am ntlnit o instan a clasei String creat prin folosirea unui literal (string):
string Nume="Popescu";

Celelalte clase C# nu au aceast posibilitate de creare a unui nou obiect. Crearea de noi instane ale acestora se face explicit cu operatorul new. Pentru a crea un nou obiect folosim operatorul new mpreun cu numele clasei, dup modelul creia dorim s crem o instan i de paranteze (ntre care se pot gsi eventual argumente):
String numeEchipa = new String(); Dinozaur j = new Dinozaur();

Parantezele sunt foarte importante: n cazul n care nu conin argumente, se creeaz cel mai simplu obiect, n cazul n care exist argumente ntre ele, acestea determin valorile iniiale ale variabilelor de instan sau ale altor caliti iniiale ale obiectului respectiv:
Point pct=new Point(12,12);

Numrul i tipul argumentelor pe care le folosim ntre paranteze mpreun cu operatorul new sunt definite la definiia clasei folosind o metod special denumit constructor. Dac ncercm s crem o nou instan a clasei folosind un numr greit de argumente sau un tip eronat al acestora, vom obine erori la compilarea programului. La folosirea operatorului new se creeaz o nou instan a clasei date, se aloc memorie pentru aceasta i se apeleaz constructorul.

Curs M I- 2-3-4-5-6-7-8

Copyright by EBS Romania S.R.L.

Pagina 20 din 52

Noiuni introductive n .NET i C#


Constructorii reprezint metode pentru crearea i iniializarea noilor instane ale claselor. Constructorii iniializeaz noul obiect i variabilele sale, creeaz orice alte obiecte de care are nevoie obiectul creat i realizeaz orice alte operaii de care obiectul are nevoie la iniializarea sa. ntr-o clas pot exista mai multe definiii de constructori, fiecare avnd un numr diferit de argumente sau tipuri. Atunci cnd folosim operatorul new, putem specifica diferite argumente n lista de argumente i va fi apelat constructorul corespunztor pentru acele argumente. La crearea unei clase putem defini orici constructori avem nevoie pentru implementarea comportamentului clasei. Spre deosebire de alte metode, o metod constructor nu poate fi apelat direct, C# apeleaz metodele constructor n mod automat. Atunci cnd este folosit instruciunea new pentru crearea unui nou obiect, se executa trei activiti: 1. aloc memorie pentru obiect; 2. iniializeaz variabilele de instan ale obiectului fie la valorile iniiale fie la cele prestabilite (o pentru numere, null pentru obiecte, false pentru valori booleene i \0 pentru caractere); 3. apeleaz metodele constructor ale clasei. Chiar dac o clas nu are definit nici o metod constructor, este totui posibil crearea unui obiect. Exist ns cazuri n care dorim s setm anumite variabile de instan sau s apelm alte metode de care obiectul are nevoie pentru a se iniializa. Prin definirea unor metode constructor n clase, putem seta valorile iniiale ale variabilelor de instan, putem apela metode pe baza acestor variabile, putem apela metode ale altor obiecte sau putem seta proprietile iniiale ale unui obiect. Metodele constructor pot fi i ele suprancrcate, la fel ca metodele obinuite, pentru a crea un obiect care are proprieti specifice, n funcie de argumentele transmise prin instruciunea new. Constructorii seamn cu metodele obinuite, cu dou diferene: metodele constructor au ntotdeauna acelai nume cu cel al clasei; metodele constructor nu returneaz nimic. n exemplul de mai jos vom vedea o clas Persoana, care folosete o metod constructor pentru a-i iniializa variabilele de instan pe baza argumentelor primite de new:
public class Persoana { string nume; int varsta; Persoana (string n, int a) { nume=n; varsta=a; } void printPersoana() { Console.Write("Eu sunt "+nume); Console.WriteLine(" si am "+varsta+" de ani"); } [STAThread] public static void Main(string[] argumente) { Persoana p; p=new Persoana("Ion",50);
Curs M I- 2-3-4-5-6-7-8 Copyright by EBS Romania S.R.L. Pagina 21 din 52

Noiuni introductive n .NET i C#


p.printPersoana(); Console.WriteLine("----"); p=new Persoana("Laura",30); p.printPersoana(); Console.WriteLine("----"); Console.Read();

Dac avem o metod constructor care prezint un comportament oarecum asemntor cu cel al unui constructor existent, putem apela primul constructor din interiorul celui de-al doilea. C# ofer o sintax special pentru a realiza acest lucru. Folosim urmtoarea instruciune pentru a apela o metod constructor definit n clasa curent:
this(arg1, arg2, arg3);

Folosirea cuvntului cheie this ntr-o metod constructor este similar modului lui de folosire pentru accesul la variabilele de instan ale obiectului. n instruciunea anterioar, argumentele primite de this() sunt argumentele metodei constructor. S lum spre exemplu o clas care definete un cerc folosind coordonatele (x, y) ale centrului i lungimea razei. Clasa CerculMeu poate avea doi constructori: unul n care este definit raza i unul n care raza primete valoarea prestabilit 1:
public class CerculMeu { int x,y,raza; CerculMeu (int coordX, int coordY, int lungRaza) { this.x=coordX; this.y=coordY; this.raza=lungRaza; } CerculMeu (int coordX, int coordY): this(coordX, coordY, 1) { } }

Al doilea constructor din clasa CerculMeu preia doar coordonatele x i y ale cercului. Deoarece nu este definit nici o raz, se folosete valoarea prestabilit 1; se apeleaz apoi prima metod constructor care primete ca argumente coordX, coordY i literalul 1. Suprancrcarea constructorilor. Ca i metodele obinuite constructorii pot avea un numr diferit de argumente i/sau tipuri diferite de argumente. Aceasta ne permite s crem un obiect cu proprietile dorite sau ofer acestuia posibilitatea de a-i calcula proprietile pornind de la date de intrare diferite. Acest lucru a fost deja ilustrat n exemplul anterior. Suprascrierea constructorilor. Din punct de vedere tehnic constructorii nu pot fi suprascrii. Pentru c au ntotdeauna acelai nume ca al clasei curente, metodele constructor nu se motenesc, ci se creeaz altele noi. Acest sistem este mulumitor n marea majoritate a cazurilor; atunci cnd este apelat metoda constructor a clasei, se apeleaz i metoda constructor cu aceeai semntur pentru toate superclasele. Din aceast cauz iniializarea se face pentru toate prile clasei pe care o motenim. Totui, atunci cnd definim metode constructor pentru clasa noastr, putem modifica felul n care este iniializat obiectul nu doar prin iniializarea noilor variabile adugate clasei, ci i prin modificarea coninutului variabilelor deja prezente. Pentru aceasta vom apela explicit metodele constructor ale superclasei i apoi vom modifica variabilele dorite.

Curs M I- 2-3-4-5-6-7-8

Copyright by EBS Romania S.R.L.

Pagina 22 din 52

Noiuni introductive n .NET i C#


Pentru a apela o metod obinuit aparinnd superclasei vom folosi sintaxa: base.nume_metoda(lista_argumente). Deoarece metodele constructor nu au nume sub care pot fi apelate, vom folosi urmtoarea form:
base(arg1, arg2, ...);

Dac nu apelm base() explicit n cadrul constructorului, C# face acest lucru implicit, folosind base() (fr argumente). La fel ca n folosirea this(...) ntr-o metod constructor, base(...) apeleaz metoda constructor pentru superclasa imediat urmtoare (care la rndul su va apela constructorul superclasei sale i aa mai departe). Reinem c n superclas trebuie s existe un constructor cu semntura respectiv pentru ca apelul base() s funcioneze. Compilatorul C# verific aceste lucruri atunci cnd ncercm s compilm fiierul surs. Nu trebuie s apelm constructorul din superclasa care are aceeai semntur cu cea a constructorului clasei noastre; trebuie doar s apelm constructorul pentru valorile pe care dorim s le iniializm. De fapt, putem crea o clas care are constructori cu semnturi total diferite de oricare dintre constructorii superclasei. n exemplul urmtor vom prezenta o clas Cerc, care extinde clasa FormaGeometrica. Clasa FormaGeometrica are un constructor care preia ca argumente 3 integer (x,y,z) i returneaz un obiect FormaGeometrica. Clasa Cerc conine o variabil de instan suplimentar i definete un constructor care iniializeaz raza i numele. Ex. suprascriere constructor:
using System; abstract class FormaGeometrica { public const double pi = Math.PI; protected double x, y, z; public FormaGeometrica (double x, double y, double z) { this.x = x; this.y = y; this.z = z; } } public abstract double Suprafata();

class Cerc: FormaGeometrica { private string Nume=""; public Cerc(double raza): base(raza,0,0) { } public Cerc(double raza, string nume): base(raza,0,0) { this.Nume=nume; } public override double Suprafata() { return pi*x*x; } public string NumeCerc
Curs M I- 2-3-4-5-6-7-8 Copyright by EBS Romania S.R.L. Pagina 23 din 52

Noiuni introductive n .NET i C#


{ get { } return Nume;

} } class Cilindru: Cerc { public Cilindru(double raza, double inaltime): base(raza) { y = inaltime; } public override double Suprafata() { return 2*(base.Suprafata()) + 2*pi*x*y; }

} class TestClass { public static void Main() { double raza = 2.5, inaltime = 3.0; Cerc Cerc1 = new Cerc(raza,"Cercul circumscris"); Cilindru Cilindru1 = new Cilindru(raza, inaltime); Console.WriteLine("Suprafata '{0}' este = {1:F2}",Cerc1.NumeCerc, Cerc1.Suprafata()); Console.WriteLine("Suprafata cilindrului= {0:F2}", Cilindru1.Suprafata()); Console.Read();

} }

Metoda constructor definit aici pentru Cerc apeleaz metoda constructor a clasei FormaGeometrica pentru a iniializa variabila de instan x, (y i z sunt iniializate cu 0). Clasa Cerc are doi constructori, unul dintre ei primete i parametrul nume care iniializeaz variabila de instan nume. Metodele de finalizare sunt opusul metodelor constructor i se mai numesc i destructori. O metod constructor este folosit pentru a iniializa un obiect, iar metodele de finalizare sunt apelate chiar nainte de distrugerea obiectului i recuperarea memoriei ocupate. Destructorii sunt folosii de obicei pentru optimizarea distrugerii unui obiect, de exemplu pentru distrugerea referinelor ctre alte obiecte. n cadrul destructorilor, putem specifica toate aciunile de curare pe care dorim s le realizm n legtur cu obiectul. Destructorii nu pot fi motenii i, din moment ce nu primesc nici un parametru, nu pot fi nici suprancrcai. Destructorii nu pot fi apelai direct, ci sunt apelai automat n momentul n care nu mai exist nici o referin ctre respectivul obiect. Cnd un obiect este distrus, sunt apelai automat toi destructorii ierarhiei de clase din care face parte respectivul obiect. Exemplul urmtor exemplific folosirea destructorilor:
class A { ~A() { Console.WriteLine("Destructorul clasei A ");
Copyright by EBS Romania S.R.L. Pagina 24 din 52

Curs M I- 2-3-4-5-6-7-8

Noiuni introductive n .NET i C#


} } class B: A { ~B() { }

Console.WriteLine("Destrucorul clasei B");

} public class ExempluDestructori { public static void Main() { B b = new B(); b = null; GC.Collect(); GC.WaitForPendingFinalizers(); Console.Read(); } }

Clasa Object definete o metod virtual de finalizare prestabilit, care nu face nimic (este vid) i care se numete Finalize(). Destructorii sunt implementai prin suprascrierea acestei metode Finalize(). Totui, programatorilor C# nu le este permis s o suprascrie sau s o apeleze direct. De aceea urmtorul exemplu genereaz dou erori de compilare:
class A {

override protected void Finalize() {} // error public void F() { this.Finalize(); // error }

Compilatorul se comport ca i cum aceast metod nu exist de loc i o suprascrie. Astfel, urmtorul exemplu este corect i metoda Finalize din System.Object este expus:
class A { }

void Finalize() {}

// corect

n marea majoritate a cazurilor practice ns, nu este nevoie s folosim deloc metoda explicit finalize(). Gestionarea memoriei n C# se face dinamic i automat. Atunci cnd crem un obiect nou, C# aloc automat o zon de memorie de dimensiunea corespunztoare obiectului. Nu trebuie s alocm explicit memorie pentru obiecte. Deoarece gestionarea memoriei se face automat, nu este nevoie s eliberm memoria ocupat de obiect atunci cnd am terminat de lucrat cu acesta. Atunci cnd am terminat lucrul cu un obiect, acesta nu mai posed nici o referin activ ctre el (nu va mai fi atribuit nici unei variabile pe care o folosim sau nu va mai fi stocat n vreun tablou). Platforma .NET SDK posed un instrument de fcut curat numit garbage collector care caut obiectele nefolosite i recupereaz memoria ocupat de acestea. Nu trebuie s eliberm explicit acea zon de memorie.

Curs M I- 2-3-4-5-6-7-8

Copyright by EBS Romania S.R.L.

Pagina 25 din 52

Noiuni introductive n .NET i C#


Tipuri de date n .NET Framework
Orice discuie despre un limbaj de programare trebuie s cuprind i descrierea tipurilor de date pe care limbajul respectiv le pune la dispoziia programatorilor pentru crearea de aplicaii. n C# exist tipuri de date fundamentale i auxiliare.

Tipuri fundamentale
Modelul obiectual al .NET Framework poate fi schiat n felul urmtor: C# Tipuri fundamentale de date

Common Intermediate Language (CIL)

Common Type System (CTS) Virtual Object System (VOS) Common Language Runtime

Tipurile fundamentale de date n C# nu sunt dect imagini ale Common Type System, astfel nct s fie permis interoperabilitatea cross-language: un tip de dat definit n C#, spre exemplu, poate fi utilizat n orice alt limbaj compatibil .NET Framework. n momentul execuiei, un tip de dat C# devine practic un tip din Common Type System. n C# exist trei tipuri fundamentale de date: tipuri primitive, tipuri referin i tipuri valoare. Tipuri primitive Sunt numite astfel, deoarece sunt folosite frecvent. Compilatorul permite manipularea lor cu o sintax simplificat: asociaz fiecrui tip primitiv tipul corespunztor descris n Base Class Library (BCL). Ex. 2.1
/* Urmtoarele dou linii de cod sunt echivalente */ System.String trueStr = System.Boolean.TrueString; string trueStr = bool.TrueString;

Curs M I- 2-3-4-5-6-7-8

Copyright by EBS Romania S.R.L.

Pagina 26 din 52

Noiuni introductive n .NET i C#


Tipurile primitive din C# sunt prezentate n tabelul urmtor. Tip Tip BCL primitiv n C# sbyte System.Sbyte byte System.Byte short System.Int16 ushort System.UInt16 int System.Int32 uint System.UInt32 long System.Int64 ulong System.Uint64 char System.Char float System.Single double bool decimal Descriere

object string

Numr ntreg (cu semn) reprezentat pe 8 bii. Numr natural reprezentat pe 8 bii. Numr ntreg (cu semn) reprezentat pe 16 bii. Numr natural reprezentat pe 16 bii. Numr ntreg (cu semn) reprezentat pe 32 bii. Numr natural reprezentat pe 32 bii Numr ntreg (cu semn) reprezentat pe 64 de bii. Numr natural reprezentat pe 64 de bii. Caracter Unicode reprezentat pe 16 bii. Numr real cu virgul mobil, reprezentat pe 32 bii (precizie simpl). Compatibil cu standardul IEEE 754. System.Double Numr real cu virgul mobil reprezentat pe 64 bii (precizie dubl). Compatibil cu standardul IEEE 754. System.Boolean O valoare: True sau False System.Decimal Numr real folosit n calcule financiare (care utilizeaz numere mari i care nu permit rotunjiri). Valoare minim admis pentru acest tip este -296 i valoare maxim este 296. Orice instan a acestui tip se reprezint binar sub forma ((-296 pn la 2 96) / 10 (0 pn la 28)). System.Object Tipul Object, clas de baz pentru toate tipurile. System.String Tipul String

Tipuri referin i tipuri valoare nelegerea diferenelor dintre tipurile referin i tipurile valoare are o importan deosebit (I believe that a developer who misunderstands the difference between reference types and value types will introduce subtle bugs and performance issues into their code (Jeffrey Richter, MSDN Magazine, Decembrie 2000)). Modelul obiectual al platformei .NET este descris de Virtual Object System (VOS). Exist dou reguli importante descrise de acest model, care ne intereseaz n acest moment: Orice obiect deriv (direct sau indirect) din tipul System.Object. Nu este permis motenirea multipl. C# este limbajul reprezentativ pentru Microsoft .NET Framework i bineneles c aceste reguli se aplic i n cazul nostru.
Ex. 2.2 // Urmtoarele definiii de tipuri sunt identice class MyClass { //... } class MyClass : System.Object { //...
}

n C# exist o ierarhie a tipurilor, n care:


Curs M I- 2-3-4-5-6-7-8 Copyright by EBS Romania S.R.L. Pagina 27 din 52

Noiuni introductive n .NET i C#


Nodul rdcin este System.Object. Orice alt tip X este: o Fie un nod intern al ierarhiei, care permite unui alt tip Y s moteneasc pe X (de ex. clasa System.Windows.Forms.Form). o Fie un nod frunz al ierarhiei, care nu permite nici unui alt tip Y s l moteneasc (spre exemplu, clasa System.String). n figura de mai jos sunt exemplificate cteva ramuri din ierarhia de tipuri existente n C#. Vom reveni asupra acestei figuri n paragrafele urmtoare. System.Object (rdcina)

System.String (nod frunz) System.ValueType (nod intern)

System.Net.EndPoint (nod intern)

System.DateTime (nod frunz)

System.Int32 (nod frunz)

System.Net.IPEndPoint (nod intern)

Pentru a putea descrie tipurile referin i tipurile valoare, precum i diferenele care apar ntre aceste tipuri, vom analiza pe scurt urmtoarele cuvinte cheie din C#: class, interface, delegate, enum, struct i namespace. Cuvnt cheie class interface delegate enum struct namespace Descriere Definete un tip referin (clas) Declar un tip referin (interfa) Definete un tip referin (un delegat este utilizat pentru a ncapsula o metod cu o anumit semntur) Declar un tip valoare (enumerare) Definete un tip valoare (structur) Declar un domeniu de tipuri (referin sau valoare).

Declaraii / Definiii Un tip referin este declarat / definit utiliznd doar cuvintele cheie class, interface i delegate. Un tip valoare este declarat / definit utiliznd cuvintele cheie enum i struct.
Ex. 2.3 using System;

Curs M I- 2-3-4-5-6-7-8

Copyright by EBS Romania S.R.L.

Pagina 28 din 52

Noiuni introductive n .NET i C#


// Declararea unui domeniu de tipuri global-unice namespace Domeniu { // Declararea unei interfee interface IDomeniu { void Write (EDomeniu aState); } // Declararea unei clase abstracte abstract class ACDomeniu { protected EDomeniu state; public event DDomeniu StateChanged; public abstract void Write (); public void changeInternalState () { state = EDomeniu.Sleeping; this.StateChanged (); } } // Definirea unei clase class CDomeniu : ACDomeniu { public CDomeniu () { state = EDomeniu.Working; base.StateChanged += new DDomeniu (Write); } public override void Write () { Console.WriteLine ("Internal state: {0}.", state); } ~CDomeniu () { base.StateChanged -= new DDomeniu (Write); Console.WriteLine ("One CDomeniu object destroyed"); } } // Declararea unui delegat public delegate void DDomeniu (); // Declararea unui tip valoare enumerativ public enum EDomeniu { Working, Sleeping } // Definirea unui tip valoare public struct SDomeniu : IDomeniu { public EDomeniu state; public void Write (EDomeniu aState) { Console.WriteLine ("Received state: {0}.", aState); } public static void Smth () {
Curs M I- 2-3-4-5-6-7-8 Copyright by EBS Romania S.R.L. Pagina 29 din 52

Noiuni introductive n .NET i C#


CDomeniu obj = new CDomeniu (); Console.WriteLine ("*****<CDomeniu>*****"); ACDomeniu acObj = obj; acObj.Write (); acObj.changeInternalState (); Console.WriteLine ("*****</CDomeniu>*****"); SDomeniu val = new SDomeniu (); Console.WriteLine ("*****<IDomeniu>*****"); IDomeniu iObj = val; iObj.Write (val.state); Console.WriteLine ("*****</IDomeniu>*****"); } public static void Main () { SDomeniu.Smth (); Console.ReadLine (); } } }

Instanierea tipurilor n C# Singurele tipuri care pot fi instaniate sunt cele definite (clasele i delegaii tipuri referin i structurile tipuri valoare). O instan a unui tip referin este numit obiect i o instan a unei structuri este numit valoare sau obiect cu tip valoare. Observaie Clasele declarate cu modificatorul abstract sunt doar parial definite, n sensul c ele pot fi utilizate doar ca tipuri de baz pentru alte clase. Astfel de clase nu pot fi instaniate. Obiecte i valori n C#. Creare i stocare Vom utiliza urmtoarele notaii: MH (Managed Heap) este zona de memorie (COM+) n care sunt alocate obiectele. MM (Memory Manager) este o component din Common Language Runtime (CLR), care gestioneaz lucrul cu MH n .NET Framewok. GC (Garbage Collector) este un motor apelat de MM n momentul n care se decide o aciune de curare a MH. n principal, scopul aciunii de curare este de a elibera din MH referinele care nu mai pot fi accesate. ST este stiva firului de execuie curent, pe care se aloc valorile.
Ex. 2.4 // Definirea unui tip referin class CDomeniu : ACDomeniu { //... } // Definirea unui tip valoare public struct SDomeniu { //... }
Curs M I- 2-3-4-5-6-7-8 Copyright by EBS Romania S.R.L. Pagina 30 din 52

Noiuni introductive n .NET i C#


// Instanierea unui tip referin: obinem o variabil de tip referin, ce adreseaz un obiect CDomeniu obj = new CDomeniu (); // Instanierea unui tip valoare: obinem o valoare sau o variabil de tip valoare SDomeniu val = new SDomeniu ();

Un obiect este creat cu operatorul new (instruciunea MSIL Microsoft Intermediate Language corespunztoare este newobj). Din punctul de vedere al gestionrii memoriei, mediul de lucru .NET este auto-controlat (managed); programatorul nu poate cura manual o zon de memorie (nu exist nici un operator dual pentru new). Cnd se utilizeaz new pentru instanierea unui tip referin, se realizeaz dou operaii majore: Alocare. Se aloc pe MH numrul de octei necesari pentru a reprezenta tipul obiectului. Suplimentar, pot fi configurai anumii octei pentru componente, cum ar fi tabela virtual (v-table). Iniializare. Sunt iniializai membrii obiectului. Operatorul new ntoarce adresa la care s-a alocat un obiect. n exemplul de mai sus, variabila obj este o adres la biii de stare ai obiectului proaspt alocat pe MH; obj poart numele de variabil de tip referin (vtr). O instan a unui tip valoare se obine fie prin new, fie doar declarnd o variabil de acel tip. Spre deosebire de un obiect, o valoare nu este alocat pe MH, ci pe ST. n exemplul de mai sus, variabila val va conine chiar biii de stare ai obiectului alocat pe ST; val este numit variabila de tip valoare (vtv). Obiecte i valori n C#. Discuii legate de performan n general, manipularea valorilor implic performane sporite. Cteva dintre aceste situaii sunt: 1. De fiecare dat cnd se utilizeaz o variabil de tip valoare (vtv), se acceseaz direct datele (biii de stare). n schimb, lucrul cu o variabil de tip referin (vtr) implic mai nti o derefereniere a unui pointer i abia apoi lucrul efectiv cu date, ceea ce implic o dimensiune a codului mai mare i o vitez de execuie sczut. 2. Valorile sunt alocate pe ST i obiectele sunt alocate pe MH. Este posibil ca n timpul unei aciuni de alocare, MM-ul s considere c nu exist suficieni octei n MH i s apeleze GC-ul. Mai mult, obiectele trebuie eliminate din MH atunci cnd nu mai pot fi utilizate. Limitri ale tipurilor valoare Dac lucrul cu tipuri valoare se dovedete a fi mai eficient, de ce s nu folosim doar astfel de tipuri? Rspunsul este c tipurile valoare au un comportament bazat pe obiecte (object based), iar tipurile referin au un comportament orientat pe obiecte (object oriented). Tipurile valoare nu ofer o interconectivitate adevrat ntre tipurile C#: Nu pot fi motenite (sunt noduri frunz n ierarhia de tipuri - System.Boolean, System.Int32 n exemplul de mai sus); Motenesc implicit (i definitiv) System.ValueType, clasa care deriv direct din System.Object. Acest comportament nu poate fi schimbat, n sensul c nu putei specifica o alt clas de baz pentru un tip valoare. Oricum, aa cum s-a vzut n exemplul 3 de cod, structurile pot mprumuta comportamentul specificat de o interfa. Comportamentul bazat pe obiecte asigur doar parial ncapsularea, abstractizarea, motenirea, polimorfismul i reutilizarea codului, adic tot ce este mai frumos n lumea orientat obiect. Dar utilizarea unui tip valoare trebuie s fie ntotdeauna o opiune serioas pentru programatori.

Curs M I- 2-3-4-5-6-7-8

Copyright by EBS Romania S.R.L.

Pagina 31 din 52

Noiuni introductive n .NET i C#


Boxing & Unboxing O noutate n .NET Framework este modul n care tipurile sunt reprezentate: mpachetate (boxed) sau despachetate (unboxed). Mecanismul de mpachetare (boxing) permite unei valori V s se comporte ca un obiect: este alocat un obiect O pe MH i se copiaz biii de stare ai valorii n obiectul alocat. Sistemul marcheaz pe O ca fiind un wrapper (o form mpachetat a unei valori), astfel nct s se permit i procedeul invers, de despachetare (unboxing). Deoarece doar asupra wrapper-elor se poate aplica procedeul de unboxing (sunt marcate!), este clar c tipurile referin nu pot fi reprezentate n forma despachetat. Tip Valoare Referin
Ex. 2.5 SDomeniu val1st = new SDomeniu (); // Boxing object obj = val1st; // Unboxing SDomeniu val2nd = (SDomeniu) obj; Console.WriteLine ("Sunt egale? Raspuns: {0}", val2nd.Equals (val1st));

Boxed Da Da (Nativ) Da (Nativ) Nu

Unboxed

System.Object Dup cum am menionat anterior, aceast clas este rdcina ierarhiei tipurilor n .NET Framework. Orice alt tip definit de BCL (Base Class Library) sau de programator este derivat, n cele din urm, din System.Object. Clasa System.Object, prin comportamentul specificat, definete serviciile primare ale unui obiect. System.ValueType Aceast clas este clasa de baz pentru toate tipurile valoare definite n BCL (Base Class Library) sau de programator. Demonstrm acest lucru prin secvenele de cod 2.6 i 2.7.
Ex. 2.6 // Cele dou definiii de tip sunt echivalente public struct MyValueType { //... } public struct MyValueType : System.ValueType { //... } Ex. 2.7 // Definiia de mai jos produce o eroare de compilator: "type n interface list is not an interface" public struct MyValueType : System.Object { //... }

Curs M I- 2-3-4-5-6-7-8

Copyright by EBS Romania S.R.L.

Pagina 32 din 52

Noiuni introductive n .NET i C#


Eroarea de compilator generat n exemplul 2.7 este evident. Implicit i definitiv, un tip valoare (n cazul nostru MyValueType) este derivat din System.ValueType. Dar cum se ajunge la aceast eroare? 1. n momentul n care ncercm s derivm MyValueType din System.Object, compilatorul de C# cunoate faptul c tipul definit de noi motenete deja clasa System.ValueType. 2. Mai mult, compilatorul nc nu a evaluat tipul System.Object. Evaluarea are loc abia dup ce este construit lista de interfee (LI) pe care MyValueType trebuie s le implementeze. 3. Deoarece motenirea multipl nu este permis de modelul descris de VOS, compilatorul consider c System.Object este o interfa i adaug acest tip n LI. Eventual, dac vor exista i alte tipuri (separate de virgul) dup System.Object, compilatorul le va aduga n LI, pn cnd LI va cunoate forma sa final. 4. n sfrit, compilatorul va evalua tipurile. n LI (interface list), System.Object (type) nu este o interfa. Am reuit s ne dm seama singuri, cuvnt cu cuvnt, de eroarea pe care am comis-o. Trebuie s recunoatem c erorile de compilator semnalate aici sunt cu adevrat sugestive! Clasa System.ValueType, prin comportamentul specificat, definete serviciile primare ale unei valori.

Tipuri auxiliare
Sunt tipuri valoare sau referin (deci nu sunt tipuri hibride), cu unele proprieti specifice. Din aceast categorie fac parte tipurile sealed i tipurile imutabile. Tipuri sealed n ierarhia tipurilor .NET Framework, tipurile sealed reprezint nodurile frunz. Prin urmare, aceste tipuri nu pot fi superclase pentru alte tipuri (nu pot fi derivate). Exemple de astfel de tipuri sunt System.String i System.DateTime.
Ex. 2.8
// cs_sealed_keyword.cs // Sealed classes using System; sealed class MyClass { public int x; public int y; } class MainClass { public static void Main() { MyClass mC = new MyClass(); mC.x = 110; mC.y = 150; Console.WriteLine("x = {0}, y = {1}", mC.x, mC.y); } } Output x = 110, y = 150

Dac n exemplul precedent se ncerca motenirea clasei MyClass prin folosirea unei instruciuni ca: class MyDerivedC: MyClass {} // eroare, rezulta urmtorul mesaj de eroare: 'MyDerivedC' cannot inherit from sealed class 'MyBaseC'.

Curs M I- 2-3-4-5-6-7-8

Copyright by EBS Romania S.R.L.

Pagina 33 din 52

Noiuni introductive n .NET i C#


Tipuri imutabile O instan a unui tip imutabil (immutable) nu deine membri care s poat s i schimbe valoarea (mutatori). Din punctul de vedere al transmiterii parametrilor, tipurile imutabile sunt interesante, deoarece au comportamentul asemntor cu tipurile valoare, dar nu pot fi scrise ca tipuri valoare. Prin urmare, un tip imutabil este un tip referin imutabil. Exemple: System.String, System.Text.RegularExpressions.Regex. Atunci cnd lucrm cu obiecte, un lucru important de neles l reprezint folosirea referinelor. O referin este un tip de pointer folosit pentru a indica valoarea unui obiect. Atunci cnd atribuim un obiect unei variabile sau transmitem un obiect ca argument pentru o metod nu folosim de fapt obiecte. Nu sunt folosite nici mcar copii ale obiectului. De fapt folosim referine ctre acele obiecte.
using System; using System.Drawing; class TestReferinte { public static void Main(string[] arg) { SolidBrush br1,br2; br1=new SolidBrush(Color.Red); br2=br1; br1.Color=Color.White; Console.WriteLine("Culoare 1: " + br1.Color); Console.WriteLine("Culoare 2: " + br2.Color);

} }

Dei, la o prim vedere variabilele pt1 i pt2 ar trebui s aib valori diferite, nu este aa. Variabilele x i y pentru pt2 au fost i ele schimbate, chiar dac n program nu se vede nimic explicit. Motivul este c n linia 6 s-a creat o referin de la pt2 la pt1, n loc s se creeze pt2 ca un nou obiect, copiat din pt1. Pt2 este o referin la acelai obiect ca i pt1. Oricare dintre variabile poate fi folosit pentru a referi obiectul sau pentru a-i modifica variabilele. Dac am fi vrut ca pt1 i pt2 s se refere obiecte separate, ar fi trebuit folosite instruciuni new Point() separate n liniile 5 i 6: pt1=new Point(100,100); pt2=new Point(100,100); Folosirea referinelor n C# devine i mai important atunci cnd transmitem argumentele metodelor . Castingul i conversia obiectelor i tipurilor primitive Atunci cnd transmitem argumente metodelor sau cnd folosim variabile n expresii, trebuie s folosim variabile cu tipuri de date corespunztoare. Dac metoda creat necesit un int, compilatorul C# rspunde cu eroare dac ncercm s transmitem o valoare float. La fel, dac ncercm s setm o variabil cu valoarea alteia, ele trebuie s fie de acelai tip. Uneori obinem ntr-un program C# o valoare care nu este de tipul necesar. Poate fi dintr-o alt clas sau dintr-un tip de dat necorespunztor cum ar fi float cnd avem nevoie de un int. Pentru a nltura acest neajuns trebuie s folosim casting-ul. Casting-ul reprezint procesul de generare a unei valori de un alt tip dect sursa. Atunci cnd efectum un cast, valoarea variabilei nu se schimb; de fapt se creeaz o noua variabil de tipul dorit.
Curs M I- 2-3-4-5-6-7-8 Copyright by EBS Romania S.R.L. Pagina 34 din 52

Noiuni introductive n .NET i C#


Chiar dac conceptul de casting este relativ simplu, folosirea sa este destul de complicat de faptul c C# posed att tipuri primitive (int, float, boolean, etc.) ct i tipuri obiect (String, ZipFile, Point etc.). Exist trei tipuri de cast i de conversie despre care vom vorbi: castingul ntre tipuri primitive (int float, float-double, etc.); castingul ntre o instan a unei clase i o instan a altei clase; conversia tipurilor primitive n obiecte i apoi extragerea valorilor primitive din aceste obiecte. Castingul ntre tipuri primitive Cea mai des ntlnit situaie este n cazul tipurilor numerice. Exist un tip de date primitiv, care nu poate fi niciodat folosit pentru cast; variabilele booleene sunt fie true, fie false i nu pot fi folosite ntr-o operaie de cast. n multe operaii de cast, ntre tipuri primitive, destinaia poate stoca valori mai mari dect sursa, astfel nct valoarea s fie convertit cu uurin. Un exemplu ar fi castingul unui byte la int. Deoarece byte-ul stocheaz informaii ntre -128 i 127, iar un int informaii ntre -2.1 milioane i 2.1 milioane, este loc mai mult dect suficient pentru a face cast de la byte la int. De multe ori putem folosi automat un byte sau un char drept un int; putem folosi un int drept un long, un int drept un float sau orice drept un double. n majoritatea cazurilor, deoarece tipul de dimensiuni mai mari ofer mai mult precizie dect cel cu dimensiuni mai mici, nu apare nici o pierdere de informaie. Excepia apare atunci cnd facem un cast de la ntregi la valori n virgula mobil castingul unui int sau al unui long ntr-un float sau al unui long ntr-un double poate duce la pierderi ale preciziei. Trebuie s folosim un cast explicit pentru a converti o valoare mai mare ntr-una mai mic, deoarece conversia valorii poate duce la o pierdere de precizie. Cast-urile explicite au sintaxa: (numetip)valoare numetip este numele tipului de dat ctre care facem conversia; valoare reprezint o expresie care are ca rezultat valoarea tipului surs. Castingul obiectelor Instanelor claselor li se poate aplica operaia de cast ctre instane ale altor clase, cu o restricie: clasele surs i destinaie trebuie s fie nrudite prin motenire. O clas trebuie s fie subclas a alteia. Asemntor conversiei unei valori primitive ctre un tip de dimensiuni mai mari, unele obiecte nu au nevoie de cast explicit. n particular, deoarece subclasele conin toate informaiile superclasei lor, putem folosi o instan a unei subclase oriunde se ateapt folosirea unei superclase. De exemplu, s lum o metod care preia dou argumente: unul de tip Object i altul de tip System.Windows.Forms. Putem transmite o instan a oricrei clase drept argument Object (deoarece toate clasele C# sunt subclase ale clasei Object); pentru argumentul System.Windows.Forms putem transmite i instane ale subclaselor sale (cum ar fi FileDialog, OpenFileDialog). Reciproca este i ea adevrat; putem folosi o superclas acolo unde se ateapt o subclas. Exist totui n acest caz o problem deoarece subclasele au un comportament mai complex dect superclasele lor, exist o pierdere de precizie. Acele obiecte superclas s-ar putea s nu posede ntregul comportament necesar pentru a putea aciona n locul obiectului subclas. Pentru a folosi obiecte superclas acolo unde se ateapt obiecte subclas, trebuie s facem cast explicit. Nu vom pierde nici o informaie prin cast, dar vom ctiga toate metodele i variabilele pe care le definete subclasa. Pentru a face cast pentru un obiect dintr-o alt clas folosim aceeai operaie ca i n cazul tipurilor primitive: (numeclasa)obiect numeclasa este numele clasei destinaie, iar obiect este o referin ctre obiectul surs. Reinem c operaia de cast creeaz o referin ctre vechiul obiect, de tip numeclasa; vechiul obiect continu s existe ca i nainte .

Curs M I- 2-3-4-5-6-7-8

Copyright by EBS Romania S.R.L.

Pagina 35 din 52

Noiuni introductive n .NET i C#


n exemplul de mai jos putem vedea un cast de la o instan a clasei VicePresedinte ctre o instan a clasei Angajat; VicePresedinte este o subclas a clasei Angajat, cu informaii suplimentare care definesc faptul c VicePresedinte are anumite drepturi suplimentare:
Angajat ang=new Angajat(); VicePresedinte vip=new VicePresedinte(); ang=vip; //nu este nevoie de cast de jos in sus vip=(VicePresedinte)ang; // e nevoie de cast explicit

n afar de castingul obiectelor ctre clase putem de asemenea face castingul obiectelor ctre interfee ns numai dac clasa obiectului respectiv sau una dintre superclasele sale implementeaz de fapt interfaa. Castingul unui obiect ctre o interfa nseamn c putem apela una dintre metodele interfeei, chiar dac clasa obiectului nu implementeaz de fapt interfaa. Conversia tipurilor primitive n obiecte i invers Unul dintre lucrurile pe care nu le putem face n nici un caz este un cast ntre un obiect i un tip de date primitiv sau invers. Tipurile primitive i obiectele sunt lucruri foarte diferite n C# i nu putem face cast automat ntre cele dou sau s le folosim unul n locul celuilalt. Ca alternativ, .NET Framework conine clase care corespund fiecrui tip de date primitive: Integer, Float, Bool, .a.m.d. Remarcm faptul c numele acestor clase ncep cu litera mare. C# trateaz foarte diferit tipurile de date i versiunile clas ale acestora; programele nu se vor compila cu succes dac se folosesc una n locul celeilalte. O conversie de care este adesea nevoie n programe este conversia unui ir ntr-un tip numeric, cum ar fi un ntreg. Acest lucru se poate face cu metoda parseInt a clasei Integer, ca n exemplul de mai jos:
string nume="12000"; int numar=Int32.Parse(nume);

Compararea obiectelor Aceast operaie se realizeaz n C# cu ajutorul operatorilor == i !=. Atunci cnd sunt folosii cu obiecte, aceti operatori nu realizeaz ceea ce ne-am atepta. n loc de a verifica dac unul dintre obiecte are aceeai valoare cu celalalt obiect, ele determin dac obiectele sunt de fapt acelai obiect. Pentru a compara instanele unei clase i a obine rezultate folositoare trebuie implementate metode speciale n cadrul clasei i apoi apelate aceste metode. Declararea variabilelor O variabil este un spaiu de memorare a unei informaii. Orice variabil are un tip prin care se specific ce fel de informaii se pstreaz n acea variabil. La declararea unei variabile se specific tipul, numele i, opional, o valoare iniial. Orice variabil trebuie s primeasc o valoare nainte de a se face o referire la ea. Construcia
class Test { static void Main() { int a; int b = 1; int c = a + b; } }

// aici se genereaz eroare

va genera o eroare, deoarece variabila a nu a fost iniializat.


Curs M I- 2-3-4-5-6-7-8 Copyright by EBS Romania S.R.L. Pagina 36 din 52

Noiuni introductive n .NET i C#


Atunci cnd vorbim de obiecte, ne referim de fapt la variabilele asociate instanelor claselor/structurilor sau direct claselor/structurilor (dac este vorba de clase statice). n declaraia unei variabile mai poate intra specificarea unui modificator de acces (public, protected, private, internal). Cteva exemple de definiii de variabile:
int y = 150; private bool y; public bool gata = false; protected System.ComponentModel.Container components = null; private readonly string txtMesaj;

O variabil este vizibil numai n domeniul n care a fost definit! Secvena urmtoare va genera o eroare: if (i==0) {string msg = Zero;} Console.WriteLine(msg); Operatori n C# exist trei tipuri de operatori: unari, binari i operatori de conversie. Cunoatem c un operator returneaz o valoare n urma operaiilor asupra operanzilor. Ca efect secundar se poate schimba i valoarea unora din operanzi. O categorisire a operanzilor C# poate fi gsit n urmtorul tabel: Categorie operatori Aritmetici Logici i pe bii Concatenare Incrementare, decrementare Deplasare Relaionali Atribuire Acces membri Indexatori Conversie Condiional Concatenare i retragere delegates Creare obiecte Informaii despre tip Control al excepiilor de depire Adres i indirectare Operatori + - * / % & | ^ ! ~ && || true false + ++ -<< >> == != < > <= >= = += -= *= /= %= &= |= ^= <<= >>= . [] () ?: + new is sizeof typeof checked unchecked * -> [] &

Curs M I- 2-3-4-5-6-7-8

Copyright by EBS Romania S.R.L.

Pagina 37 din 52

Noiuni introductive n .NET i C#


Instruciuni n C# Majoritatea instruciunilor n C# sunt mprumutate din C sau C++. Ceea ce s-a urmrit n primul rnd a fost ca limbajul s fie ct mai simplu, mai elegant i uor de neles, s permit dezvoltarea de componente care s fie uor de integrat n alte aplicaii, chiar dac acestea sunt scrise n alte limbaje din familia .NET. Cteva observaii generale despre instruciunile C#: instruciunile pot sau nu s fac parte dintr-un bloc delimitat cu {i}; exist instruciuni etichetate i implicit instruciunea goto; o expresie poate figura ca o instruciune: Fct(x); // F este o funcie de un anumit tip; exist instruciunile decizionale if i switch; n cazul lui switch se evalueaz variabile (expresii) de tip ntreg sau ir; instruciunile de ciclare sunt for, while, do, foreach; exist instruciuni specifice pentru tratarea excepiilor (try-catch-finally i throw); instruciunile checked i unchecked (care pot figura i ca operatori) permit gestionarea erorilor de depire de capacitate. Namespaces Namespace-urile (spaii de nume) nu sunt altceva dect nite grupri logice de componente (clase, variabile, etc.). Clase definite n fiiere fizice diferite (assembly-uri diferite) pot face parte din acelai namespace. Un namespace conine de regul clase care pot fi grupate ntr-o anumit categorie, care au funcionaliti n acelai domeniu. n .NET exist cteva namespace-uri standard, cum ar fi: System, System.Data, Declararea unei clase ntr-un anumit namespace se face n felul urmtor:
namespace Domeniu { public delegate void ChangedEventHandler(string arg); public class OClasa { // definitie clasa } }

Aceast definiie poate face parte dintr-un fiier, s spunem exNS.cs, care poate fi compilat ntr-un DLL exNS.dll. O aplicaie care va avea nevoie de un obiect din clasa Oclasa l poate declara n felul urmtor: private Domeniu.OClasa objClasa; Namespace-ul va putea fi omis n definiia de mai sus dac se va specifica la nceputul programului o clauz using: using Domeniu; La compilare se va aduga o referin la fiierul exNS.dll. Reamintim c se pot defini clase n acelai namespace, dar care s fie n fiiere fizice diferite. Namespace-urile standard ale platformei .NET sunt structurate n form de arbore. Cteva din namespace-urile sistem sunt: System, System.Data, System.Drawing, System.Windows.Forms.

Curs M I- 2-3-4-5-6-7-8

Copyright by EBS Romania S.R.L.

Pagina 38 din 52

Noiuni introductive n .NET i C#


Delegai i Evenimente Delegai S presupunem c pstrm evidena crilor dintr-o bibliotec ntr-o baz de date i avem colecii, clase definite pentru gestionarea acestei baze de date. Pentru a permite unui utilizator care utilizeaz baza de date s poat prelucra, s spunem, numai crile din domeniul tehnic, vom crea o metod care verific domeniul crilor din bibliotec i pentru cele tehnice apeleaz o funcie pentru care se cunosc tipul, parametrii i adresa la care se gsete, fr s se cunoasc coninutul efectiv al funciei. Acest apel se face de fapt ctre un delegat, care nu este altceva dect o adres, o referin la o metod (funcie). Avantajul acestei abordri const n aceea c n codul care menine baza de date nu trebuie s tim dinainte ce prelucrri se vor face cu crile din domeniul tehnic. Se pune la dispoziie o metod care gsete crile tehnice i apeleaz pentru fiecare o funcie indicat ulterior. Un client care dezvolt o aplicaie care exploateaz o astfel de baz de date i va crea metode proprii care prelucreaz crile tehnice, fr s l intereseze n ce fel codul responsabil de baza de date i selecteaz crile tehnice. O implementare a acestui model este dat n continuare:
// clase pentru biblioteca de carti namespace Bookstore { using System.Collections; // descrierea unei carti: public struct Book { public string Title; public string Author; public decimal Price; public bool Technical; public Book(string title, string author, decimal price, bool technical) { Title = title; Author = author; Price = price; Technical = technical; } } // Declar tip de delegate pentru procesarea unei cri public delegate void ProcessBookDelegate(Book book); // gestioneaz colecia de cri public class BookDB { // Lista crilor ArrayList list = new ArrayList(); // Metoda pentru adugarea unei cri n baza de date: public void AddBook(string title, string author, decimal price, bool technical) { list.Add(new Book(title, author, price, technical)); } // Pentru fiecare carte tehnic se apeleaz metoda referit de delegate public void ProcessTechnicalBooks(ProcessBookDelegate processBook) { foreach (Book b in list) { if (b.Technical) processBook(b);
Curs M I- 2-3-4-5-6-7-8 Copyright by EBS Romania S.R.L. Pagina 39 din 52

Noiuni introductive n .NET i C#


} } } }

Metoda ProcessTechnicalBooks primete ca parametru o referin la o funcie care are un parametru de tip Book. Deci delegate-ul de tip ProcessBookDelegate refer o funcie care nu returneaz nimic (void) i care are un singur parametru de tip Book. n continuare dm o secven de cod client care utilizeaz aceast baz de date.
namespace BookTestClient { using Bookstore; using System; // Clasa pentru calculul sumei preurilor i al preului mediu class PriceTotaller { int countBooks = 0; decimal priceBooks = 0.0m; internal void AddBookToTotal(Book book) { countBooks += 1; priceBooks += book.Price; } internal decimal AveragePrice() { return priceBooks / countBooks; } } // Clasa pentru testarea bazei de date create class Test { // Afieaza titlul static void PrintTitle(Book b) { Console.WriteLine(" {0}", b.Title); } static void Main() { BookDB bookDB = new BookDB(); // Apeleaz o metod care introduce cri n baza de date: AddBooks(bookDB); // Afieaz crile tehnice: Console.WriteLine("Technical Book Titles:"); // Creaz un obiect delegat pentru metoda static // Test.PrintTitle bookDB.ProcessTechnicalBooks(new ProcessBookDelegate(PrintTitle)); // Se creaz o instan a clasei PriceTotaller pentru a obine // preul mediu al crilor tehnice. PriceTotaller totaller = new PriceTotaller(); // Creaz un obiect delegat pentru metoda nonstatic // AddBookToTotal a obiectului totaller bookDB.ProcessTechnicalBooks(new ProcessBookDelegate(totaller.AddBookToTotal)); Console.WriteLine("Average Technical Book Price: ${0:#.##}",
Curs M I- 2-3-4-5-6-7-8 Copyright by EBS Romania S.R.L. Pagina 40 din 52

Noiuni introductive n .NET i C#


totaller.AveragePrice()); } // Inializarea bazei de date static void AddBooks(BookDB bookDB) { bookDB.AddBook("The C Programming Language", "Brian W. Kernighan and Dennis M. Ritchie", 19.95m, true); bookDB.AddBook("The Unicode Standard 2.0", "The Unicode Consortium", 39.95m, true); bookDB.AddBook("The MS-DOS Encyclopedia", "Ray Duncan", 129.95m, false); bookDB.AddBook("Dogbert's Clues for the Clueless", "Scott Adams", 12.00m, true); }

n aceast secven avem o clas PriceTotaller care conine metode pentru calculul sumei preurilor i al preului mediu. Clasa test conine metoda Main i nc dou metode statice, PrintTitle i AddBooks. n aceast metod, dup crearea i iniializarea unei colecii de cri se apeleaz de dou ori metoda ProcessTechnicalBooks care primete prima dat ca parametru un delegat pentru metoda PrintTitle, respectiv AddBookToTotal. Cu alte cuvinte, metodele PrintTitle i AddBookToTotal se vor apela pentru fiecare carte din domeniul tehnic. S reinem deci aceast proprietate foarte interesant a delegailor care nu tiu i nu le pas de ce tip sunt obiectele pe care le refer. Ceea ce conteaz esta c argumentele funciilor invocate de delegate s corespund cu argumentele din declaraia delegate-ului. Evenimente Un eveniment ntr-o clas este modalitatea prin care un obiect din clasa respectiv i anun clienii c n interiorul lui se petrece ceva. Clienii pot lua cunotin despre acel eveniment i pot reaciona. Deci noiunea de eveniment nu are sens s fie discutat dac nu o legm de modalitatea n care putem reaciona la acel eveniment. Evenimente sunt apsarea unui buton sau taste, deschiderea sau nchiderea unei ferestre, schimbarea poziiei curente ntr-o tabel, etc. Delegaii (delegates) ne spun ce fel de proceduri trebuie s scriem pentru a rspunde la un eveniment. Astfel, orice declaraie de eveniment trebuie s fie nsoit de specificarea tipului de funcie prin care se poate rspunde la acel eveniment. Obiectul care conine evnimentul nu trebuie s tie dinainte ce funcie se apeleaz ca rspuns la acel eveniment. Delegates reprezint deci nite adrese de funcii (pointeri) asemntori cu pointerii de funcii in C++. Exemplu: Definim un tip de delegate i o clas care are un eveniment tratat de un astfel de delegate: public delegate void EvFunc(int arg); class CuEvent { public event EvFunc Eveniment; public CuEvent() { //cod constructor } protected virtual void OnEveniment(int nr) { if (Eveniment!=null) Eveniment(null);
Curs M I- 2-3-4-5-6-7-8 Copyright by EBS Romania S.R.L. Pagina 41 din 52

Noiuni introductive n .NET i C#


} } Aceste definiii se pot include ntr-o bibliotec (DLL) care ulterior poate fi referit n orice program. Un program care utilizeaz clasa TestEvent ar arta astfel: class TestEvent { private CuEvent objTest; public TestEvent() { objTest = new CuEvent(); objTest.Eveniment += new EvFunc(declansare); } private void declansare(int x) { Console.WriteLine(ai declansat evenimentul cu valoarea {0},x); } } Trebuie observat c ataarea unei funcii la un eveniment se face cu ajutorul operatorului += urmat de cuvntul cheie new, tipul de delegate i numele unei proceduri de tipul acestui delegate. Pentru detaarea unei funcii de la un eveniment se folosete operatorul -= urmat de aceleai elemente. Compilatorul C# Compilatorul C# este csc.exe. O linie de comand poate arta astfel: se compileaz fiierul File.cs rezultnd File.exe:
csc File.cs csc /target:library File.cs csc /out:My.exe File.cs

se compileaz File.cs rezultnd File.dll: se compileaz File.cs rezultnd My.exe:

csc /define:DEBUG /optimize /out:File2.exe *.cs

se compileaz toate fiierele C# din directorul curent, cu activarea optimizrii i generarea de simboluri pentru depanare. Fiierul rezultat este File2.exe: se compileaz toate fiierele C# din directorul curent rezultnd un fiier cu informaii pentru depanare (File2.dll). Nu se afieaz logo-ul i avertismentele.

csc /target:library /out:File2.dll /warn:0 /nologo /debug *.cs

O list a opiunilor de compilare pe categorii este prezent n tabelul urmtor: Opiunea Optimizare /filealign /optimize Fiiere de ieire
Curs M I- 2-3-4-5-6-7-8 Copyright by EBS Romania S.R.L. Pagina 42 din 52

Descriere Specific dimensiunea seciunilor n fiierul de ieire. Activare/dezactivare optimizri.

Noiuni introductive n .NET i C#


Opiunea /doc /out /target Descriere Proceseaz comentariile pentru documentare i produce fiier XML Specific numele fiierului de ieire. Specific formatul fiierului de ieire /target:exe /target:library /target:module /target:winexe

Assembly-uri /addmodule /lib /nostdlib /reference Depanare i testare erori /bugreport /checked /debug /fullpaths /nowarn /warn /warnaserror /bugreport /checked /debug /fullpaths /nowarn /warn /warnaserror /define Preprocesor /define Resurse /linkresource /resource /win32icon /win32res
Curs M I- 2-3-4-5-6-7-8

Specific modulele care s fie incluse n assembly-ul rezultat. Specific locaia assembly-urilor din clauza/reference. Nu import biblioteca standard (mscorlib.dll). Import metadata dintr-un fiier care conine un assembly.

Creaz fiier cu informaii necesare pentru raportarea bug-urilor. Specific dac se vor genera erori de depire de capacitate la rulare. Se genereaz informaii pentru depanare. Referiri la fiiere vor conine calea complet (de ex. specificarea fiierelor care au generat erori). Nu se vor genera warning-urile de nivelele specificate. Nivelul minim de la care warning-urile se afieaz (0 la 4) Trateaz warning-urile ca erori. Creaz fiier cu informaii necesare pentru raportarea bug-urilor. Specific dac se vor genera erori de depire de capacitate la rulare. Se genereaz informaii pentru depanare. Referirile la fiiere vor conine calea complet (de ex. specificarea fiierelor care au generat erori). Nu se vor genera warning-urile de nivelele specificate. Nivelul minim de la care warning-urile se afieaz (0 la 4) Trateaz warning-urile ca erori. Se definesc simboluri preprocessor (similar cu clauza #define).

Se definesc simboluri preprocessor (similar cu clauza #define).

Creeaz link la o resurs. Include resurs n fiierul de ieire. Include un fiier .ico n fiierul de ieire. Include o resurs Win32 n fiierul de ieire.
Copyright by EBS Romania S.R.L. Pagina 43 din 52

Noiuni introductive n .NET i C#


Opiunea Diverse @ /? /baseaddress /codepage /help /incremental /main /noconfig /nologo /recurse /unsafe /utf8output Descriere

Specific fiierul de unde se iau opiunile de compilare i fiierele surs. Lista tuturor opiunilor de compilare. Specific adresa de unde se prefer ncrcarea unui DLL. Specific codepage-ul de utilizat (dac sau folosit mai multe codpage-uri n fiierele surs). Lista tuturor opiunilor de compilare. Activeaz compilare incremental (numai a poriunilor care au suferit modificri de la compilarea precedent). Specific n ce clas se gsete metoda Main. Nu se utilizeaz fiierul csc.rsp (care conine resurse pentru compilare). Nu afieaz logo-ul compilatorului. Se caut fiierele surs n subdirectoare. Compileaz codul care utilizeaz clauza unsafe. Afieaz informaiile de ieire utiliznd codificarea UTF-8.

Colecii de date
n implementarea unui model obiectual, anumite proprieti pot aprea sub forma unor colecii de date. De exemplu, pentru un obiect de tip Automobil putem avea proprietatea Culori, care va conine toate culorile n care este disponibil automobilul respectiv. Sau, un obiect Departament al unei firme ar putea avea o proprietate Angajai, care este o colecie cu toi angajaii din departamentul respectiv. .NET-ul pune la dispoziie o gam de colecii care au diferite faciliti orientate spre diferite particulariti ale coleciilor. De exemplu, putem avea colecii care s conin obiecte de orice fel sau colecii care conin numai obiecte de un anumit tip. Sau putem avea colecii n care se pot aduga sau terge elemente i colecii n care numrul de elemente este fix. Prin colecii vom avea acces la tipuri de date, cum ar fi vectori, mulimi, tabele de dispersie, etc. Coleciile sunt folosite la memorarea i manipularea datelor, precum i la transmiterea datelor de la o metod la alta. Alegerea modelului de colecie potrivit pentru implementarea unei anumite proprieti este o operaiune cu care ne familiarizm n timp, pe msur ce dobndim o oarecare experien. Cteva din coleciile existe n .NET sunt implementate de urmtoarele clase: .ArrayList este o list indexat, care permite adugri i tergeri; .BitArray list de bii (valori boolene); .Dicionare, ale cror elemente sunt perechi de form (cheie, valoare). Accesul la valoare se realizeaz cu ajutorul cheii (HashTable); .Queue list de tip FIFO; .Stack list de tip LIFO.

Curs M I- 2-3-4-5-6-7-8

Copyright by EBS Romania S.R.L.

Pagina 44 din 52

Noiuni introductive n .NET i C#


Interfee n System.Collections
Deja tim c o interfa definete un anumit comportament al unei clase sau, altfel spus, o interfa definete metode care urmeaz s fie prezente n clasele derivate. n procesul de motenire, o clas poate implementa mai multe interfee. Cele mai importante interfee din namespace-ul Collections sunt: IEnumerable, IEnumerator, IDictionaryEnumerator, ICollection, IList i IDictionary. n figura urmtoare sunt prezentate ierarhiile n care pot fi ncadrate aceste interfee.

IEnumerator i IDictionaryEnumerator
Un enumerator este utilizat n parcurgerea secvenial a unei colecii. Comportamentul unui enumerator n C# este asemntor cu cel al unui iterator n Java. Interfaa de baz care descrie comportamentul unui enumerator este IEnumerator.
public interface IEnumerator { object Current { get; } bool MoveNext (); // Dac mai exist elemente n mulime, avanseaz void Reset (); // Fixeaz enumeratorul pe poziia iniial }

Enumeratorii sunt utilizai doar la parcurgerea (citirea) datelor, n sensul c nu pot modifica datele unei colecii. La crearea unei colecii, enumeratorul este poziionat naintea primului element (acolo se face poziionarea i la apelul metodei Reset).

Curs M I- 2-3-4-5-6-7-8

Copyright by EBS Romania S.R.L.

Pagina 45 din 52

Noiuni introductive n .NET i C#


Pentru a itera elementele unui dicionar se utilizeaz enumeratori specializai, descrii n interfaa IDictionaryEnumerator.
public interface IDictionaryEnumerator: IEnumerator { DictionaryEntry Entry { get; //ntoarce un element al dicionarului } object Key { get; // ntoarce cheia elementului curent } object Value { get; // ntoarce valoarea elementului curent } }

Interfaa IEnumerable
IEnumerable descrie o colecie de date ale crei elemente pot fi enumerate (expune un enumerator pentru acea colecie).
public interface IEnumerable { IEnumerator GetEnumerator (); }

ICollection
ICollection descrie o colecie de date pentru care: Elementele pot fi enumerate (comportament motenit de la IEnumerable); Numrul curent de elemente este cunoscut; Se poate obine acces exclusiv la elemente; Elementele pot fi copiate ntr-un obiect de tip Array (este cunoscut numrul lor).
public interface ICollection: IEnumerable { int Count { get; // Numr curent de elemente } bool IsSynchronized { get; // Thread-safe? } object SyncRoot { get; // Obin un obiect la care este asigurat accesul exclusiv } }

Curs M I- 2-3-4-5-6-7-8

Copyright by EBS Romania S.R.L.

Pagina 46 din 52

Noiuni introductive n .NET i C#


IList
IList descrie coleciile de date indexate: un element poate fi accesat prin indexul corespunztor.
public interface IList: IEnumerable, ICollection { bool IsFixedSize { get; } bool IsReadOnly { get; } object this [int index] { get; set; } void Add (object value); void Clear (); bool Contains (object value); int IndexOf (object value); void Insert (int index, object value); void Remove (object value); void RemoveAt (int index); }

IDictionary
Interfaa IDictionary este interfaa de baz pentru toate coleciile de tip dicionar, ale cror elemente sunt perechi de forma (cheie, valoare), n care: "cheie" este un obiect diferit de null; "valoare" poate fi orice instan a unui tip referin, chiar null. Pentru a reprezenta un astfel de element se utilizeaz structura DictionaryEntry.
public interface IDictionary: IEnumerable, ICollection { bool IsFixedSize { get; } bool IsReadOnly { get; } object this [object key] { get; set; } ICollection Keys { get;
Curs M I- 2-3-4-5-6-7-8 Copyright by EBS Romania S.R.L. Pagina 47 din 52

Noiuni introductive n .NET i C#


} ICollection Values { get; } void Add (object key, object value); void Clear (); bool Contains (object key); IDictionaryEnumerator GetEnumerator (); void Remove (object key);

HashTable
Un alt model de colecie l reprezint coleciile de tip HashTable. Acestea sunt tot colecii de tip cheie-valoare, organizate pentru a permite cutri rapide. Pentru fiecare cheie dintr-o pereche cheie-valoare se genereaz un cod unic (hash code). Aceste coduri sunt adugate n nite couri, care vor restrnge ulterior setul de articole n care se face cutarea unei chei, asta deoarece n momentul n care se primete o cheie se va ti exact n ce co trebuie s se caute. Pentru generarea unui hash code se utilizeaz algoritmi specifici (hashAlgorihtms). Aceste valori hash se utilizeaz i n criptogafie. O cheie hash reprezint de fapt o secven de octei de lungime fix care identific n mod unic o secven voluminoas de octei de dimensiune variabil. De asemenea, valorile hash se pot utiliza i n verificarea integritii datelor (pentru date de volum mare se compar valorile hash generate la intrare cu cele generate la ieire). Exemplu /* * Context: mi inchipui un workgroup (grup de studeni implicai ntr-o activitate - spre exemplu * Program de Consultan Microsoft). Fiecare student poate fi identificat prin datele sale. * n cazul nostru, prin numrul matricol. Alte date ar putea fi: nume, anul de studiu, etc... * * Cerin: sortarea studenilor dup diverse criterii, ntr-un mod ct mai elegant, n C#. * * Soluie: mulimea de studeni va fi manipulat cu o tabel de dispersie, deoarece fiecare student * are o cheie unic (numrul matricol). Vom generaliza, n sensul n care ar putea exista o combinaie de date personale prin care studentul s poat fi unic determinabil (structura CheieStudent). */
using System; using System.Collections; namespace DomeniuDeTipuri { /* * Enumerez criteriile dup care mulimea de studeni poate fi sortat. * Key: sortare dup cheie (sortarea unor numere ntregi aici) * Value: sortare dup valoare (sortarea unor string-uri aici) * Tipul poate fi extins... */ enum SortezDupa {
Curs M I- 2-3-4-5-6-7-8 Copyright by EBS Romania S.R.L. Pagina 48 din 52

Noiuni introductive n .NET i C#


} Cheie, Valoare

struct CheieStudent: IComparable { /* * Detalii unice pentru un student: n acest caz doar numrul matricol. */ private int nrMatricol; /* * Cheia studentului */ private int codHash; public override int GetHashCode () { return codHash; } public override string ToString () { return codHash.ToString (); } public CheieStudent (int nrMatricol) { this.nrMatricol = nrMatricol; /* * n acest caz, unicitatea este dat doar de numrul matricol. */ this.codHash = nrMatricol;

/* * Implementez IComparable pentru sortare (cheie). */ public int CompareTo (object altaCheieStudent) { int altCodHash = altaCheieStudent.GetHashCode (); } return (codHash < altCodHash ? -1: (codHash == altCodHash ? 0: 1));

} struct Student: IComparable { /* * Cheie unic */ private CheieStudent cheie; /* * Detalii student: nume, an de studiu, etc... */ private string nume;
Curs M I- 2-3-4-5-6-7-8 Copyright by EBS Romania S.R.L. Pagina 49 din 52

Noiuni introductive n .NET i C#


/* * Redefinete n cazul n care adaugi noi cmpuri n clasa Student! */ public override string ToString () { return nume; } /* * Nu redefini n cazul n care adaugi noi cmpuri n clasa Student! */ public override int GetHashCode () { return cheie.GetHashCode (); } public Student (int nrMatricol, string nume) { cheie = new CheieStudent (nrMatricol); this.nume = nume; } /* * Implementez IComparable pentru sortare (nume). */ public int CompareTo (object altStudent) { return nume.CompareTo (altStudent.ToString ()); }

} class WorkGroup {

/* * n tabela de dispersie, cheile sunt cheile studenilor i valorile sunt * instane ale tipului Student. * Valorile ar putea fi chiar numele studenilor, dar generalizez i aici. */ private Hashtable studenti; public WorkGroup () { this.studenti = new Hashtable (); } public void AdaugaStudent (Student student) { studenti [student.GetHashCode ()] = student; } public void EliminaStudent (Student student) { studenti.Remove (student.GetHashCode ()); } public void ListeazaSortat (SortezDupa criteriu) {

Curs M I- 2-3-4-5-6-7-8

Copyright by EBS Romania S.R.L.

Pagina 50 din 52

Noiuni introductive n .NET i C#


/* * Pentru thread-safety, utilizeaz SyncRoot. * Coleciile chei i valori ar trebui s conin acelai numr de elemente. */ ICollection chei = studenti.Keys; Array cheiTab = Array.CreateInstance (typeof (object), chei.Count); chei.CopyTo (cheiTab, 0); ICollection valori = studenti.Values; Array valoriTab = Array.CreateInstance (typeof (object), valori.Count); valori.CopyTo (valoriTab, 0); switch (criteriu) { case SortezDupa.Cheie: Array.Sort (cheiTab, valoriTab); Afiseaza (cheiTab, valoriTab); break; case SortezDupa.Valoare: Array.Sort (valoriTab, cheiTab); Afiseaza (valoriTab, cheiTab); break; }

public static void Afiseaza (Array tab, Array coresp) { IEnumerator tabEnum = tab.GetEnumerator (); IEnumerator corespEnum = coresp.GetEnumerator (); while (tabEnum.MoveNext () && corespEnum.MoveNext ()) { Console.WriteLine ( tabEnum.Current.ToString () + ", " + corespEnum.Current.ToString () ); }

} } public class App { public static void Main () { /* * Exemplifica */

Student dr = new Student (97107, "Dr"); Student ax = new Student (98007, "Ax"); Student gg = new Student (95782, "Gg"); WorkGroup wg = new WorkGroup (); wg.AdaugaStudent (dr); wg.AdaugaStudent (ax); wg.AdaugaStudent (gg); wg.ListeazaSortat (SortezDupa.Cheie);
Curs M I- 2-3-4-5-6-7-8 Copyright by EBS Romania S.R.L. Pagina 51 din 52

Noiuni introductive n .NET i C#


Console.WriteLine ("*********"); wg.EliminaStudent (ax); wg.ListeazaSortat (SortezDupa.Valoare); Console.ReadLine (); } } }

De reinut clasele reprezint modele, obiectele sunt elementele create pe aceste modele cu care se opereaz efectiv; interfeele definesc un comportament comun al unor obiecte care pot fi foarte diferite; o clas poate fi derivat dintr-o singur superclas, dar poate moteni mai multe interfee; clasele definite n procesul de dezvoltare se grupeaz logic n namespace-uri; n .NET Framework (i implicit n C#), tipurile de date fundamentale sunt: tipurile primitive, tipurile referin i tipurile valoare. Tipurile de date sunt sarea n bucate pentru Microsoft .NET Framework i, implicit, pentru C#. .NET Framework unific modelul de programare pentru toate limbajele compatibile (care produc Common Intermediate Language pentru Common Language Runtime). Un bun exemplu l constituie Common Type System. Delegaii ne ajut s referim funcii pentru care cunoatem doar tipul parametrilor, fr s ne intereseze exact despre ce funcii este vorba; acetia se utilizeaz i la ataarea de funcii evenimentelor. Platforma .NET ofer un suport larg pentru implementarea modelelor care utilizeaz colecii, n funcie de tipurile i funcionalitile obiectelor care compun coleciile; Coleciile care conin perechi de tip cheie-valoare sunt implementate cu ajutorul interfeei IDictionary; un caz particular l reprezint clasa HashTable. Pentru a accesa elementele acestor colecii s-a creat structura DictionaryEntry; Interfaa IEnumerator conine funcionalitile de baz necesare pentru parcurgerea unei colecii. Coleciile cu indexatori n C# sunt cu baz 0, spre deosebire de cele din VB care sunt cu baz 1; Coleciile pot avea indeci numerici sau indeci cheie (de tip string).

Curs M I- 2-3-4-5-6-7-8

Copyright by EBS Romania S.R.L.

Pagina 52 din 52