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
Pagina 1 din 52
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
Pagina 3 din 52
Curs M I- 2-3-4-5-6-7-8
Pagina 4 din 52
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
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
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
Pagina 9 din 52
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;
} }
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
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
Pagina 12 din 52
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
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();
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
Pagina 14 din 52
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
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
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
} }
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
Pagina 18 din 52
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
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
Pagina 20 din 52
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
Pagina 22 din 52
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
} } 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
} 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
Pagina 25 din 52
Tipuri fundamentale
Modelul obiectual al .NET Framework poate fi schiat n felul urmtor: C# Tipuri fundamentale de date
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
Pagina 26 din 52
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 { //...
}
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
Pagina 28 din 52
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
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
Pagina 31 din 52
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
Pagina 32 din 52
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
Pagina 33 din 52
} }
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
Curs M I- 2-3-4-5-6-7-8
Pagina 35 din 52
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; } }
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
Pagina 37 din 52
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
Pagina 38 din 52
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
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
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.
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
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).
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
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
Pagina 44 din 52
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
Pagina 45 din 52
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
Pagina 46 din 52
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
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
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
} 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
Pagina 50 din 52
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 () ); }
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
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
Pagina 52 din 52