Está en la página 1de 232

Cuprins

I. PROGRAMARE ORIENTAT PE OBIECTE.............................................................................................. 3 I.1. INTRODUCERE IN .NET.............................................................................................................................. 3 I.1.1. Arhitectura .NET Framework .......................................................................................................... 4 I.1.2. Compilarea programelor................................................................................................................. 4 I.1.3. De ce am alege .NET? ..................................................................................................................... 5 I.2. INTRODUCERE N LIMBAJUL C# ................................................................................................................. 5 I.2.1. Caracterizare................................................................................................................................... 5 I.2.2. Crearea aplicaiilor consol............................................................................................................ 6 I.2.3. Structura unui program C#.............................................................................................................. 8 I.2.4. Sintaxa limbajului.......................................................................................................................... 10 I.2.4.6. Expresii i operatori ......................................................................................................................... 12 I.2.6.9. Instruciunile try-catch-finally i throw............................................................................................ 48 I.3. PRINCIPIILE PROGRAMRII ORIENTATE PE OBIECTE ................................................................................. 75 I.3.1. Evoluia tehnicilor de programare ................................................................................................ 75 I.3.2. Tipuri de date obiectuale. ncapsulare .......................................................................................... 76 I.3.3. Suprancrcare .............................................................................................................................. 78 I.3.4. Motenire ....................................................................................................................................... 79 I.3.5. Polimorfism. Metode virtuale ........................................................................................................ 80 I.3.6. Principiile programrii orientate pe obiecte ................................................................................. 81 I.4. STRUCTURA UNEI APLICAII ORIENTAT PE OBIECTE N C#..................................................................... 81 I.4.1. Clas de baz i clase derivate...................................................................................................... 82 I.4.2. Constructori................................................................................................................................... 82 I.4.3. Suprancrcarea constructorilor i definirea constructorilor n clasele derivate ......................... 83 I.4.4. Destructor...................................................................................................................................... 84 I.4.5. Metode ........................................................................................................................................... 84 I.5. CLASE I OBIECTE ................................................................................................................................... 88 I.5.1. Clase .............................................................................................................................................. 88 I.6. CLASE I FUNCII GENERICE .................................................................................................................. 111 I.7. DERIVAREA CLASELOR (MOTENIRE) .................................................................................................... 114 I.7.1. Principiile motenirii ................................................................................................................... 114 I.7.2. Accesibilitatea membrilor motenii ............................................................................................ 116 I.7.3. Metode ......................................................................................................................................... 118 I.7.4. Interfee........................................................................................................................................ 119 I.8. TRATAREA EXCEPIILOR N C#.............................................................................................................. 121 I.8.1. Aruncarea i prinderea excepiilor.............................................................................................. 123 I.9. POLIMORFISM ........................................................................................................................................ 126 I.9.1. Introducere .................................................................................................................................. 126 I.9.2. Polimorfismul parametric............................................................................................................ 127 I.9.3. Polimorfismul ad-hoc .................................................................................................................. 128 I.9.4. Polimorfismul de motenire ......................................................................................................... 129 I.9.5. Modificatorii virtual i overide ......................................................................................... 130 I.9.6. Modificatorul new ....................................................................................................................... 131 I.9.7. Metoda sealed.......................................................................................................................... 132 II. PROGRAMARE VIZUAL ....................................................................................................................... 133 I....................................................................................................................................................................... 133 II ..................................................................................................................................................................... 133 II.1. CONCEPTE DE BAZ ALE PROGRAMRII VIZUALE.............................................................................. 133 II.2. MEDIUL DE DEZVOLTARE VISUAL C# (PREZENTAREA INTERFEEI) .................................................. 134 II.3. ELEMENTELE POO N CONTEXT VIZUAL ........................................................................................... 136 Barele de instrumente ................................................................................................................................. 138 II.4. CONSTRUIREA INTERFEEI UTILIZATOR ............................................................................................ 143 II.4.1. Ferestre........................................................................................................................................ 143 II.4.2. Controale ..................................................................................................................................... 146 II.5. APLICAII ......................................................................................................................................... 147 II.5.1. Numere pare ................................................................................................................................ 147 II.5.2. Proprieti comune ale controalelor i formularelor: ................................................................. 149 II.5.3. Metode i evenimente................................................................................................................... 150
1

II.5.4. Obiecte grafice............................................................................................................................. 172 II.5.5. Validarea informaiilor de la utilizator ....................................................................................... 174 II.5.6. MessageBox ................................................................................................................................. 175 II.5.7. Interfa definit de ctre utilizator............................................................................................ 178 II.5.8. Browser creat de ctre utilizator ................................................................................................. 186 II.5.9. Ceas ............................................................................................................................................. 191 II.6. ACCESAREA I PRELUCRAREA DATELOR PRIN INTERMEDIUL SQL SERVER ....................................... 194 II.6.1. Crearea unei baze de date. Conectare i deconectare................................................................. 194 II.6.2. Popularea bazei de date .............................................................................................................. 196 II.6.3. Introducere n limbajul SQL ........................................................................................................ 197 II.7. ACCESAREA I PRELUCRAREA DATELOR CU AJUTORUL MEDIULUI VIZUAL........................................ 205 II.7.1. Conectare i deconectare............................................................................................................. 205 II.7.2. Operaii specifice prelucrrii tabelelor ....................................................................................... 208 II.8. ACCESAREA I PRELUCRAREA DATELOR CU AJUTORUL ADO.NET................................................... 209 II.8.1. Arhitectura ADO.NET ................................................................................................................. 210 II.8.2. Furnizori de date (Data Providers) ............................................................................................. 211 II.8.3. Conectare..................................................................................................................................... 211 II.8.4. Comenzi ....................................................................................................................................... 213 II.8.5. DataReader.................................................................................................................................. 213 II.8.6. Constructori i metode asociate obiectelor de tip comand ........................................................ 215 II.8.7. Interogarea datelor...................................................................................................................... 218 II.8.8. Inserarea datelor ......................................................................................................................... 218 II.8.9. Actualizarea datelor .................................................................................................................... 219 II.8.10. tergerea datelor ........................................................................................................................ 220 II.8.11. DataAdapter i DataSet .............................................................................................................. 223 II.9. APLICAIE FINAL ............................................................................................................................ 226

I. Programare orientat pe obiecte I.1. Introducere in .NET

.NET este un cadru (Framework) de dezvoltare software unitar care permite realizarea, distribuirea i rularea aplicaiilor desktop Windows i aplicaiilor WEB. Tehnologia .NET pune laolalt mai multe tehnologii (ASP, XML, OOP, SOAP, WDSL, UDDI) i limbaje de programare (VB, C++, C#, J#) asigurnd, totodat, att portabilitatea codului compilat ntre diferite calculatoare cu sistem Windows, ct i reutilizarea codului n programe, indiferent de limbajul de programare utilizat. .NET Framework este o component livrat mpreun cu sistemul de operare Windows. De fapt, .NET 2.0 vine cu Windows Server 2003, se poate instala pe versiunile anterioare, pn la Windows 98 inclusiv; .NET 3.0 vine instalat pe Windows Vista i poate fi instalat pe versiunile Windows XP cu SP2 i Windows Server 2003 cu minimum SP1. Pentru a dezvolta aplicaii pe platforma .NET este bine s avem 3 componente eseniale:

un set de limbaje (C#, Visual Basic .NET, J#, Managed C++, Smalltalk, Perl, Fortran, Cobol, Lisp, Pascal etc), un set de medii de dezvoltare (Visual Studio .NET, Visio), o bibliotec de clase pentru crearea serviciilor Web, aplicaiilor Web i aplicaiilor desktop Windows.

Cnd dezvoltm aplicaii .NET, putem utiliza:

Servere specializate - un set de servere Enterprise .NET (din familia SQL Server 2000, Exchange 2000 etc), care pun la dispoziie funcii de stocare a bazelor de date, email, aplicaii B2B (Bussiness to Bussiness comer electronic ntre partenerii unei afaceri). Servicii Web (n special comerciale), utile n aplicaii care necesit identificarea utilizatorilor (de exemplu, .NET Passport - un mod de autentificare folosind un singur nume i o parol pentru toate site-urile vizitate) Servicii incluse pentru dispozitive non-PC (Pocket PC Phone Edition, Smartphone, Tablet PC, Smart Display, XBox, set-top boxes, etc.)

.NET Framework Componenta .NET Framework st la baza tehnologiei .NET, este ultima interfa ntre aplicaiile .NET i sistemul de operare i actualmente conine:

Limbajele C#, VB.NET, C++ i J#. Pentru a fi integrate n platforma .NET, toate aceste limbaje respect nite specificaii OOP numite Common Type System (CTS). Ele au ca elemente de baz: clase, interfee, delegri, tipuri valoare i referin, iar ca mecanisme: motenire, polimorfism i tratarea excepiilor.
3

Platforma comun de executare a programelor numit Common Language Runtime (CLR), utilizat de toate cele 4 limbaje. CTS face parte din CLR. Ansamblul de biblioteci necesare n realizarea aplicaiilor desktop sau Web, numit Framework Class Library (FCL).

I.1.1.

Arhitectura .NET Framework

Servicii WEB

Formulare

Data and XML classes (ADO.NET, SQL, XML etc.) Framework Base Classes (IO, securitate, fire de execuie, colecii etc.) Common Language Runtime (execepii, validri de tipuri,compilatoare JIT)

CLR

Componenta .NET Framework este format din compilatoare, biblioteci i alte executabile utile n rularea aplicaiilor .NET. Fiierele corespunztoare se afl, n general, n directorul C:\WINDOWS\Microsoft. NET\Framework\V2.0. (corespunztor versiunii instalate)

FCL

I.1.2.

Compilarea programelor

Un program scris ntr-unul dintre limbajele .NET conform Common Language Specification (CLS) este compilat n Microsoft Intermediate Language (MSIL sau IL). Codul astfel obinut are extensia "exe", dar nu este direct executabil, ci respect formatul unic MSIL. CLR include o main virtual asemntoare cu o main Java, ce execut instruciunile IL rezultate n urma compilrii. Maina folosete un compilator special JIT (Just In Time). Compilatorul JIT analizeaz codul IL corespunztor apelului unei metode i produce codul main adecvat i eficient. El recunoate secvenele de cod pentru care s-a obinut deja codul main adecvat, permind reutilizarea acestuia fr recompilare, ceea ce face ca, pe parcursul rulrii, aplicaiile .NET s fie din ce n ce mai rapide. Faptul c programul IL produs de diferitele limbaje este foarte asemntor are ca rezultat interoperabilitatea ntre aceste limbaje. Astfel, clasele i obiectele create ntr-un limbaj specific .NET pot fi utilizate cu succes n altul.

n plus, CLR se ocup de gestionarea automat a memoriei (un mecanism implementat n platforma .NET fiind acela de eliberare automat a zonelor de memorie asociate unor date devenite inutile Garbage Collection). Ca un element de portabilitate, trebuie spus c .NET Framework este implementarea unui standard numit Common Language Infrastructure (http://www.ecma-international.org/publications/standards/Ecma-335.htm ), ceea ce permite rularea aplicaiilor .NET, n afar de Windows, i pe unele tipuri de Unix, Linux, Solaris, Mac OS X i alte sisteme de operare (http://www.mono-project.com/Main_Page ).

I.1.3.

De ce am alege .NET?

n primul rnd pentru c ne ofer instrumente pe care le putem folosi i n alte programe, ofer acces uor la baze de date, permite realizarea desenelor sau a altor elemente grafice. Spaiul de nume System.Windows.Forms conine instrumente (controale) ce permit implementarea elementelor interfeei grafice cu utilizatorul. Folosind aceste controale, putei proiecta i dezvolta rapid i interactiv, elementele interfeei grafice. Tot .NET v ofer clase care efectueaz majoritatea sarcinilor uzuale cu care se confrunt programele i care plictisesc i fur timpul programatorilor, reducnd astfel timpul necesar dezvoltrii aplicaiilor.

I.2.

Introducere n limbajul C#
I.2.1. Caracterizare

Limbajul C# a fost dezvoltat de o echip restrns de ingineri de la Microsoft, echip din care s-a evideniat Anders Hejlsberg (autorul limbajului Turbo Pascal i membru al echipei care a proiectat Borland Delphi). C# este un limbaj simplu, cu circa 80 de cuvinte cheie i 12 tipuri de date predefinite. El permite programarea structurat, modular i orientat obiectual, conform perceptelor moderne ale programrii profesioniste. Principiile de baz ale programrii orientate pe obiecte (NCAPSULARE, MOTENIRE, POLIMORFISM) sunt elemente fundamentale ale programrii C#. n mare, limbajul motenete sintaxa i principiile de programare din C++. Sunt o serie de tipuri noi de date sau funciuni diferite ale datelor din C++, iar n spiritul realizrii unor secvene de cod sigure (safe), unele funciuni au fost adugate (de exemplu, interfee i delegri), diversificate (tipul struct), modificate (tipul string) sau chiar eliminate (motenirea multipl i pointerii ctre funcii). Unele funciuni (cum ar fi accesul
5

direct la memorie folosind pointeri) au fost pstrate, dar secvenele de cod corespunztoare se consider nesigure.

I.2.2.

Crearea aplicaiilor consol

Pentru a realiza aplicaii consol (ca i cele din Borland Pascal sau Borland C) n mediul de dezvoltare Visual Studio, trebuie s instalm o versiune a acestuia, eventual mediul free Microsoft Visual C# 2008 Express Edition de la adresa http://www.microsoft.com/express/download/ Dup lansarea aplicaiei, din meniul File se alege opiunea NewProject apoi alegem ConsoleApplication, modificnd numele aplicaiei n caseta Name.

Cnd creai o aplicaie consol, se genereaz un fiier cu extensia .cs. n cazul nostru, s-a generat fiierul Primul.cs. Extensia cs provine de la C Sharp. Redenumirea lui se poate realiza

din fereastra Solution Explorer, pe care o putei afia cu ajutorul combinaiei de taste Ctrl+W,S sau din meniul View. Codul surs generat este :
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { } } }

Completai funcia Main cu urmtoarea linie de program:


Console.WriteLine("Primul program");

Vei observa c n scrierea programului suntei asistai de IntelliSense, ajutorul contextual.

Pentru compilarea programului, selectai Build din meniul principal sau apsai tasta F6. n cazul n care avei erori, acestea sunt afiate n fereastra Error List. Efectund dublu-clic pe fiecare eroare n parte, cursorul din program se poziioneaz pe linia coninnd eroarea. Rularea programului se poate realiza n mai multe moduri: rapid fr asisten de depanare (Start Without Debugging Ctrl+F5)

rapid cu asisten de depanare (Start Debugging F5 sau cu butonul din bara de instrumente) rulare pas cu pas (Step Into F11 i Step Over F10) rulare rapid pn la linia marcat ca punct de ntrerupere (Toggle Breakpoint F9 pe linia respectiv i apoi Start Debugging F6). ncetarea urmririi pas cu pas (Stop Debugging Shift+F5) permite ieirea din modul depanare i revenirea la modul normal de lucru. Toate opiunile i rulare i depanare se gsesc n meniul Debug al mediului de programare.
7

Icoanele din IntelliSense i semnificaia lor

I.2.3.

Structura unui program C#

Majoritatea crilor care trateaz limbaje de programare ncep cu un exemplu, devenit celebru, aprut pentru prima dat n ediia din 1978 a crii The C Programming Language a lui Brian W. Kernighan i Dennis M. Ritchie, prinii limbajului C. Vom prezenta i noi acest exemplu adaptat la limbajul C#:
1 2 3 4 5 6 7 8 9 10 11 12 using System; namespace HelloWorld { class Program { static void Main() { Console.WriteLine("Hello World!"); } } }

O aplicaie C#

este format din una sau mai multe clase, grupate n spaii de nume

(namespaces). Este obligatoriu ca doar una din aceste clase s conin un punct de intrare (entry point), i anume metoda (funcia) Main.

Clasa (class), n termeni simplificai, reprezint principalul element structural i de organizare n limbajele orientate spre obiecte, grupnd date ct i funcii care prelucreaz respectivele date. Spaiul de nume (Namespaces): din raiuni practice, programele mari, sunt divizate n module, dezvoltate separat, de mai multe persoane. Din acest motiv, exist posibilitatea de a aprea identificatori cu acelai nume. Pentru a evita erori furnizate din acest motiv, n 1955 limbajul C++ introduce noiunea i cuvntul cheie namespace. Fiecare mulime de definiii dintr-o librrie sau program este grupat ntr-un spaiu de nume, existnd astfel posibilitatea de a avea ntr-un program definiii cu nume identic, dar situate n alte spaii de nume. n cazul n care, ntr-o aplicaie, unele clase sunt deja definite, ele se pot folosi importnd spaiile de nume care conin definiiile acestora. Mai menionm faptul c un spaiu de nume poate conine mai multe spaii de nume.

S comentm programul de mai sus: linia 1: este o directiv care specific faptul c se vor folosi clase incluse n spaiul de nume System. n cazul nostru, se va folosi clasa Console. linia 3: spaiul nostru de nume linia 5: orice program C# este alctuit din una sau mai multe clase linia 7: metoda Main, punctul de intrare n program linia 9: clasa Console, amintit mai sus, este folosit pentru operaiile de intrare/ieire. Aici se apeleaz metoda WriteLine din aceast clas, pentru afiarea mesajului dorit pe ecran. n C#, simplificat vorbind, un program poate fi privit ca avnd mai multe straturi: avem cod n interiorul metodelor, care, la rndul lor, se afl n interiorul claselor, aflate n interiorul namespaces-urilor. Convenie: S-a adoptat urmtoarea namespace class metod cod

convenie de scriere: n cazul n care folosim nume compuse din mai multe cuvinte, fiecare cuvnt este scris cu majuscul: HelloWorld, WriteLine. Aceast convenie poart numele de Convenie Pascal. Asemntoare este Convenia cmil, cu diferena c primul caracter din primul cuvnt este liter mic.

I.2.4.

Sintaxa limbajului

Ca i limbajul C++ cu care se nrudete, limbajul C# are un alfabet format din litere mari i mici ale alfabetului englez, cifre i alte semne. Vocabularul limbajului este format din acele simboluri cu semnificaii lexicale n scrierea programelor: cuvinte (nume), expresii, separatori, delimitatori i comentarii.

I.2.4.1. Comentarii
Limbajul C# admite trei tipuri de comentarii:

comentariu pe un rnd prin folosirea //. Tot ce urmeaz dup caracterele // sunt considerate, din acel loc pn la sfritul rndului, drept comentarii.
// Acesta este un comentariu pe un singur rand

comentariu pe mai multe rnduri prin folosirea /* i */. Orice text cuprins ntre simbolurile menionate mai sus se consider a fi comentariu. Simbolurile /* reprezint nceputul comentariului, iar */ sfritul respectivului comentariu.
/* Acesta este un comentariu care se intinde pe mai multe randuri */

creare document n format XML folosind ///.

Nepropunndu-ne s intrm n

amnunte, amintim c XML (eXtensible Markup Language) a fost proiectat n scopul transferului de date ntre aplicaii pe Internet, fiind un model de stocare a datelor nestructurate i semi-structurate.

I.2.4.2. Nume Definiie: Prin nume dat unei variabile, clase, metode etc. nelegem o succesiune de caractere care ndeplinete urmtoarele reguli:

numele trebuie s nceap cu o liter sau cu unul dintre caracterele _ i @; primul caracter poate fi urmat numai de litere, cifre sau un caracter de subliniere; numele care reprezint cuvinte cheie nu pot fi folosite n alt scop dect acela pentru care au fost definite; cuvintele cheie pot fi folosite n alt scop numai dac sunt precedate de @;
10

dou nume sunt distincte dac difer prin cel puin un caracter (fie el i liter mic ce difer de aceeai liter majuscul).

Convenii pentru nume:

n cazul numelor claselor, metodelor, a proprietilor, enumerrilor, interfeelor, spaiilor de nume, fiecare cuvnt care compune numele ncepe cu majuscul; n cazul numelor variabilelor, dac numele este compus din mai multe cuvinte, primul ncepe cu minuscul, celelalte cu majuscul.

I.2.4.2. Cuvinte cheie n C#


Cuvintele cheie sunt identificatori predefinii cu semnificaie special pentru compilator. Definim n C# urmtoarele cuvinte cheie: abstract byte class delegate event fixed if internal new override readonly short struct try unsafe volatile as case const do explicit float implicit is null params ref sizeof switch typeof ushort while base catch continue double extern for in lock object private return stackalloc this uint using bool char decimal else false foreach int long operator protected sbyte static throw ulong virtual break checked default enum finally goto interface namespace out public sealed string true unchecked void

Pentru a da semnificaii specifice codului, n C# avem i cuvinte cheie contextuale:

ascending get on value

by group orderby where

descending into partial yield

equals join select

from let set

n general, cuvintele cheie nu pot fi folosite n programele pe care le scriem, dndu-le o alt semnificaie. n cazul n care, totui, dorim s le dm o alt semnificaie, va trebui s le scriem cu simbolul @ ca prefix. Datorit neclaritilor care pot s apar, se va evita folosirea cuvintelor rezervate n alte scopuri.

11

I.2.4.3. Constante
n C# exist dou modaliti de declarare a constantelor: folosind const sau folosind modificatorul readonly. Constantele declarate cu const trebuie s fie iniializate la declararea lor. Exemplul 1:
const int x; const int x = 13; //gresit, constanta nu a fost initializata //corect

Constantele declarate cu ajutorul lui readonly sunt doar variabilele membre ale claselor, ele putnd fi iniializate doar de ctre constructorii claselor respective.

Exemplul 2:
readonly int x; readonly int x = 13; //corect //corect

I.2.4.4. Variabile

O variabil n C# poate s conin fie o valoare a unui tip elementar, fie o referin la un obiect. C# este case sensitive, deci face distincie ntre litere mari i mici.

Exemplul 3:
int Salut; int Azi_si_maine; char caracter;

I.2.4.6. Expresii i operatori


Definiie: Prin expresie se nelege o secven format din operatori i operanzi. Un operator este un simbol ce indic aciunea care se efectueaz, iar operandul este valoarea asupra creia se execut operaia. Operatorii se mpart n trei categorii:
12

Unari: - acioneaz asupra unui singur operand Binari: - acioneaz ntre doi operanzi Ternari: - acioneaz asupra a trei operanzi; exist un singur operator ternar i acesta este ?:

n C# sunt definii mai muli operatori. n cazul n care ntr-o expresie nu intervin paranteze, operaiile se execut conform prioritii operatorilor. n cazul n care sunt mai muli operatori cu aceeai prioritate, evaluarea expresiei se realizeaz de la stnga la dreapta. n tabelul alturat prioritatea descrete de la 0 la 13. Tabelul de prioriti: Prioritate 0 1 2 3 4 5 6 7 8 9 10 11 12 13 Tip Primar Unar Multiplicativ Aditiv De deplasare Relaional De egalitate AND (SI) logic XOR (SAU exclusiv) logic OR (SAU) logic AND (SI) condiional OR (SAU) condiional Condiional(ternar) atribuire simpl atribuire compus Operatori ( ) [ ] f() . x++ x-- new typeof sizeof checked unchecked -> + - ! ~ ++x --x (tip) true false & sizeof * / % + << >> < > <= >= is as == != & ^ | && || ?: = *= /= %= += -= ^= &= <<= >>= Asociativitate |=

Exemplul 4: folosind operatorul ternar ?:, s se decid dac un numr citit de la tastatur este pozitiv sau negativ. Indicaii:

Sintaxa acestui operator este: (condiie) ? (expr_1): (expr_2) cu semnificaia se evalueaz condiie, dac ea este adevrat se execut expr_1, altfel expr_2 int.Parse convertete un ir la int

13

using System; using System.Collections.Generic; using System.Text; namespace OperatorConditional { class Program { static void Main(string[] args) { int a; string rezultat; a = int.Parse(Console.ReadLine()); Console.Write(a); rezultat = (a > 0) ? " este nr. pozitiv" : " este nr. negativ"; Console.Write(rezultat); Console.ReadLine(); } } }

n urma rulrii programului obinem:

Exemplul 5: Folosind operatorul %, s se verifice dac un numr este par sau impar. Observaie: Convert.ToInt32 convertete un ir la Int32
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace primul_proiect { class Program { static void Main(string[] args) { int x; x = Convert.ToInt32(Console.ReadLine()); if (x % 2 == 0) Console.WriteLine("este par"); else System.Console.WriteLine("este impar"); } } }

14

Exemplul 6: Urmtorul program afieaz la consol tabelul de adevr pentru operatorul logic &.
using using using using System; System.Collections.Generic; System.Linq; System.Text;

namespace Exemplul_6 { class Program { static void Main(string[] args) { bool v1, v2; v1 = true; v2 = true; Console.WriteLine("{0,6}" + " & " + "{0,6}" + " = " v1, v1 = true; v2 = false; Console.WriteLine("{0,6}" + " & " + "{0,6}" + " = " v1, v1 = false; v2 = true; Console.WriteLine("{0,6}" + " & " + "{0,6}" + " = " v1, v1 = false; v2 = false; Console.WriteLine("{0,6}" + " & " + "{0,6}" + " = " v1, Console.ReadKey(); } } }

+ "{0,6}", v2, v1 & v2); + "{0,6}", v2, v1 & v2); + "{0,6}", v2, v1 & v2); + "{0,6}", v2, v1 & v2);

I.2.4.7. Opiuni de afiare


Pentru a avea control asupra modului de afiare a informaiei numerice, se poate folosi urmtoarea form a lui WriteLine():
WriteLine("sir",var1,var2,, varn);

unde sir este format din dou elemente:

caracterele afiabile obinuite coninute n mesaje

15

specificatorii de format ce au forma general {nr_var,width:fmt} unde nr_var precizeaz numrul variabilei (parametrului) care trebuie afiat ncepnd cu 0, width stabilete limea cmpului de afiare, iar fmt stabilete formatul

Exemplul 7:
using System; using System.Collections.Generic; using System.Text; namespace Exemplul_7 { class Program { static void Main(string[] args) { int a, b, c = 5; a = c++; b = ++c; Console.WriteLine("a={0} b={1}", a,b); } } }

Exemplul 8: n acest exemplu, formatul de afiare ales #.### va produce afiarea cu trei zecimale a constantei PI
using System; using System.Collections.Generic; using System.Text; namespace Exemplul_8 { class Program { static void Main(string[] args) { Console.WriteLine("Valoarea constantei matematice PI este {0:#.###}",Math.PI); } } }

16

I.2.4.8. Conversii
n C# exist dou tipuri de conversii numerice:

implicite explicite.

Conversia implicit se efectueaz (automat) doar dac nu este afectat valoarea convertit. Exemplul 9: Exemplul urmtor realizeaz suma a dou valori numerice fr semn cu reprezentare pe 8 bii. Rezultatul va fi reinut pe 64 bii
using using using using System; System.Collections.Generic; System.Linq; System.Text;

namespace Exemplul_9 { class Program { static void Main(string[] args) { byte a = 13; // byte intreg fara semn pe 8 bii byte b = 20; long c; // intreg cu semn pe 64 bii c = a + b; Console.WriteLine("{0} + {1} = {2}", a, b, c); Console.WriteLine("Suma intregilor pe 8 bii se reprezinta pe 64 bii"); } } }

17

I.2.4.8.1. Conversiile implicite


Regula dup care se efectueaz conversiile implicite este descris de tabelul urmtor: din
sbyte byte short ushort int uint long char float ulong

n
short, int, long, float, double, decimal short, ushort, int, uint, long, ulong, float, double, decimal int, long, float, double, decimal int, uint, long, ulong, float, double, decimal long, float, double, decimal long, ulong, float, double, decimal float, double, decimal ushort, int, uint, long, ulong, float, double, decimal double float, double, decimal

I.2.4.8.2. Conversia explicit Se realizeaz prin intermediul unei expresii cast (care va fi studiat mai trziu), atunci cnd nu exist posibilitatea unei conversii implicite.

din
sbyte byte short ushort int uint long ulong char float double decimal

n
byte, ushort, uint, ulong, char sbyte, char sbyte, byte, ushort, uint, ulong, char sbyte, byte, short, char sbyte, byte, short, ushort, uint, ulong, char sbyte,byte, short, ushort, int, char sbyte, byte, short, ushort, int, uint, ulong, char sbyte, byte, short, ushort, int, uint, long, char sbyte, byte, short sbyte, byte, short, ushort, int, uint, long, ulong, char, decimal sbyte, byte, short, ushort, int, uint, long, ulong, char, float, decimal sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double

18

Exemplul 10:
using System; using System.Collections.Generic; using System.Text; namespace Exemplul_10 { class Program { static void Main(string[] args) { int a = 5; int b = 2; float c; c = (float)a / b; //operatorul cast Console.WriteLine("{0} / {1} = {2}", a, b, c); Console.WriteLine("Catul intregilor, reprezentat ca real datorita operatorului cast\nde conversie explicita"); } } }

n urma rulrii programului, se va obine:

n cazul n care nu s-ar fi folosit operatorul cast, rezultatul - evident eronat - ar fi fost:

Des ntlnit este conversia din tipul numeric n ir de caractere i reciproc. Conversia din tipul numeric n ir de caractere se realizeaz cu metoda ToString a clasei Object

Exemplul 11:

int i = 13 string j = i.ToString();

19

Conversia din ir de caractere n numr se realizeaz cu ajutorul metodei Parse tot din clasa Object. Exemplul 12:

string s = "13"; int n = int.Parse(s);

Exemplul 13: Exemplul de mai jos prezint mai multe tipuri de conversii
using using using using System; System.Collections.Generic; System.Linq; System.Text;

namespace Exemplul_13 { class Program { static void Main(string[] args) { short srez, sv = 13; int iv = 123; long lrez; float frez, fv = 13.47F; double drez, dv = 87.86; string strrez, strv = "15"; bool bv = false; Console.WriteLine("Exemple de conversii:\n"); Console.WriteLine("Implicite:"); drez = fv + sv; Console.WriteLine("float si short spre double {0} + {1} = {2}", fv, sv, drez); frez = iv + sv; Console.WriteLine("int si short spre float {0} + {1} = {2}\n", iv, sv, frez); Console.WriteLine("Explicite:"); srez = (short)fv; Console.WriteLine("float spre short folosind cast {0} spre {1}",

fv, srez);

strrez = Convert.ToString(bv) + Convert.ToString(frez); Console.WriteLine("bool si float spre string folosind ToString \"{0}\" + \"{1}\" = {2}", bv, frez, strrez); lrez = iv + Convert.ToInt64(strv); Console.WriteLine("int si string cu ToInt64 spre long {0} + {1} = {2}", iv, strv, lrez); } } }
20

I.2.4.8.3. Conversii boxing i unboxing

Datorit faptului c n C# toate tipurile sunt derivate din clasa Object (System.Object), prin conversiile boxing (mpachetare) i unboxing (despachetare) este permis tratarea tipurilor valoare drept obiecte i reciproc. Prin conversia boxing a unui tip valoare, care se pstreaz pe stiv, se produce ambalarea n interiorul unei instane de tip referin, care se pstreaz n memoria heap, la clasa Object. Unboxing permite convertirea unui obiect n tipul valoare echivalent.

Exemplul 14: Prin boxing, variabila i este asignata unui obiect ob:
int i = 13; object ob = (object)i; //boxing explicit

sau
int i = 13; object ob = i; //boxing implicit

n prima linie din exemplu se declar i se iniializeaz o variabil de tip valoare, care va conine valoarea 13, valoare care va fi stocat pe stiv. Linia a doua creeaz o referin ctre un obiect alocat n heap, care va conine att valoarea 13, ct i informaia referitoare la tipul de dat coninut. i

stiva 13 int i=13; ob object ob=i;

heap

int 13

21

Se poate determina tipul pentru care s-a fcut mpachetarea folosind operatorul is:

Exemplul 15:
int i = 13; object ob = i; if (ob is int) { Console.WriteLine("Impachetarea s-a facut pentru int"); }

Prin boxing se creeaz o copie a valorii care va fi coninut. Exemplul 16:


using System; using System.Collections.Generic; using System.Text; namespace ConsoleApplication1 {class Program {static void Main(string[] args) { int i = 13; object ob = i; i=6; Console.WriteLine("In ob se pastreaza {0}", ob); Console.WriteLine("Valoarea actuala a lui i este {0}", i); Console.ReadLine(); } } }

n urma rulrii se obine:

Exemplul 17: Prin conversia de tip unboxing, obiectul ob poate fi asignat variabilei ntregi i:
int i = 13; object ob = i; i = (int)ob;

//boxing implicit //unboxing explicit

22

I.2.4.8.4. Conversii ntre numere i iruri de caractere


Limbajul C# ofer posibilitatea efecturii de conversii ntre numere i iruri de caractere. Sintaxa pentru conversia numr n ir de caractere:
numr ir + numr

Pentru conversia invers, adic din ir de caractere n numr, sintaxa este:


ir ir ir ir int long double float int.Parse(ir) sau Int32.Parse(ir) long.Parse(ir) sau Int64.Parse(ir) double.Parse(ir) sau Double.Parse(ir) float.Parse(ir) sau Float.Parse(ir)

Observaie: n cazul n care irul de caractere nu reprezint un numr valid, conversia acestui ir la numr va eua.

Exemplul 18:

using using using using

System; System.Collections.Generic; System.Linq; System.Text;

namespace Exemplul_18 { class Program { static void Main(string[] args) { string s; const int a = 13; const long b = 100000; const float c = 2.15F; double d = 3.1415; Console.WriteLine("CONVERSII\n"); Console.WriteLine("TIP\tVAL. \tSTRING"); Console.WriteLine("----------------------"); s = "" + a; Console.WriteLine("int\t{0} \t{1}", a, s); s = "" + b; Console.WriteLine("long\t{0} \t{1}", b, s); s = "" + c; Console.WriteLine("float\t{0} \t{1}", c, s); s = "" + d; Console.WriteLine("double\t{0} \t{1}", d, s); Console.WriteLine("\nSTRING\tVAL \tTIP"); Console.WriteLine("----------------------"); int a1; a1 = int.Parse("13");
23

Console.WriteLine("{0}\t{1}\tint", "13", a1); long b2; b2 = long.Parse("1000"); Console.WriteLine("{0}\t{1} \tlong", "1000", b2); float c2; c2 = float.Parse("2,15"); Console.WriteLine("{0}\t{1} \tfloat", "2,15", c2); double d2; d2 = double.Parse("3.1415", System.Globalization.CultureInfo.InvariantCulture); Console.WriteLine("{0}\t{1}\tdouble", "3.1415", d2); Console.ReadKey();

} } }

I.2.5. Tipuri de date


n C# exist dou categorii de tipuri de date:

tipuri valoare
-

tipul simplu predefinit: byte, char, int, float etc. tipul enumerare enum tipul structur - struct tipul clas class tipul interfa interface tipul delegat delegate tipul tablou - array
24

tipuri referin
-

Observaie: Toate tipurile de date sunt derivate din tipul System.Object Toate tipurile valoare sunt derivate din clasa System.ValueType, derivat la rndul ei din clasa Object (alias pentru System.Object). Pentru tipurile valoare, declararea unei variabile implic i alocarea de spaiu. Dac iniial, variabilele conin valoarea implicit specific tipului, la atribuire, se face o copie a datelor n variabila destinaie care nu mai este legat de variabila iniial. Acest proces se numete transmitere prin valoare, sau value semantics. Exemplul 19:

using System; using System.Collections.Generic; using System.Text; namespace ExempluTipuriValoare { public struct Intreg { public int v; } class Program { static void Main(string[] args) { Intreg sa = new Intreg(); sa.v = 13; Intreg sb = sa; // se initializeaza prin copiere variabila sb Console.WriteLine("sa.v este {0}.", sa.v); Console.WriteLine("sb.v este {0} prin initializare.", sb.v); sa.v = 10; Console.WriteLine("sa.v este {0}.", sa.v); Console.WriteLine("sb.v este {0}.", sb.v); Console.ReadLine(); } } }

Spre deosebire de tipurile valoare, pentru tipurile referin, declararea unei variabile nu implic automat alocarea de spaiu: iniial, referin ele sunt null i trebuie alocat explicit memorie pentru obiectele propriu-zise. n plus, la atribuire, este copiat referina n variabila

25

destinaie, dar obiectul spre care indic rmne acelai (aliasing). Aceste reguli poarta denumirea de reference semantics. Exemplul 20: Pentru exemplificarea celor de mai sus, pentru tipurile referin, vom folosi clasa StringBuilder.
using using using using System; System.Collections.Generic; System.Linq; System.Text;

namespace ExempluTipuriReferinta { class Program { static void Main(string[] args) { StringBuilder a = new StringBuilder(); StringBuilder b = a; a.Append("Salut"); Console.WriteLine("a este '{0}'.", a); Console.WriteLine("b este '{0}' prin initializare.", b); a = null; Console.WriteLine("a este '{0}' prin atribuirea unei noi valori.", a); Console.WriteLine("b este '{0}'.", b); Console.ReadLine(); } } }

I.2.5.1. Tipul valoare I.2.5.1.1. Tipuri predefinite


Limbajul C# conine un set de tipuri predefinite (int, bool etc.) i permite definirea unor tipuri proprii (enum, struct, class etc.).

26

Tipuri simple predefinite


Tip object string sbyte short int long byte ushort uint ulong float double bool char decimal Descriere rdcina oricrui tip secven de caractere Unicode tip ntreg cu semn, pe 8 bii tip ntreg cu semn, pe 16 bii tip ntreg cu semn pe, 32 bii tip ntreg cu semn, pe 64 de bii tip ntreg fr semn, pe 8 bii tip ntreg fr semn, pe 16 bii tip ntreg fr semn, pe 32 bii tip ntreg fr semn, pe 64 bii tip cu virgul mobil, simpl precizie, pe 32 bii (8 pentru exponent, 24 pentru mantis) tip cu virgul mobil, dubl precizie, pe 64 bii (11 pentru exponent, 53 pentru mantis) tip boolean tip caracter din setul Unicode, pe 16 bii tip zecimal, pe 128 bii (96 pentru mantis), 28 de cifre semnificative Domeniul de valori pentru tipurile numerice: Tip sbyte short int long byte ushort uint ulong float double decimal Domeniul de valori -128; 127 -32768; 32767 -2147483648; 2147483647 -9223372036854775808; 9223372036854775807 0; 255 0; 65535 0; 4294967295 0; 18446744073709551615 -3.402823E+38; 3.402823E+38 -1.79769313486232E+308; 1.79769313486232E+308 -79228162514264337593543950335; 79228162514264337593543950335 Alias pentru tipul struct din spaiul de nume System System.String System.Sbyte System.Int16 System.Int32 System.Int64 System.Byte System.Int16 System.Uint32 System.Uint64 System.Single System.Double System.Boolean System.Char System.Decimal

O valoare se asigneaz dup urmtoarele reguli: Sufix nu are u, U L, L ul, lu, Ul, lU, UL, LU, Lu Tip int, uint, long, ulong uint, ulong long, ulong ulong

27

Exemplul 21: string s = Salut! long a = 10; long b = 13L; ulong c = 12; ulong d = 15U; ulong e = 16L; ulong f = 17UL; float g = 1.234F; double h = 1.234; double i = 1.234D; bool cond1 = true; bool cond2 = false; decimal j = 1.234M;

I.2.5.1.2. Tipul enumerare


Tipul enumerare, asemntor cu cel din C++, se definete de ctre utilizator. Acest tip permite utilizarea numelor care, sunt asociate unor valori numerice. Enumerrile nu pot fi declarate abstracte i nu pot fi derivate. Orice enum este derivat automat din clasa System.Enum, derivat din System.ValueType. n cazul n care nu se specific tipul enumerrii, acesta este considerat implicit int. Specificarea tipului se face dup numele enumerrii:
[atribute][modificatori]enum NumeEnumerare [: Tip] { lista }

n ceea ce urmeaz, vom considera enum fr elementele opionale. Folosirea tipului enumerare impune urmtoarele observaii:

n mod implicit, valoarea primului membru al enumerrii este 0, iar fiecare variabil care urmeaz are valoarea (implicit) mai mare cu o unitate dect precedenta. valorile folosite pentru iniializri trebuie s fac parte din domeniul de valori al tipului enum nu se admit referine circulare
enum ValoriCirculare { a = b, b }

n acest exemplu, a depinde explicit de b, iar b depinde de a implicit Asemntor celor cunoscute din C++, tipul structur poate s conin declaraii de constante, cmpuri, metode, proprieti, indexatori, operatori, constructori sau tipuri imbricate.

28

Exemplul 22:
using System; namespace tipulEnum {class Program { enum lunaAnului { Ianuarie = 1, Februarie, Martie, Aprilie, Mai, Iunie, Iulie, August, Septembrie, Octombrie, Noiembrie, Decembrie } static void Main(string[] args) { Console.WriteLine("Luna Mai este a {0}",(int)lunaAnului.Mai + luna din an."); Console.ReadLine(); } } }

"

I.2.5.1.3. Tipuri nulabile


Tipurile nulabile, nullable, sunt tipuri valoare pentru care se pot memora valori posibile din aria tipurilor de baz, eventual i valoarea null. Am vzut mai sus c pentru tipurile valoare, la declararea unei variabile, aceasta conine valoarea implicit a tipului. Sunt cazuri n care se dorete ca, la declarare, valoarea implicit a variabilei s fie nedefinit. n C# exist o astfel de posibilitate, folosind structura System.Nullable<T>. Concret, o declaraie de forma:
System.Nullable<T> var;

este echivalent cu
T? var;

unde T este un tip valoare.


29

Aceste tipuri nulabile conin dou proprieti:


proprietate HasValue, care indic dac valoarea intern este diferit sau nu de null proprietatea Value, care va conine valoarea propriu zis. Legat de aceast noiune, s-a mai introdus operatorul binar ??

a ?? b

cu semnificaia: dac a este null b este evaluat i constituie rezultatul expresiei, altfel rezultatul este a.

I.2.6. Instruciuni condiionale, de iteraie i de control


Ne referim aici la instruciunile construite folosind cuvintele cheie: if, else, do, while, switch, case, default, for, foreach, in, break, continue, goto.

I.2.6.1. Instruciunea if
Instruciunea if are sintaxa:
if (conditie) Instructiuni_A; else Instructiuni_B;

Exemplul 23: Citindu-se dou numere ntregi, s se decid care dintre ele este mai mare
using System; namespace Exemplul_23 { class Program { static void Main(string[] args) { int a, b; string rezultat; Console.Write("Dati primul numar intreg : "); a = Convert.ToInt32(Console.ReadLine()); Console.Write("Dati al doilea numar intreg : "); b = Convert.ToInt32(Console.ReadLine()); if (a > b) rezultat = "primul este mai mare"; else if (a < b) rezultat = "primul este mai mic"; else rezultat = "numere egale"; Console.WriteLine("Rezultatul comparatiei lui {0} cu {1} este \"{2}\"", a, b, rezultat); } } }

30

Exemplul 24: S se verifice dac 3 puncte din plan M1, M2 i M3, date prin coordonatele lor ntregi, sunt coliniare. Punctele M1(x1,y1), M2(x2,y2), M3(x3,y3) sunt coliniare

x1
x2

y1 1 y2 1 = 0 y3 1

x3

E=(x2-x1)(y3-y1)-(x3-x1)(y2-y1)=0

using using using using

System; System.Collections.Generic; System.Linq; System.Text;

namespace Exemplul_24 { class Program { static void Main(string[] args) { double x1, y1, x2, y2, x3, y3; Console.WriteLine("Coordonatele primului punct:"); Console.Write("Abscisa : "); x1 = Convert.ToDouble(System.Console.ReadLine()); Console.Write("Ordonata : "); y1 = Convert.ToDouble(System.Console.ReadLine()); Console.WriteLine("Coordonatele celui de-al doilea punct:"); Console.Write("Abscisa : "); x2 = Convert.ToDouble(System.Console.ReadLine()); Console.Write("Ordonata : "); y2 = Convert.ToDouble(System.Console.ReadLine()); Console.WriteLine("Coordonatele celui de-al treilea punct:"); Console.Write("Abscisa : "); x3 = Convert.ToDouble(System.Console.ReadLine()); Console.Write("Ordonata : "); y3 = Convert.ToDouble(System.Console.ReadLine()); double E = (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1); if (E == 0) Console.WriteLine("Puncte coliniare"); else Console.WriteLine("Puncte necoliniare"); } } }

31

Exemplul 25: S se verifice dac un numr ntreg x este ntr-un interval dat [a, b]
using using using using System; System.Collections.Generic; System.Linq; System.Text;

namespace Exemplul_25 { class Program { static void Main(string[] args) { int a, b, x; Console.WriteLine("Se citesc doua numere care vor reprezenta capetele intervalului"); Console.Write("Dati prima valoare : "); a = Convert.ToInt32(Console.ReadLine()); Console.Write("Dati a doua valoare : "); b = Convert.ToInt32(Console.ReadLine()); if (a > b) { x = a; a = b; b = x; } // interschimbarea valorilor pentru a avea intervalul [a, b] Console.Write("x = "); x = Convert.ToInt32(Console.ReadLine()); if (x >= a && x <= b) Console.WriteLine("Numarul {0} este in intervalul [ {1}, {2} ]", x, a, b); else Console.WriteLine("Numarul {0} nu este in intervalul [ {1}, {2} ]", x, a, b); } } }

32

I.2.6.2. Instruciunea switch


n cazul instruciunii switch n C/C++, dac la finalul instruciunilor dintr-o ramur case nu exist break, se trece la urmtorul case. n C# se semnaleaz eroare. Exist i aici posibilitatea de a face verificri multiple (n sensul de a trece la verificarea urmtoarei condiii din case) doar dac case-ul nu conine instruciuni: Instruciunea switch admite n C# variabil de tip ir de caractere care s fie comparat cu irurile de caractere din case-uri: Exemplul 26: Programul urmtor afieaz ultima cifr a numrului xn, unde x i n sunt numere naturale citite de la tastatur.
using using using using System; System.Collections.Generic; System.Linq; System.Text;

namespace Exemplul_26 { class Program { static void Main(string[] args) { int x, n, k, ux; Console.Write("Dati un numar natural ca baza a puterii : "); x = Convert.ToInt32(Console.ReadLine()); Console.Write("Dati un numar natural ca exponent al puterii : "); n = Convert.ToInt32(Console.ReadLine()); ux = x % 10; // ma intereseaza doar ultima cifra Console.Write("Ultima cifra a lui {0} la puterea {1} este : ", x, n); if (n == 0) Console.WriteLine(" 1 "); else switch (ux) { case 0: Console.WriteLine(" 0 "); break; case 1: Console.WriteLine(" 1 "); break; case 2: k = n % 4; switch (k) { case 0: Console.WriteLine(" 6 "); case 1: Console.WriteLine(" 2 "); case 2: Console.WriteLine(" 4 "); case 3: Console.WriteLine(" 8 "); } break;

break; break; break; break;

33

case 3: k = n % 4; switch (k) { case 0: Console.WriteLine(" 1 "); case 1: Console.WriteLine(" 3 "); case 2: Console.WriteLine(" 9 "); case 3: Console.WriteLine(" 7 "); } break; case 4: if (n % 2 == 0) Console.WriteLine(" 6 else Console.WriteLine(" 4 "); break; case 5: Console.WriteLine(" 5 "); break; case 6: Console.WriteLine(" 6 "); break; case 7: k = n % 4; switch (k) { case 0: Console.WriteLine(" 1 "); case 1: Console.WriteLine(" 7 "); case 2: Console.WriteLine(" 9 "); case 3: Console.WriteLine(" 3 "); } break; case 8: k = n % 4; switch (k) { case 0: Console.WriteLine(" 6 "); case 1: Console.WriteLine(" 8 "); case 2: Console.WriteLine(" 4 "); case 3: Console.WriteLine(" 2 "); } break; case 9: if (n % 2 == 0) Console.WriteLine(" 1 else Console.WriteLine(" 9 "); break; } } } using using using using } System; System.Collections.Generic; System.Linq; System.Text;

break; break; break; break;

");

break; break; break; break;

break; break; break; break;

");

34

Exemplul 27: Programul urmtor efectueaz calculele corespunztoare pentru dou numere ntregi i unul dintre semnele +,-,*,/ , % introduse de la tastatur

namespace Exemplul_27 { class Program { static void Main(string[] args) { char op; int a, b; Console.WriteLine("Exemplu pentru operatori aritmetici"); Console.Write("Dati primul numar intreg : "); a = Convert.ToInt32(Console.ReadLine()); Console.Write("Dati al doilea numar intreg : "); b = Convert.ToInt32(Console.ReadLine()); Console.Write("Dati simbolul unui operator aritmetic : "); op = (char)Console.Read(); switch (op) { case '+': Console.WriteLine("Adunare : {0} + {1} = {2}", a, b, a + b); break; case '-': Console.WriteLine("Scadere : {0} - {1} = {2}", a, b, a - b); break; case '*': Console.WriteLine("Inmultire : {0} * {1} = {2}", a, b, a * b); break; case '/': Console.WriteLine("Impartire : {0} / {1} = {2}", a, b, (float)a / b); break; case '%': Console.WriteLine("Modulo : {0} % {1} = {2}", a, b, a % b); break; default: Console.WriteLine("Simbolul nu reprezinta o operatie aritmetica"); break; } } } }

35

I.2.6.2. Instruciunea while


Instruciunea while are sintaxa: while (conditie) Instructiuni;

Ct timp conditie este ndeplinit se execut Instructiuni.

Exemplul 28: S se afieze numerele ntregi pozitive <= 10

using System; namespace Exemplul_28 { class Program { static void Main(string[] args) { int n = 0; while (n <= 10) { Console.Write("{0,3}", n); n++; } Console.ReadLine(); } } }

36

Exemplul 29: Programul de mai jos numr cte cifre pare are un numr natural:
using System; namespace Exemplul_29 { class Program { static void Main(string[] args) { uint a = 1223466, b; b = CateCifrePare(a); Console.WriteLine("Numarul {0} are {1} cifre pare", a, b); } static uint CateCifrePare(uint a) { uint k = 0; if (a == 0) k = 1; while (a != 0) { if (a % 10 % 2 == 0) k++; // sau if(a % 2 == 0) // pentru ca a numar par daca si numai daca ultima cifra este para a = a / 10; } return k; } } }

Exemplul 30: S se calculeze cmmdc i cmmmc pentru dou numere citite de la tastatur.
using using using using System; System.Collections.Generic; System.Linq; System.Text;

namespace Exemplul_30 { class Program { static void Main(string[] args) { int a, b, r, x, y; Console.Write("Dati primul numar : "); a = Convert.ToInt32(Console.ReadLine());

37

Console.Write("Dati al doilea numar : "); b = Convert.ToInt32(Console.ReadLine()); x = a; y = b; r = x % y; while (r != 0) { x = y; y = r; r = x % y; } if (y != 1) Console.WriteLine("Cmmdc ({0}, {1}) = {2} ", a, b, y); else Console.WriteLine("{0} si {1} sunt prime intre ele ", a, b); Console.WriteLine("Cmmmc ({0}, {1}) = {2}", a, b, a / y * b); Console.ReadKey(); } } }

Exemplul 31: Dintr-un numr ntreg pozitiv, citit de la tastatur, s se elimine cifra cea mai mic i s se afieze numrul rezultat n urma acestei operaii.
using using using using System; System.Collections.Generic; System.Linq; System.Text;

namespace Exemplul_31 { class Program { static void Main(string[] args) { uint n, min, v; Console.Write("Dati un numar intreg pozitiv : "); n = Convert.ToUInt32(Console.ReadLine()); min = MinCifra(n); v = Valoare(n, min); Console.WriteLine("Eliminand cifra minima {0} din {1} obtinem {2}", min, n, v); }

38

static uint MinCifra(uint x) { uint min = 9; while (x != 0) { if (x % 10 < min) min = x % 10; x /= 10; } return min; } static uint Valoare(uint x, uint min) { uint y = 0, p = 1; while (x != 0) { if (x % 10 != min) { y = y + (x % 10) * p; p *= 10; } x /= 10; } return y; } } }

I.2.6.4. Instruciunea do while


Instruciunea do while are sintaxa:
do Instructiuni; while(conditie)

Se execut Instructiuni dup care se verific conditie. Dac aceasta este adevrat, ciclul se reia, altfel ciclul se termin.

39

Exemplul 32: Asemntor cu exerciiul 28, s se afieze numerele ntregi pozitive <= 10
using System; namespace Exemplul_32 { class Program { static void Main(string[] args) { int n = 0; do { Console.Write("{0,3}", n); n++; } while (n <= 10) ; Console.ReadLine(); } } }

Exemplul 33: S se afieze numerele cu proprietatea de a fi palindroame, pn la o valoare citit de la tastatur. De asemenea, s se afieze i numrul lor.
using using using using System; System.Collections.Generic; System.Linq; System.Text;

namespace Exemplul_33 { class Program { static void Main(string[] args) { int x, n, k = 0; do { Console.Write("Dati un numar natural : "); n = Convert.ToInt32(Console.ReadLine()); if (n <= 0) Console.WriteLine("Eroare la citire!"); } while (n <= 0); Console.Write("Numerele palindroame mai mici strict decat {0} sunt :\n", n); x = 1;

40

do {

} static uint palindrom(int x) { int y = 0, z = x; do { y = y * 10 + z % 10; z /= 10; } while (z != 0); if (y == x) return 1; else return 0; } } }

if (palindrom(x) == 1) { Console.Write(" {0,3} ", x); k++; } x++; } while (x < n); Console.WriteLine(); if (k == 0) Console.WriteLine("Nu exista numere!"); else Console.WriteLine("Sunt {0} numere palindroame!", k);

I.2.6.5. Instruciunea for


Instruciunea for are sintaxa:
for(initializareCiclu; conditieFinal; reinitializareCiclu) Instructiune

41

Exemplul 34: Ne propunem, s afim numerele pozitive <=10


using System; namespace Exemplul_34 {class Program {static void Main(string[] args) { for (int n = 0; n <= 10; n++) { Console.Write("{0,3}", n); } Console.ReadLine(); } } }

Exemplul 35: S se determine numerele prime, precum i numrul lor, cuprinse ntre dou valori ntregi citite de la tastatur.
using using using using System; System.Collections.Generic; System.Linq; System.Text;

namespace Exemplul_35 { class Program { static void Main(string[] args) { int a, b, x, k = 0; // k va determina cate numere prime sunt in interval do { Console.Write("Dati prima valoare : "); a = Convert.ToInt32(Console.ReadLine()); } while (a <= 0); do { Console.Write("Dati a doua valoare : "); b = Convert.ToInt32(Console.ReadLine()); } while (b <= a);

42

Console.Write("Numerele prime : "); for (x = a; x <= b; x++) if (prim(x) == 1) { Console.Write("{0, 3}", x); k++; } Console.WriteLine(); if (k == 0) Console.WriteLine("In intervalul [ {0}, {1} ] nu sunt numere prime!", a, b); else Console.WriteLine("In intervalul [ {0}, {1} ] sunt {2} numere prime!", a, b, k); } static int prim(int x) { if (x == 1) return 0; if (x % 2 == 0 && x != 2) return 0; for (int d = 3; d * d <= x; d += 2) if (x % d == 0) return 0; return 1; } } }

Exemplul 36: Un exemplu de for pe numere reale.


using using using using System; System.Collections.Generic; System.Linq; System.Text;

namespace Exemplul_36 { class Program { static void Main(string[] args) { double rc, ic; double x, y, z; int n; for (ic = 1.4; ic >= -1.4; ic -= 0.05) { for (rc = -0.7; rc <= 1.80; rc += 0.05) {

43

} } } }

} Console.WriteLine();

n = 0; x = ic * ic + rc * rc; y = 2 * ic - 4 * rc; z = x * x + y * y; while (n <= 40 && z < 5) { x = ic * ic + rc * rc - rc; y = 2 * ic - 4 * rc; z = x * x - y * y; n++; } switch (n % 4) { case 0: Console.Write("*"); case 1: Console.Write("$"); case 2: Console.Write("o"); case 3: Console.Write("@"); }

break; break; break; break;

44

I.2.6.6. Instruciunea foreach


O instruciune nou, pe care o aduce limbajul C#, este foreach. Aceast instruciune enumer elementele dintr-o colecie, executnd o instruciune pentru fiecare element. Elementul care se extrage este de tip read-only, neputnd fi transmis ca parametru i nici aplicat un operator care s-i schimbe valoarea.

45

Pentru a vedea cum acioneaz, o vom compara cu instruciunea cunoscut for. Considerm un vector nume format din iruri de caractere:
string[] nume = {"Ana", "Ionel", "Maria"}

Afiarea irului folosind for:


for(int i=0; i<nume.Length; i++) Console.Write("{0} ", nume[i]);

Acelai rezultat l obinem folosind instruciunea foreach:


foreach (string copil in nume) Console.Write("{0} ", copil);

Mai dm nc un exemplu de folosire a lui foreach:


string s="Curs"+" de"+" informatica"; foreach(char c in s) Console.Write(c);

Exemplul 37: S se mpart un ir de caractere n cuvinte. Se va afia numrul de cuvinte i fiecare cuvnt n parte
using System; namespace Exemplul_37 { class Program { static void Main(string[] args) { string sir = "Acesta este un sir"; char[] delimitator = { ' ', ',', '.', ':' }; Console.WriteLine("Sirul care va fi impartit in cuvinte \n{0}", sir); string[] cuvant = sir.Split(delimitator); Console.WriteLine("Sunt {0} cuvinte in text:", cuvant.Length); foreach (string s in cuvant) { Console.WriteLine(s); } } } }

46

I.2.6.7. Instruciunea goto


Instruciunea goto poate fi folosit, n C#, pentru efectuarea unor salturi, n instruciunea switch

Exemplul 38:
switch (a) { case 13: x = 0; y = 0; goto case 20; case 15: x = 3; y = 1; goto default; case 20: x = 5; y = 8; break; default: x = 1; y = 0; break; }

I.2.6.8. Instruciunea continue


Instruciunea continue permite reluarea iteraiei celei mai apropiate instruciuni switch, while, do while, for sau foreach.

47

Exemplul 39:
using System; namespace Exemlul_39 { class Program { static void Main(string[] args) { int i = 0; while (true) { Console.Write("{0} ", i); i++; if (i < 10) continue; else break; } Console.ReadLine(); } } }

I.2.6.9. Instruciunile try-catch-finally i throw


Prin excepie se nelege un obiect care ncapsuleaz informaii despre situaii anormale. Ea se folosete pentru a semnala contextul n care apare o situaie special. Exemple: erori la deschiderea unor fiiere a cror nume este greit, mprire la 0 etc. Aceste erori se pot manipula astfel nct programul s nu se prbueasc. Cnd o metod ntlnete o situaie dintre cele menionate mai sus, se va arunca o excepie care trebuie sesizat i tratat. Limbajul C# poate arunca ca excepii obiecte de tip System.Exception sau derivate ale acestuia. Aruncarea excepiilor se face cu instruciunea throw
throw new System.Exception();

Prinderea i tratarea excepiilor se face folosind un bloc catch. Pot exista mai multe blocuri catch, fiecare dintre ele prinde i trateaz o excepie.

48

Pentru a garanta c un anumit cod se va executa indiferent dac totul decurge normal sau apare o excepie, acest cod se va pune n blocul finally care se va executa n orice situaie.

Exemplul 40: Presupunem c dorim s citim fiierul Gigel.txt


using System; using System.IO; namespace Exemplul_40 { class tryCatch { static void Main(string[] args) { File.OpenRead("Gigel.txt"); } } }

ncercnd s compilm obinem:

Pentru a remedia aceast eroare, vom prinde excepia, punnd ntr-un bloc try linia care a furnizat-o. Putem vizualiza mesajul produs de excepia ntlnit:

49

using System; using System.IO; namespace Exemplul_40 { class tryCatch { static void Main(string[] args) { try { File.OpenRead("Gigel.txt"); } catch (FileNotFoundException a) { Console.WriteLine(a); } finally { Console.WriteLine("Acest bloc se va executa"); Console.ReadLine(); } } } }

Bineneles c n blocul catch putem s scriem ce cod dorim, de exemplu:

50

using System; using System.IO; namespace Exemplul_40 { class tryCatch { static void Main(string[] args) { try { File.OpenRead("Gigel.txt"); } catch (FileNotFoundException a) { Console.WriteLine("Nu exista fisierul cerut de dv."); } finally { Console.WriteLine("Acest bloc se va executa"); Console.ReadLine(); } } } }

Alteori putem simula prin program o stare de eroare, aruncnd o excepie (instruciunea throw) sau putem profita de mecanismul de tratare a erorilor pentru a implementa un mecanism de validare a datelor prin generarea unei excepii proprii pe care, de asemenea, o aruncm n momentul nendeplinirii unor condiii puse asupra datelor. Clasa System.Exception i derivate ale acesteia servesc la tratarea adecvat i diversificat a excepiilor.

51

I.2.7. Tablouri

I.2.7.1. Tablouri unidimensionale


Limbajul C# trateaz tablourile ntr-o manier nou fa de alte limbaje (Pascal, C/C++). La declararea unui tablou, se creeaz o instan a clasei .NET, System.Array. Compilatorul va traduce operaiile asupra tablourilor, apelnd metode ale System.Array. Declararea unui tablou unidimensional se face astfel:
Tip[] nume;

Prin aceast declaraie nu se aloc i spaiu pentru memorare. Pentru aceasta, tabloul trebuie instaniat:
nume = new Tip[NumarElemente];

Se pot face n acelai timp operaiile de declarare, instaniere i iniializare: Exemplu:


int[] v = new int[] {1,2,3);

sau
int[] v = {1,2,3);

Exemplul 41: Crearea, sortarea i afiarea unui vector:

int[] v = new int[5] { 10, 2, 4, 8, 6 }; Array.Sort(v); //sortarea crescatoare a vectorului v for (int i = 0; i < v.Length; i++) Console.Write("{0,3}", v[i]); //afisarea vectorului v

Afiarea se poate face i cu ajutorul lui foreach:


foreach (int i in v) Console.Write("{0,3}",i);

52

Exemplul 42: S se afieze numrul de elemente de pe a doua linie a tabloului i numrul total de linii.
using System; namespace Exemplul_42 { class Program {static void Main(string[] args) { int[,] tab = { { 1, 2, 3 }, { 4, 5, 6 } }; // Afisarea numarului de elemente ale // lui tab de pe linia a 2-a. // Reamintim ca prima linie are numarul de ordine 0 Console.WriteLine(tab.GetLength(1)); // Afisarea numarului de linii a tabloului tab Console.WriteLine(tab.Rank); Console.ReadLine(); } } }

Exemplul 43: S se afieze primele n+1 linii din triunghiul lui PASCAL(n20).
using System; namespace Exemplul_43 { class Program { static void Main() { int n, i, j; int[] p, q; n = Convert.ToInt32(Console.ReadLine()); p = new int[n + 1]; q = new int[n + 1]; p[0] = 1; for (i = 1; i <= n + 1; i++) { q[0] = 1; q[i - 1] = 1; for (j = 1; j <= i - 2; j++) q[j] = p[j - 1] + p[j]; for (j = 0; j <= i - 1; j++) { Console.Write(q[j] + " "); p[j] = q[j]; } Console.WriteLine(); } } } }
53

Exemplul 44: Ciurul lui Eratostene. Pentru un numr natural n dat se afieaz toate numerele prime mai mici dect n. Selectarea numerelor prime se face folosind ciurul lui Eratostene Ciurul lui Eratostene presupune formarea unui ir din numerele 2, 3, 4, , n-1, n. Pentru a obine acest ir tiem mai nti toi multiplii lui 2, apoi ai lui 3 .a.m.d. n final rmn numai numerele prime din intervalul [2,n]. Noiunea de tiere a unui element va nsemna, n acest caz, atribuirea valorii zero pentru acel element.

using System; namespace Exemplul_44 { class Program { static void Main() { int n, i, j, k; int[] c; n = Convert.ToInt32(Console.ReadLine()); c = new int[n + 1]; for (i = 2; i <= n; i++) c[i] = i; i = 2; while (i <= n / 2)//cel mai mare divizor propriu al unui numar este<=jumatatea sa { if (c[i] != 0) { j = 2 * i; while (j <= n) { if (c[j] != 0) c[j] = 0; j += i; } } i++; } for (i = 2; i <= n; i++) if (c[i] != 0) Console.Write(c[i] + " "); Console.WriteLine(); } } }

54

Exemplul 45: Ionel urc n fiecare zi n trepte(n<40) pn la apartamentul n care locuiete. El poate urca pind pe treapta urmtoare sau srind peste o treapt. n cte moduri poate urca Ionel cele n trepte? Dac notm cu f[i] numrul de moduri n care poate urca copilul i trepte, observm c exist 2 moduri prin care acesta poate ajunge la treapta i: de la treapta i-1 sau de la treapta i-2. Pentru a determina numrul de moduri, vom nsuma n cte moduri poate ajunge pe treapta i-1 cu numrul de modaliti de a ajunge pe treapta i-2, deci f[i]=f[i-1]+f[i-2].
using System; namespace Exemplul_45 { class Program { static void Main() { int n, i; int[] f; Console.Write("Numarul de trepte = "); n = Convert.ToInt32(Console.ReadLine()); f = new int[n + 1]; f[1] = f[2] = 1; for (i = 3; i <= n; i++) f[i] = f[i - 1] + f[i - 2]; Console.WriteLine("Numarul de posibilitati este = {0}",f[n].ToString()); Console.ReadLine(); } } }

55

Exemplul 46: S se determine valoare elementului maxim dintr-un tablou unidimensional, precum i frecvena sa de apariie

using System; namespace Exemplul_46 { class Program { static void Main(string[] args) { int n, i, max, f; int[] a; Console.Write("Dati dimensiunea tabloului : "); n = Convert.ToInt32(Console.ReadLine()); a = new int[n + 1]; for (i = 0; i < n; i++) { Console.Write(" a[ {0} ] = ", i + 1); a[i] = Convert.ToInt32(Console.ReadLine()); } max = a[0]; f = 1; for (i = 1; i < n; i++) if (a[i] > max) { max = a[i]; f = 1; } else if (a[i] == max) f++; Console.WriteLine("Maximul din tablou este {0} cu frecventa {1} ", max, f); } } }

56

Exemplul 47: Operaii cu elementele unui vector: citire, afiare, eliminare elemente de valoare 0, inserare dup fiecare valoare a celei mai apropiate puteri ale lui 2 (dac cele dou puteri sunt la aceeai distan fa de numr se va insera cea mai mic dintre cele doua puteri)
using System; namespace Exemplul_47 { class Program { static void Main(string[] args) { int n, i, j, k = 0; int[] a; Console.Write("Dati dimensiunea tabloului : "); n = Convert.ToInt32(Console.ReadLine()); a = new int[2 * n + 1]; Console.WriteLine("Citire tablou : "); for (i = 0; i < n; i++) { Console.Write(" a[ {0} ] = ", i + 1); a[i] = Convert.ToInt32(Console.ReadLine()); } Console.WriteLine("Afisare tablou : "); for (i = 0; i < n; i++) Console.Write("{0} ", a[i]); Console.WriteLine(); // stergere valori nule i = 0; while (a[i] != 0 && i < n) i++; while (i < n) { if (a[i] == 0) { for (j = i; j < n && a[j] == 0; j++) ; a[i++] = a[j]; a[j] = 0; k++; } else i++; } while (a[n - 1] == 0 && n > 0) n--; Console.WriteLine("Afisare tablou fara valori nule : "); for (i = 0; i < n; i++) Console.Write("{0} ", a[i]); Console.WriteLine(); // inserare valori for (i = 0; i < n; i += 2) { for (j = n; j > i; j--) a[j] = a[j - 1]; a[i + 1] = putere(a[i]); n++; } Console.WriteLine("Afisare tablou dupa inserare puteri ale lui 2 : "); for (i = 0; i < n; i++) Console.Write("{0} ", a[i]); Console.WriteLine(); }

57

static int putere(int x) { int p = 1, q; while (p <= x) p *= 2; q = p / 2; if (x - q <= p - x) return q; else return p; } } }

I.2.7.2. Tablouri multidimensionale


n cazul tablourilor cu mai multe dimensiuni facem distincie ntre tablouri regulate i tablouri neregulate (tablouri de tablouri) Declararea n cazul tablourilor regulate bidimensionale se face astfel:
Tip[,] nume;

iar instanierea:
nume = new Tip[Linii,Coloane];

Accesul:
nume[indice1,indice2]

58

Exemplu: Declararea instanierea i iniializarea


int[,] mat = new int[,] {{1,2,3},{4,5,6},{7,8,9}};

sau
int[,] mat = {{1,2,3},{4,5,6},{7,8,9}};

n cazul tablourilor neregulate (jagged array) declararea se face:


Tip [][] nume; //tablou neregulat cu doua //dimensiuni

iar instanierea i iniializarea:


Tip [][] nume = new Tip[][] { new Tip[] {sir_0}, new Tip[] {sir_1}, ... new Tip[] {sir_n} };

sau
Tip [][] nume = { new Tip[] {sir_0}, new Tip[] {sir_1}, ... new Tip[] {sir_n} };

Acces

nume[indice1][indice2]

59

Exemple:
int[][] mat = new int[][] { new int[3] {1,2,3}, new int[2] {4,5}, new int[4] {7,8,9,1} };

sau
int[][] mat = {

};

new int[3] { 1, 2, 3 }, new int[2] { 4, 5 }, new int[4] { 7, 8, 9, 1 }

Observaie: Este posibil declararea vectorilor de dimensiuni mai mari. Exemple:


int[, ,] vect = new int[2, 3, 5];

int[, , ,] vect = new int[6, 2, 4, 8];

Vectorii 3-D sunt utilizai frecvent n aplicaiile grafice.

Exemplul 48: Descompunerea unui numr n sum de numere naturale consecutive. Se citete un numr natural n. S se memoreze toate posibilitile de descompunere a numrului n n sum de numere consecutive. Dac numrul n se scrie ca sum de numere naturale consecutive, atunci rezult c exist i,kN* astfel nct i+(i+1)+(i+2)+(i+3)++(k)=n (1+2+...+k)-(1+2+...+i-1)=nk*(k+1)/2-i*(i-1)/2=n k2+k-i2+i-2n=0 k=(-1+ 1 8n - 4i 4i 2 )/2 Vom memora descompunerile n matricea neregulat a (descompunerile au dimensiuni variabile).
60

using System; namespace Exemplul_48 { class Program { static void Main() { Console.Write("Introduceti un numar natural "); int n = Convert.ToInt32(Console.ReadLine()); int[][] a = new int[n / 2][]; int l = 0, i, j; for (i = 1; i <= n / 2; i++) { double k = (Math.Sqrt(1 + 8 * n - 4 * i + 4 * i * i) - 1)/ 2; if (k == (int)k) { a[l] = new int[(int)k - i + 1]; for (j = i; j <= k; j++) a[l][j - i] = j; l++; } } Console.WriteLine("Descompunerea lui {0} in suma de numere naturale consecutive", n); for (i = 0; i < l; i++) { for (j = 0; j < a[i].Length; j++) Console.Write(a[i][j] + " "); Console.WriteLine(); } } } }

Exemplul_49: Pentru o matrice ptratic, ale crei elemente ntregi se citesc de la tastatur, s se determine:

maximul dintre valorile situate deasupra diagonalei principale numrul de numere prime (dac acestea exist) situate sub diagonala secundar

61

using System; using System.Collections.Generic; using System.Text; namespace Exemplul_49 { class Program { static void Main(string[] args) { int i, j, n; Console.Write("Dati dimensiunea matricei patratice : "); n = Convert.ToInt32(Console.ReadLine()); int[,] a; a = new int[n + 1, n + 1]; Console.WriteLine("Citire matrice : "); for (i = 0; i < n; i++) for (j = 0; j < n; j++) { Console.Write("a[{0}][{1}] = ", i + 1, j + 1); a[i, j] = Convert.ToInt32(Console.ReadLine()); } Console.WriteLine("Afisare matrice : "); for (i = 0; i < n; i++) { for (j = 0; j < n; j++) Console.Write("{0, 4}", a[i, j]); Console.WriteLine(); } int max = a[0, 1]; for (i = 0; i < n - 1; i++) for (j = i + 1; j < n; j++) if (a[i, j] > max) max = a[i, j]; Console.WriteLine("Maximul dintre valorile situate deasupra diagonalei principale : {0}", max); int k = 0; for (i = 1; i < n; i++) for (j = n - i; j < n; j++) if (prim(a[i, j]) == 1) k++; if (k == 0) Console.WriteLine("Sub diagonala secundara nu sunt numere prime!"); else Console.WriteLine("Sub diagonala secundara sunt {0} numere prime!", k); } static int prim(int x) { if (x == 1) return 0; if (x % 2 == 0 && x != 2) return 0; for (int d = 3; d * d <= x; d += 2) if (x % d == 0) return 0; return 1; }

62

I.2.8. iruri de caractere


Pentru reprezentarea irurilor de caractere, n limbajul C#, tipul de date utilizat este clasa System.String (sau aliasul string). Se definesc dou tipuri de iruri:

regulate de tip Verbatim

Tipul regulat conine ntre ghilimele zero sau mai multe caractere, inclusiv secvene escape.
string a = "Acesta este un sir de caractere"; string b = ""; string nume = "Gigel";

63

Limbajul C# introduce, pe lng irurile regulate i cele de tip verbatim. n cazul n care folosim multe secvene escape, putem utiliza irurile verbatim. Aceste iruri se folosesc n special n cazul n care dorim s facem referiri la fiiere, la prelucrarea lor, la regitri. Un astfel de ir ncepe cu simbolul @ naintea ghilimelelor de nceput. Exemplu:
using System; namespace SiruriDeCaractere { class Program { static void Main(string[] args) { string a = "un sir de caractere"; string b = "linia unu \nlinia doi"; string c = @"linia unu linia doi"; string d = "c:\\exemple\\unu.cs"; string e = @"c:\exemple\unu.cs"; Console.WriteLine(a); Console.WriteLine(b); Console.WriteLine(c); Console.WriteLine(d); Console.WriteLine(e); Console.ReadLine(); } } }

Secvenele escape permit reprezentarea caracterelor care nu au reprezentare grafic precum i reprezentarea unor caractere speciale: backslash, caracterul apostrof, etc. Secven escape \ \ \\ \0 \a \b \f \n \r Efect apostrof ghilimele backslash null alarm backspace form feed pagin nou new line linie nou carriage return nceput de rnd
64

\t \u \v \x

horizontal tab tab orizontal caracter unicode vertical tab tab vertical caracter hexazecimal

I.2.8.1. Concatenarea irurilor de caractere


Pentru a concatena iruri de caractere folosim operatorul + Exemplu:
string a = "Invat " + "limbajul " + "C#"; //a este "Invat limbajul C#"

1.2.8.2. Compararea irurilor de caractere


Pentru a compara dou iruri de caractere vom utiliza operatorii == i !=. Definiie: dou iruri se consider egale dac sunt amndou null, sau dac amndou au aceeai lungime i pe fiecare poziie au caractere respectiv identice. n caz contrar irurile se consider diferite. Exemplul 50: Exemplul urmtor demonstraz c operatorul == este definit pentru a compara valoarea obiectelor string i nu referina lor
using using using using System; System.Collections.Generic; System.Linq; System.Text;

namespace Exemplul_50 { class Program { static void Main(string[] args) { string a = "Invat limbajul C#"; string b = "Invat " + "limbajul "; b += "C#"; Console.WriteLine("a='{0}'", a); Console.WriteLine("b='{0}'", b); Console.WriteLine("a == b {0}", a == b); Console.WriteLine("(object)a == b {0}", (object)a == b); } } }

65

I.2.8.1. Funcii importante pentru iruri


Clasa String pune la dispoziia utilizatorului mai multe metode i proprieti care permit prelucrarea irurilor de caractere. Dintre acestea amintim: metode de comparare:

Compare CompareOrdinal CompareTo EndsWith StartsWith IndexOf LastIndexOf Concat CopyTo Insert Join PadLeft PadRight Remove Replace Split Substring ToLower ToUpper Trim TrimEnd TrimStart

metode pentru cutare:


-

metode care permit modificarea irului curent prin obinerea unui nou ir:
-

Proprietatea Length am folosit-o pe parcursul acestei lucrri i, dup cum tim returneaz un ntreg care reprezint lungimea (numrul de caractere) irului.
66

Tabelul de mai jos prezint cteva dintre funciile (metodele) clasei String Funcia (metod a clasei Strig) string Concat(string u, string v) int IndexOf(char c) int IndexOf(string s) string Insert(int a, string s) string Remove(int a, int b) string Replace(string u, string v) string Split(char[] c) string Substring(int index) string Substring(int a, int b) string ToLower() string ToUpper() string Trim() string TrimEnd() string TrimStart() Descrierea returneaz un nou ir obinut prin concatenarea irurilor u i v returneaz indicele primei apariii a caracterului c n ir returneaz indicele primei apariii a subirului s returneaz un nou ir obinut din cel iniial prin inserarea n irul iniial, ncepnd cu poziia a, a irului s returneaz un nou ir obinut din cel iniial prin eliminarea, ncepnd cu poziia a, pe o lungime de b caractere returneaz un nou ir obinut din cel iniial prin prin nlocuirea subirului u cu irul v mparte un ir n funcie de delimitatorii c returneaz un nou ir care este un subir al irului ini ial ncepnd cu indicele index returneaz un nou ir care este un subir al irului iniial, ncepnd de pe poziia a, pe lungimea b caractere returneaz un nou ir obinut din cel iniial prin convertirea tuturor caracterelor la minuscule returneaz un nou ir obinut din cel iniial prin convertirea tuturor caracterelor la majuscule returneaz un nou ir obinut din cel iniial prin tergerea spaiilor goale de la nceputul i sfritul irului ini ial returneaz un nou ir obinut din cel iniial prin tergerea spaiilor goale de la sfritul irului ini ial returneaz un nou ir obinut din cel iniial prin tergerea spaiilor goale de la nceputul irului ini ial

Exemplul 51: Exemplificm aplicarea funciilor de mai sus:


using using using using System; System.Collections.Generic; System.Linq; System.Text;

namespace Exemplul_51 { class Program { static void Main(string[] args) { string a = "Invat limbajul "; string b = "C#"; string c; Console.WriteLine("a = '{0}'", a); Console.WriteLine("b = '{0}'", b);

67

c = string.Concat(a, b); Console.WriteLine("string.Concat(a, b) = \"{0}\"", c); Console.WriteLine("a.IndexOf(\"v\") = {0}", Convert.ToString(a.IndexOf("v"))); Console.WriteLine("a.IndexOf(\"mba\") = {0}", Convert.ToString(a.IndexOf("mba"))); Console.WriteLine("a.Insert(6, \"de zor \") = {0}", a.Insert(6, "de zor ")); Console.WriteLine("a.Remove(5, 7) = {0}", a.Remove(5, 7)); Console.WriteLine("a.Replace(\"limbajul \", \"la informatica.\") = {0}", a.Replace("limbajul ", "la informatica.")); Console.WriteLine("a.Substring(6) = {0}", a.Substring(6)); Console.WriteLine("a.Substring(10, 3) = {0}", a.Substring(10, 3)); Console.WriteLine("a.ToLower() = {0}", a.ToLower()); Console.WriteLine("a.ToUpper() = {0}", a.ToUpper()); string d = " Ana are mere. "; Console.WriteLine("d = {0}", d); Console.WriteLine("d.Trim() = {0}", d.Trim()); Console.WriteLine("d.TrimStart() = {0}", d.TrimStart()); } } }

Exemplul 52: Programul urmtor contorizeaz majusculele dintr-un text.


using System; using System.Collections.Generic; using System.Text; namespace Exemplul_52 { class Majuscule { static void Main() { int i, nrm = 0; string text = System.Console.ReadLine();

68

for (i = 0; i < text.Length; i++) { if (text[i] >= 'A' && text[i] <= 'Z') nrm++; } System.Console.WriteLine("numarul de majuscule este=" + nrm);

Exemplul 53: S se verifice dac cuvintele s1 i s2 citite de la tastatur au aceeai textur. Dou cuvinte au aceeai textur dac au aceeai lungime i toate caracterele corespondente au acelai tip. Nu se face distincie ntre litere mari, litere mici. Ex : acum i elev au aceeai textur (vocal consoan vocal consoan)

using System; namespace Exemplul_53 { class Program { private static bool strchr(string p, char p_2) { for (int i = 0; i < p.Length; i++) if (p[i] == p_2) return true; return false; } static void Main() { String s1 = Console.ReadLine(); String s2 = Console.ReadLine(); String v = string.Copy("aeiouAEIOU"); bool textura = true; int i; if (s1.Length != s2.Length) textura = false; else { for (i = 0; i < s1.Length; i++) if (strchr(v, s1[i]) && !strchr(v, s2[i]) || !strchr(v, s1[i]) && strchr(v, s2[i])) textura = false; } if (textura) Console.WriteLine("Au aceeasi textura"); else Console.WriteLine("Nu au aceeasi textura"); } } }

69

Exemplul 54: Folosind metoda Split, s se numere cuvintele unui text tiind c acestea sunt separate printr-un singur separator din mulimea { ' ', ',', ';'}.
using System; namespace Exemplul_54 { class Program { static void Main(string[] args) { String s = "Metoda Split() nu face gruparea mai multor separatori"; char[] x = { ' ', ',', ';' }; String[] cuvant = s.Split(x); int nrcuv = 0; for (int i = 0; i < cuvant.Length; i++) { Console.WriteLine(cuvant[i]); nrcuv++; } Console.WriteLine("Textul contine {0} cuvinte.",nrcuv); } } }

Metoda Split() nu face gruparea mai multor separatori, lucru care ar fi de dorit. Pentru aceasta se folosesc expresii regulate.
70

Expresiile regulate reprezint o metod extrem de util pentru a opera cutri/nlocuiri pe text.

Exemplul 55:

using System; using System.Text.RegularExpressions; namespace Exemplul_55 { class Program { static void Main(string[] args) { String s = "Expresiile regulate , reprezinta o metoda extrem de facila de a opera cautari, nlocuiri pe text. "; //separator: virgula, spatiu sau punct si virgula //unul sau mai multe, orice combinatie Regex regex = new Regex("[, ;]+"); String[] cuvant = regex.Split(s); for (int i = 0; i < cuvant.Length; i++) { Console.WriteLine(cuvant[i]); } Console.ReadKey(); } } }

71

I.2.9. Stocarea informaiilor n fiiere


I.2.9.1. Administrarea fiierelor
Tehnica de citire i scriere a datelor n i din fiiere, utilizat pentru a pstra aceste informaii, reprezint administrarea fiierelor. Pentru accesarea unui fiier de pe disc se folosesc funcii din spaiul de nume System.IO. n acest spaiu exist mai multe clase: File, StreamWriter, BinaryReader i BinaryWriter. Aceste clase sunt folosite pentru operaiile de intrare-ieire cu fiiere. Obiectul File este o reprezentare a unui fiier de pe disc, iar pentru a-l utiliza trebuie s l conectm la un flux (stream). Pentru a scrie datele pe disc, se ataeaz unui flux un obiect File. Astfel se face administrarea datelor. Limbajul C# ofer dou tipuri de fiiere: fiiere text i fiiere binare.

I.2.9.2. Scrierea i citirea datelor din fiiere text


Fiierele de ieire necesit utilizarea unui obiect StreamWriter. Funcia CreateText(), ce face parte din clasa File, deschide un fiier i creeaz obiectul StreamWriter.

Exemplul 56:
using using using using System; System.Collections.Generic; System.Text; System.IO;

namespace Exemplul_56 { class Program { static void Main(string[] args) { string[] a = { "primul", "fisier", "creat", "de mine", }; //deschiderea unui fisier si atasarea lui la un flux StreamWriter outputFile = File.CreateText("C:\\C#\\fisier1.txt");

72

foreach (string b in a) { outputFile.WriteLine(b);//scrierea textului in fisier } //inchiderea fisierului outputFile.Close(); //deschidem din nou fisierul de data aceasta pentru a citi din el StreamReader inputFile = File.OpenText("C:\\C#\\fisier1.txt"); //definim o variabila string care va parcurge fisierul pana la final string x; while ((x = inputFile.ReadLine()) != null) { System.Console.WriteLine(x); } //inchidem fisierul inputFile.Close();

} } }

I.2.9.3. Scrierea i citirea datelor din fiiere binare


Dac la fiierele text tipul de flux folosit era StreamWriter, la cele binare, pentru scrierea datelor programul creeaz un obiect FileStream, la care trebuie ataat i un obiect BinaryWriter.

73

Exemplul 57:
using System; using System.Collections.Generic; using System.Text; using System.IO; namespace Exemplul_57 { class Program { static void Main(string[] args) { int i, j, x; int[,] a = new int[10, 10]; //se creeaza un fisier si un flux FileStream f = new FileStream("C:\\C#\\fisier2.dat", FileMode.CreateNew); // se creeaza un scriitor binar si il ataseaza la flux //acesta traduce datele fluxului in format binar BinaryWriter outputFile = new BinaryWriter(f); for (i = 1; i <= 4; i++) for (j = 1; j <= 4; j++) if (i == j) a[i, j] = 1; else if (j == 5 - i) a[i, j] = 2; else a[i, j] = 0; for (i = 1; i <= 4; i++) for (j = 1; j <= 4; j++) outputFile.Write(a[i, j]); //se inchide fisierul creat outputFile.Close(); f.Close(); //incepe citirea datelor din fisierul creat mai sus //se creeaza un obiect FileStream FileStream g = new FileStream("C:\\C#\\fisier2.dat", FileMode.Open); //se creeaza un obiect BinaryReader BinaryReader inputFile = new BinaryReader(g); bool final; for (final = false, i = 1; !final; i++) { for (final = false, j = 1; !final; j++) {//se apeleaza functia PeekChar care face parte din clasa BinaryReader //si examineaza urmatorul caracter din flux, daca acesta este diferit de -1 // atunci se executa citirea urmatorului caracter din flux prin functia ReadInt32() if (inputFile.PeekChar() != -1) { x = inputFile.ReadInt32(); System.Console.Write("{0} ", x); } } System.Console.Write("\n"); } inputFile.Close(); g.Close(); } } }

74

I.3. Principiile programrii orientate pe obiecte


I.3.1. Evoluia tehnicilor de programare
Programarea nestructurat (un program simplu, ce utilizeaz numai variabile globale); complicaiile apar cnd prelucrarea devine mai ampl, iar datele se multiplic i se diversific. Programarea procedural (program principal deservit de subprograme cu parametri formali, variabile locale i apeluri cu parametri efectivi); se obin avantaje privind depanarea i reutilizarea codului i se aplic noi tehnici privind transferul parametrilor i vizibilitatea variabilelor; complicaiile apar atunci cnd la program sunt asignai doi sau mai muli programatori care nu pot lucra simultan pe un acelai fiier ce conine codul surs. Programarea modular (gruparea subprogramelor cu funcionaliti similare n module, implementate i depanate separat); se obin avantaje privind independena i ncapsularea (prin separarea zonei de implementare, pstrnd vizibilitatea numai asupra zonei de interfa a modulului) i se aplic tehnici de asociere a procedurilor cu datele pe care le manevreaz, stabilind i diferite reguli de acces la date i la subprograme.
program principal date

modul_1
(date+date1) subprog_1 subprog_2 subprog_3

modul_2
(date+date2) subprog_1 subprog_2

Se observ c modulele sunt centrate pe proceduri, acestea gestionnd i setul de date pe care le prelucreaz (date+date1 din figur). Dac, de exemplu, dorim s avem mai multe seturi diferite de date, toate nzestrate comportamental cu procedurile din modulul modul_1, aceast arhitectur de aplicaie nu este avantajoas. Programarea orientat obiect POO (programe cu noi tipuri ce integreaz att datele, ct i metodele asociate crerii, prelucrrii i distrugerii acestor date); se obin avantaje prin

75

abstractizarea programrii (programul nu mai este o succesiune de prelucrri, ci un ansamblu de obiecte care prind
obiect1
date1 met1

obiect4
date4 met4

obiect3 obiect2
date2 met2 date3 met3

via, au diverse proprieti, sunt capabile de aciuni specifice i care interacioneaz n cadrul programului); intervin tehnici noi privind instanierea, derivarea i polimorfismul tipurilor obiectuale.

I.3.2. Tipuri de date obiectuale. ncapsulare


Definiie: Un tip de date abstract (ADT) este o entitate caracterizat printr-o structur de date i un ansamblu de operaii aplicabile acestor date. Considernd, n rezolvarea unei probleme de gestiune a accesului utilizatorilor la un anumit site, tipul abstract USER, vom observ c sunt multe date ce caracterizeaz un utilizator Internet. Totui se va ine cont doar de datele semnificative pentru problema dat. Astfel, culoarea ochilor este irelevant n acest caz, n timp ce data naterii poate fi important. n aceeai idee, operaii specifice ca se nregistreaz, comand on-line pot fi relevante, n timp ce operaia mnnc nu este, n cazul nostru. Evident, nici nu se pun n discuie date sau operaii nespecifice (numrul de laturi sau aciunea zboar).

Definiie: Operaiile care sunt accesibile din afara ADT formeaz interfaa acesteia. Astfel, operaii interne cum ar fi conversia datei de natere la un numr standard calculat de la 01.01.1900 nu fac parte din interfaa tipului de date abstract, n timp ce operaia plaseaz o comand on-line face parte, deoarece permite interaciunea cu alte obiecte (SITE, STOC etc.). Definiie: Numim instan a unui tip de date abstract o concretizare a tipului respectiv, format din valori efective ale datelor. Definiie: Un tip de date obiectual este un tip de date care implementeaz un tip de date abstract.

76

Definiie: Vom numi metode operaiile implementate n cadrul tipului de date abstract. Definiie: Numim membri ai unui tip de date obiectual datele i metodele definite mai sus. Folosirea unui tip de date obiectual tip presupune:

existena definiiei acestuia apelul metodelor accesul la date.

Exemplul 58: Un exemplu de-acum clasic de tip de date abstract este STIVA. Ea poate avea ca date: numerele naturale din stiv, capacitatea stivei, vrful etc. Iar operaiile specifice pot fi: introducerea n stiv (push) i extragerea din stiv (pop). La implementarea tipului STIVA, vom defini o structur de date care s rein valorile memorate n stiv i cmpuri de date simple pentru: capacitate, numr de elemente etc. Vom mai defini metode (subprograme) capabile s creeze o stiv vid, care s introduc o valoare n stiv, s extrag valoarea din vrful stivei, s testeze dac stiva este vid sau dac stiva este plin etc. Definiie: Crearea unei instane noi a unui tip obiectual, presupune operaii specifice de construire a noului obiect, metoda corespunztoare purtnd numele de constructor. Definiie: La desfiinarea unei instane i eliberarea spaiului de memorie aferent datelor sale, se aplic o metod specific numit destructor (datorit tehnicii de suprancrcare, limbaje de genul C++, Java i C# permit existena mai multor constructori ). O aplicaie ce utilizeaz tipul obiectual STIVA, va putea construi dou sau mai multe stive (de cri de joc, de exemplu), le va umple cu valori distincte, va muta valori dintr-o stiv n alta dup o anumit regul desfiinnd orice stiv golit, pn ce rmne o singur stiv. De observat c toate aceste prelucrri recurg la datele, constructorul, destructorul i la metodele din interfaa tipului STIVA descris mai sus. Definiii: Principalul tip obiectual ntlnit n majoritatea mediilor de dezvoltare (Visual Basic, Delphi, C++, Java, C#) poart numele de clas (class). Exist i alte tipuri obiectuale (struct, object). O instan a unui tip obiectual poart numele de obiect. Definiie: La implementare, datele i metodele asociate trebuie s fie complet i corect definite, astfel nct utilizatorul s nu fie nevoit s in cont de detalii ale acestei implementri. El
77

va accesa datele, prin intermediul proprietilor i va efectua operaiile, prin intermediul metodelor puse la dispoziie de tipul obiectual definit. Spunem c tipurile de date obiectuale respect principiul ncapsulrii. Astfel, programatorul ce utilizeaz un tip obiectual CONT (n banc) nu trebuie s poarte grija modului cum sunt reprezentate n memorie datele referitoare la un cont sau a algoritmului prin care se realizeaz actualizarea soldului conform operaiilor de depunere, extragere i aplicare a dobnzilor. EL va utiliza unul sau mai multe conturi (instane ale tipului CONT), accesnd proprietile i metodele din interfa, realizatorul tipului obiectual asumndu-i acele griji n momentul definirii tipului CONT. Permind extensia tipurilor de date abstracte, clasele pot avea la implementare:

date i metode caracteristice fiecrui obiect din clas (membri de tip instan), date i metode specifice clasei (membri de tip clas).

Astfel, clasa STIVA poate beneficia, n plus, i de date ale clasei cum ar fi: numrul de stive generate, numrul maxim sau numrul minim de componente ale stivelor existente etc. Modificatorul static plasat la definirea unui membru al clasei face ca acela s fie un membru de clas, nu unul de tip instan. Dac n cazul membrilor nestatici, exist cte un exemplar al membrului respectiv pentru fiecare instan a clasei, membrii statici sunt unici, fiind accesai n comun de toate instanele clasei. Mai mult, membrii statici pot fi referii chiar i fr a crea vreo instan a clasei respective.

I.3.3.Suprancrcare
Dei nu este o tehnic specific programrii orientat obiect, ea creeaz un anumit context pentru metodele ce formeaz o clas i modul n care acestea pot fi (ca orice subprogram) apelate. Definiie: Prin suprancrcare se nelege posibilitatea de a defini n acelai domeniu de vizibilitate mai multe funcii cu acelai nume, dar cu parametri diferii ca tip i/sau ca numr. Definiie: Ansamblul format din numele funciei i lista sa de parametri reprezint o modalitate unic de identificare numit semntur sau amprent. Suprancrcarea permite obinerea unor efecte diferite ale apelului n contexte diferite Capacitatea unor limbaje (este i cazul limbajului C#) de a folosi ca nume al unui subprogram un operator, reprezint suprancrcarea operatorilor. Aceasta este o facilitate care reduce
78

diferenele dintre operarea la nivel abstract (cu DTA) i apelul metodei ce realizeaz aceast operaie la nivel de implementare obiectual. Dei ajut la sporirea expresivitii codului, prin suprancrcarea operatorilor i metodelor se pot crea i confuzii. Apelul unei funcii care beneficiaz, prin suprancrcare, de dou sau mai multe semnturi se realizeaz prin selecia funciei a crei semntur se potrivete cel mai bine cu lista de parametri efectivi (de la apel). Astfel, poate fi definit metoda comand on-line cu trei semnturi diferite:

comanda_online(cod_prod) cu un parametru ntreg (desemnnd comanda unui singur produs identificat prin cod_prod comanda_online(cod_prod,cantitate) cu primul parametru ntreg i celalalt real comanda_online(cod_prod,calitate) cu primul parametru ntreg i al-II-lea caracter.

I.3.4. Motenire

Definiie: Pentru tipurile de date obiectuale class este posibil o operaie de extindere sau specializare a comportamentului unei clase existente prin definirea unei clase noi ce motenete datele i metodele clasei de baz, cu aceast ocazie putnd fi redefinii unii membri existeni sau adugai unii membri noi. Operaia mai poart numele de derivare. Definiii: Clasa din care se motenete se mai numete clas de baz sau superclas. Clasa care motenete se numete subclas, clas derivat sau clas descendent. Definiie: Ca i n Java, n C# o subclas poate moteni de la o singur superclas, adic avem de-a face cu motenire simpl; aceeai superclas ns poate fi derivat n mai multe subclase distincte. O subclas, la rndul ei, poate fi superclas pentru o alt clas derivat. O clas de baz mpreun cu toate clasele descendente (direct sau indirect) formeaz o ierarhie de clase. n C#, toate clasele motenesc de la clasa de baz Object. n contextul mecanismelor de motenire trebuie amintii modificatorii abstract i sealed aplicai unei clase, modificatori ce oblig la i respectiv se opun procesului de derivare. Astfel, o clas abstract trebuie obligatoriu derivat, deoarece direct din ea nu se pot obine obiecte prin operaia de instaniere, n timp ce o clas sigilat (sealed) nu mai poate fi derivat (e un fel de terminal n ierarhia claselor).

79

Definiie: O metod abstract este o metod pentru care nu este definit o implementare, aceasta urmnd a fi realizat n clasele derivate din clasa curent care trebuie s fie i ea abstract (virtual pur, conform terminologiei din C++). Definiie: O metod sigilat este o metod care nu mai poate fi redefinit n clasele derivate din clasa curent.

I.3.5. Polimorfism. Metode virtuale


Definiie: Folosind o extensie a sensului etimologic, un obiect polimorfic este cel capabil s ia diferite forme, s se afle n diferite stri, s aib comportamente diferite. Polimorfismul obiectual, care trebuie s fie abstract, se manifest n lucrul cu obiecte din clase aparinnd unei ierarhii de clase, unde, prin redefinirea unor date sau metode, se obin membri diferii avnd ns acelai nume. Astfel, n cazul unei referiri obiectuale, se pune problema stabilirii datei sau metodei referite. Comportamentul polimorfic este un element de flexibilitate care permite stabilirea contextual, n mod dinamic, a membrului referit. Acest lucru este posibil doar n cazul limbajelor ce permit legarea ntrziat. La limbajele cu legare timpurie, adresa la care se face un apel al unui subprogram se stabilete la compilare. La limbajele cu legare ntrziat, aceast adres se stabilete doar in momentul rulrii, putndu-se calcula distinct, n funcie de contextul n care apare apelul.

Exemplul 59: Dac este definit clasa numit PIESA (de ah), cu metoda nestatic muta (pozitie_initiala, pozitie_finala), atunci subclasele TURN i PION trebuie s aib metoda muta definit n mod diferit (pentru a implementa maniera specific a pionului de a captura o pies en passant, sau, ntr-o alt concepie, metoda muta poate fi implementat la nivelul clasei PIESA i redefinit la nivelul subclasei PION, pentru a particulariza acest tip de deplasare care captureaz piesa peste care trece pionul n diagonal). Atunci, pentru un obiect T, aparinnd claselor derivate din PIESA, referirea la metoda muta pare nedefinit. Totui mecanismele POO permit stabilirea, n momentul apelului, a clasei proxime creia i aparine obiectul T i apelarea metodei corespunztore (mutare de pion sau tur sau alt pies). Pentru a permite acest mecanism, metodele care necesit o decizie contextual (n momentul apelului), se declar ca metode virtuale (cu modificatorul virtual). n mod curent, n C#

80

modificatorului virtual al funciei din clasa de baz, i corespunde un specificator override al funciei din clasa derivat ce redefinete funcia din clasa de baz. O metod ne-virtual nu este polimorfic i, indiferent de clasa creia i aparine obiectul, va fi invocat metoda din clasa de baz.

I.3.6. Principiile programrii orientate pe obiecte


Ideea POO este de a crea programele ca o colecie de obiecte, uniti individuale de cod care interacioneaz unele cu altele, n loc de simple liste de instruciuni sau de apeluri de proceduri. Obiectele POO sunt, de obicei, reprezentri ale obiectelor din viaa real (domeniul problemei), astfel nct programele realizate prin tehnica POO sunt mai uor de neles, de depanat i de extins dect programele procedurale. Aceasta este adevrat mai ales n cazul proiectelor software complexe i de dimensiuni mari. Principiile POO sunt: 1. abstractizarea - principiu care permite identificarea caracteristicilor i comportamentului obiectelor ce in nemijlocit de domeniul problemei. Rezultatul este un model. n urma abstractizrii, entitilor din domeniul problemei se definesc prin clase. 2. ncapsularea numit i ascunderea de informaii, este caracterizat prin 2 aspecte: a. Gruparea comportamentelor i caracteristicilor ntr-un tip abstract de date b. Definirea nivelului de acces la datele unui obiect 3. motenirea organizeaz i faciliteaz polimorfismul i ncapsularea permind definirea si crearea unor clase specializate plecnd de la clase (generale) care sunt deja definite acestea pot mprti (i extinde) comportamentul lor fr a fi nevoie de redefinirea aceluiai comportament. 4. Polimorfismul - posibilitatea mai multor obiecte dintr-o ierarhie de clase de a utiliza denumiri de metode cu acelai nume dar, cu un comportament diferit.

I.4. Structura unei aplicaii orientat pe obiecte n C#


Limbajul C# permite utilizarea programrii orientate pe obiecte respectnd toate principiile enunate anterior. Toate componentele limbajului sunt ntr-un fel sau altul, asociate noiunii de clas. Programul nsui este o clas avnd metoda static Main() ca punct de intrare, clas ce nu se instaniaz.

81

Chiar i tipurile predefinite byte, int sau bool sunt clase sigilate derivate din clasa ValueType din spaiul System. Tot din ierarhia de clase oferit de limbaj se obin i tipuri speciale cum ar fi: interfee, delegri i atribute. ncepnd cu versiunea 2.0 a limbajului i s-a adugat un nou tip: clasele generice, echivalentul claselor template din C++. n cele ce urmeaz vom analiza, fr a intra n detalii o aplicaie POO simpl n C#.

I.4.1. Clas de baz i clase derivate


S definim o clas numit Copil:
public class Copil { }

unde: public sunt modificatori de acces. class cuvnt rezervat pentru noiunea de clas Copil numele clasei { } corpul clasei Dac considerm clasa Copil ca i clas de baz, putem deriva dou clase Fetia i Biat

Copil Fetita Baiat

public class Fetita: Copil { } public sealed class Baiat: Copil { }

unde: modificatorul sealed a fost folosit pentru a desemna faptul c nu se mai pot ob ine clase derivate din clasa Baiat

I.4.2. Constructori
nainte de a continua amintim cteva noiuni legate de constructorii unei clase: Constructorul este o funcie care face parte din corpul unei clase. Corpul constructorului este format din instruciuni care se execut la crearea unui nou obiect al clasei respective (sau la crearea clasei, n cazul constructorilor cu modificatorul static). pot exista mai muli constructori care se pot diferenia prin lista lor de parametri constructorii nu pot fi motenii dac o clas nu are definit niciun constructor, se va asigna automat constructorul fr parametri al clasei de baz (clasa object, dac nu este precizat clasa de baz)
82

Instanierea presupune declararea unei variabile de tipul clasei respective i iniializarea acesteia prin apelul constructorului clasei (unul dintre ei, dac sunt definii mai muli) precedat de operatorul new. Relum exemplu de mai sus n care vom prezenta un constructor fr parametri i constructorul implicit din clasa derivat. Vom aduga un constructor fr parametri. La iniializarea obiectului se va citi de la tastatur un ir de caractere care va reprezenta numele copilului.

Exemplul 60:
public class Copil { protected string nume;

public Copil ( ) { nume = Console.ReadLine( ); } } class Fetita: Copil { } ... Fetita f = new Fetita ( ); Copil c = new Copil ( );

//data accesibila numai in interiorul //clasei si a claselor derivate //constructorul fara parametrii ai clasei

I.4.3. Suprancrcarea constructorilor i definirea constructorilor n clasele derivate


Relum exemplul anterior i l dezvoltm:

83

public class Copil { protected string nume;

} class Fetita: Copil { public Fetita (string s): base(s) //base semnifica faptul ca { //se face apel la nume = "Fetita "+ nume; //constructorul //din clasa de baza } } ... Copil c1 = new Copil ( ); //numele copilului se citeste de la //tastatura Copil c2 = new Copil ("Gigel"); //numele lui c2 va fi Gigel Fetita f1 = new Fetita ( ); Fetita f2 = new Fetita ("Maria");

//data accesibila numai in interiorul //clasei si a claselor derivate public Copil ( ) //constructorul fara parametrii ai clasei {nume = Console.ReadLine( );} public Copil (string s) //constructor cu parametru {nume = s;}

I.4.4. Destructor
Corpul destructorului este format din instruciuni care se execut la distrugerea unui obiect al clasei respective. Pentru orice clas poate fi definit un singur constructor. Destructorii nu pot fi motenii. n mod normal, destructorul nu este apelat n mod explicit, deoarece procesul de distrugere a unui obiect este invocat i gestionat automat de Garbage Collector

I.4.5. Metode
Din corpul unei clase pot face parte i alte funcii: metodele. Exemplificarea o vom face tot pe exemplul anterior.

Exemplul 61:

84

public class Copil { protected string nume; //data accesibila numai in interiorul //clasei si a claselor derivate public const int nr_max = 10; //constanta public static int nr_copii = 0; //camp simplu (variabila) static Copil[] copii = new Copil[nr_max]; //camp de tip //tablou (variabila) public static void adaug_copil(Copil c) //metod { copii[nr_copii++] = c; if (nr_copii == nr_max) throw new Exception("Prea multi copii"); } public static void afisare() //metod { Console.WriteLine("Sunt {0} copii:", nr_copii); for (int i = 0; i < nr_copii; i++) Console.WriteLine("Nr.{0}. {1}", i + 1, copii[i].nume); } public Copil() //constructorul fara parametrii ai clasei { nume = Console.ReadLine(); } public Copil(string s) { nume = s; } } class Fetita : Copil { public Fetita(string s) : base(s) { nume = "Fetita " + nume; //din clasa de baza } } //constructor cu parametru

//base semnifica faptul ca //se face apel la //constructorul

Fetita c = new Fetita(); Copil.adaug_copil(c); //referina noului obiect se memoreaz n tabloul static copii //(caracteristic clasei) i se incrementeaz data static nr_copii Baiat c = new Baiat(); Copil.adaug_copil(c); Copil c = new Copil(); Copil.adaug_copil(c); Copil.afisare(); //se afieaz o list cu numele celor 3 copii ...

Definirea datelor i metodelor nestatice corespunztoare clasei Copil i claselor derivate

Exemplul 62:

85

public class Copil { protected string nume; ... public virtual void se_joaca( ) //virtual functia se poate { //suprascrie la derivare Console.WriteLine("{0} se joaca.", this.nume); } public void se_joaca(string jucaria) //supradefinirea metodei { //se_joaca Console.WriteLine("{0} se joaca cu {1}.",this.nume,jucaria); } ... } class Fetita: Copil { public override void se_joaca( ) //redefinire { Console.WriteLine("{0} chinuie pisica.", this.nume); } } ... //polimorfism Fetita f = new Fetita( ); f.se_joaca("pisica"); f.se_joaca( ); Baiat b = new Baiat ( ); b.se_joaca("calculatorul"); b.se_joaca( );

I.4.6. Proprieti
Proprietile sunt asemntoare cu metodele n ceea ce privete modificatorii i numele metodelor. Metodele de acces sunt dou: set i get. Dac proprietatea nu este abstract sau extern, poate s apar una singur dintre cele dou metode de acces sau amndou, n orice ordine. Este o manier de lucru recomandabil aceea de a proteja datele membru (cmpuri) ale clasei, definind instrumente de acces la acestea: pentru a obine valoarea cmpului respectiv (get) sau de a memora o anumit valoare n cmpul respectiv (set). Dac metoda de acces get este perfect asimilabil cu o metod ce returneaz o valoare (valoarea datei pe care vrem s-o obinem sau valoarea ei modificat conform unei prelucrri suplimentare specifice problemei n cauz), metoda set este asimilabil cu o metod care un parametru de tip valoare (de intrare) i care
86

atribuie (sau nu, n funcie de context) valoarea respectiv cmpului. Cum parametrul corespunztor valorii transmise nu apare n structura sintactic a metodei, este de tiut c el este implicit identificat prin cuvntul value. Dac se supune unor condiii specifice problemei, se face o atribuire de felul cmp=value. Definirea n clasa Copil a proprietii Nume, corespunztoare cmpului protejat ce reine, sub forma unui ir de caractere, numele copilului respectiv. Se va observ c proprietatea este motenit i de clasele derivate Fetia i Biat.

Exemplul 63:
public class Copil {... string nume; // este implicit protected public string Nume //proprietatea Nume { get { if(char.IsUpper(nume[0])) return nume; else return nume.ToUpper(); } set { nume = value; } } public Copil() //metoda set { Nume = Console.ReadLine( ); } } class Fetita:Copil { public override void se_joaca() //metoda get { Console.WriteLine("{0} leagana papusa.",this.Nume); } }

I.4.7. Concluzie
Scrierea unui program orientat obiect implic determinarea obiectelor necesare; acestea vor realiza prelucrrile care definesc comportarea sistemului. Obiectele sunt responsabile pentru modificarea datelor proprii. n proiectarea unei aplicaii POO parcurgem urmtoarele etape: 1. identificarea entitilor, adic a obiectelor care apar n domeniul aplicaiei, prin evidenierea substantivelor din enunul problemei 2. pentru fiecare obiect se identific datele i operaiile, prin evidenierea verbelor i adjectivelor care caracterizeaz subiectul respectiv 3. identificarea relaiilor dintre entiti 4. crearea unei ierarhii de clase, pornind de la aceste entiti
87

5. implementarea claselor i a sistemului 6. testarea i punerea la punct.

I.5. Clase i obiecte


I.5.1. Clase

Clasele reprezint tipuri referin definite de utilizator. O aplicaie C# este format din una sau mai multe clase, grupate n spaii de nume namespaces. n mod obligatoriu, doar una dintre aceste clase conine un punct de intrare - entry point, i anume metoda Main. Sintaxa:
[atribut][modificatorAcces] class [identificator][:clasaBaza] { corpul_clasei }

unde: atribut este opional, reprezentnd informaii declarative cu privire la entitatea definit modificatorAcces - este opional, iar n cazul n care lipsete se consider public modificatorAcces public internal protected private protected internal new sealed abstract Explicaii acces nelimitat, clasa este vizibil peste tot acces permis doar n clasa sau spaiul de nume care o cuprinde acces n clasa curent sau n cele derivate modificator implicit. Acces permis doar pentru clase interioare folosit pentru clase interioare semnificnd accesul n clasa care-l conine sau n tipurile derivate din clasa care-l conine permis claselor interioare. Clasa cu acest modificator ascunde un membru cu acelai nume care este motenit clasa nu poate fi motenit clasa nu poate fi dect clas de baz, neputnd fi instaniat. Se folosete pentru clase interioare sau spaii de nume identificator - este numele clasei
88

clasaBaza - este opional, fiind numele clasei de baz, din care deriv clasa actual.

Exemplul 64: Se consider clasa IncludeClase care include ase clase avnd modificatori de acces diferii. Se pune problema vizibilitii lor din exterior

using System; using System.Collections.Generic; using System.Text; namespace AplicatiiClase { public class IncludeClase { public class Clasa1 { } abstract class Clasa2 { } protected class Clasa3 { } internal class Clasa4 { } private class Clasa5 { } class Clasa6 { } } class Program { static void Main(string[] args) { IncludeClase.Clasa1 a; IncludeClase.Clasa2 b; //Eroare, //Clasa2 este inaccesibila IncludeClase.Clasa3 c; //Eroare, //Clasa3 este inaccesibila IncludeClase.Clasa4 d; IncludeClase.Clasa5 e; //Eroare, //Clasa5 este inaccesibila IncludeClase.Clasa6 f; //Eroare, //Clasa6 este inaccesibila } } }

Corpul clasei - este alctuit din:


date funcii

Att datele ct i funciile pot avea ca modificatori de acces: modificatorAcces public internal Explicaii Membrul este accesibil de oriunde Membrul este accesibil doar n assembly-ul curent (bloc funcional al unei aplicaii .NET)

89

protected private protected internal

Membrul este accesibil oricrui membru al clasei care-l conine i a claselor derivate Modificator implicit. Accesibil permis doar pentru clasa care-l conine Membrul este accesibil oricrui membru al clasei care-l conine i a claselor derivate, precum i n assembly-ul curent

I.5.1.(1)

Date

Datele situate ntr-o clas sunt desemnate sub numele de variabile sau atribute. Datele pot fi de orice tip, inclusiv alte clase. Declararea datelor se face:
[modificatorAcces] tipData nume;

unde: modificatorAcces - este opional. Implicit este private. tipData - reprezint tipul datei obiectului pe care vrem s-l atribuim. nume - se refer la numele dat de utilizator obiectului respectiv. Datele pot fi:

constante, cmpuri.

Constantele - descriu valori fixe, putnd fi valori calculate sau dependente de alte constante. n mod obligatoriu valoarea unei astfel de constante trebuie s fie calculat n momentul compilrii. Valoarea unei constante se declar prin cuvntul const. Sintaxa este:
[modificator] const tip identificator = expresieConstanta

[modificator] const tip identificator = expresieConstanta

unde tip poate fi: bool, decimal, sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, enum, string

90

Constanta mai poate avea ca modificator de acces: internal, protected internal, private.

new, public, protected,

Exemplul 65:
class Constante { public const int MAX = 100; const string SALUT = "Buna ziua!"; public const double MIN = MAX / 3.2; }

Cmpul - reprezint o dat variabil a unei clase. n afar de modificatorii menionai mai sus, se mai adaug: new, readonly, volatile, static. Opional, cmpurile pot fi iniializate cu valori compatibile. Un astfel de cmp se poate folosi fie prin specificarea numelui su, fie printr-o calificare bazat pe numele clasei sau al unui obiect. Sintaxa este:

tip identificator [=valoare]

Exemplul 66:
class Camp { public int varsta; protected string nume; private int id = 13; int a; //implicit private static void Main(string[] args) { Camp obiect = new Camp(); obiect.a = 1; } }

Cmpuri de instan n cazul n care ntr-o declaraie de cmp nu este inclus modificatorul static, atunci respectivul cmp se va regsi n orice obiect de tipul clasei curente care va fi instaniat. Deoarece un astfel de cmp are o valoare specific fiecrui obiect, accesarea lui se va face folosind numele obiectului: obiect.a = 1;

91

Un cmp special este this care reprezint o referin la obiectul curent

Cmpuri statice Dac ntr-o declaraie de cmp apare specificatorul static, cmpul respectiv va aparine clasei. Accesarea unui astfel de cmp din exteriorul clasei se poate face doar prin intermediul numelui de clas:

Exemplul 67:
class Camp { public static int a = 13; static void Main(string[] args) { Camp.a++; } }

Cmpuri readonly Pentru a declara un cmp readonly se va folosi cuvntul readonly n declaraia sa. Atribuirea se face doar la declararea sa, sau prin intermediul unui constructor:

Exemplul 68:
class Camp { public readonly string a = Exemplu; //camp readonly initializat public readonly string b; public class Camp(string b) //constructor {this.b = b;} //camp readonly initializat }

n momentul compilrii valoarea cmpului readonly nu se presupune a fi cunoscut.

Cmpuri volatile Cmpurile volatile se declar cu ajutorul cuvntului volatile, care poate fi ataat doar urmtoarelor tipuri:

byte, sbyte, short, ushort, int, uint, char, float, bool


92

un tip enumerare care are tipul: byte, sbyte, short, ushort, int, uint un tip referin

Iniializarea cmpurilor Valorile implicite pe care le iau cmpurile la declararea lor sunt: tip numeric bool char enum referin valoare 0 false \0 0 null

I.5.1.(2) Funcii
Funciile pot fi:

Constructori Destructori Metode Proprieti Evenimente Indexatori Operatori

I.5.1.(3)

Constructori

Definiie: Constructorii sunt funcii care folosesc la iniializarea unei instane a clasei. Constructorii au acelai nume cu al clasei. Constructorul poate avea un modificator de acces i nu returneaz nimic. Sintaxa este:
modificatorAcces numeConstructor([parametri])[:initializator] [{ corp_constructor }]
93

unde: initializator permite invocarea unui constructor anume, nainte de executarea instruciunilor care formeaz corpul constructorului curent. Iniializatorul poate lua dou forme: base([parametri]) sau this([parametri]). Dac nu se precizeaz niciun iniializator, implicit se va asocia base( ). n cazul n care nu definim nici un constructor, C# va crea unul implicit avnd corpul vid.

Exemplul 69:
class Elev { public Elev() { } }

//constructor

O clas poate conine mai muli constructori, difereniai dup numrul i tipul de parametri. Exemplul 70:
class Elev { public string nume; public Elev() //constructor { nume = ""; } public Elev(string Nume) //constructor { nume = Nume; } }

Apelul unui constructor se face automat la instanierea clasei prin operatorul new. Exemplul 71:
class Exemplu_71 { Elev elev = new Elev(); }

Exemplul 69: Constructor cu doi parametri

94

using System; namespace Complex { class Complex { private int re; private int im; //constructor cu doi parametri public Complex(int i, int j) { re = i; im = j; } public void Afis() { Console.WriteLine(re + "+" + im + "i"); } } class Program { static void Main(string[] args) { Complex c = new Complex(1, 2); c.Afis(); Console.ReadLine(); } } }

Observaie: Constructorii nu pot fi motenii.

I.5.1.(4) Destructori
Destructorul clasei implementeaz aciunile necesare distrugerii unei instane a clasei. Numele destructorului coincide cu numele clasei, fiind precedat de caracterul ~. Destructorul nu are parametri i nici modificator de acces. Destructorul este apelat automat. ntr-o clas exist un singur destructor. Destructorul nu poate fi motenit.

Exemplul 73:

95

using System; using System.Collections.Generic; using System.Text; namespace Mesaj { class Program { static void Main(string[] args) { Mesaj a = new Mesaj(); Console.ReadLine(); } class Mesaj { public Mesaj() { Console.WriteLine("Apel constructor"); } ~Mesaj() { Console.WriteLine("Apel destructor"); } } } }

I.5.1.2.3. Metode

Metoda este un membru al unei clase care implementeaz o aciune. Metoda poate admite parametri i returna valori. Tipul returnat de ctre o metod poate fi unul predefinit (int, bool etc.) sau de tip obiect (class). n cazul n care metoda nu returneaz nimic, tipul este void. Metodele pot fi supradefinite (suprancrcate), adic se pot defini mai multe metode, care s poarte acelai nume, dar s difere prin numrul i tipul de parametri. Valoarea returnat de ctre o metod nu poate s fie luat n considerare n cazul supradefinirii. Sintaxa este:
modificatorAcces tipReturnat numeMetoda([parametri]) [{ corp_Metoda }]

unde: modificatorAcces - este opional. n cazul n care lipsete se consider implicit


96

private. modificatorAcces poate fi orice modificatorAcces amintit, precum i new, static, virtual, sealed, override, abstract, extern. tipReturnat poate fi un tip definit sau void. numeMetoda - poate fi un simplu identificator sau, n cazul n care definete n mod explicit un membru al unei interfee, numele este de forma:
[numeInterfata].[numeMetoda]

parametri - lista de parametri formali este o succesiune de declarri desprite prin virgule, declararea unui parametru avnd sintaxa:

[atribut][modificator] tip nume

Modificatorul unui parametru poate fi ref (parametru de intrare i ieire) sau out (parametru care este numai de ieire). Parametrii care nu au niciun modificator sunt parametri de intrare.
Un parametru formal special este parametrul tablou cu sintaxa:
[atribut] params tip [ ] nume

Pentru metodele abstracte i externe, corpul metodei se poate reduce la un semn ; Semntura fiecrei metode este format din numele metodei, modificatorii acesteia, numrul i tipul parametrilor. Din semntur (amprent) nu fac parte tipul returnat, numele parametrilor
formali i nici specificatorii ref i out.

Numele metodei trebuie s difere de numele oricrui alt membru care nu este metod. La apelul metodei, orice parametru trebuie s aib acelai modificator ca la definire Invocarea unei metode se realizeaz prin:
[nume_obiect].[nume_metoda] [nume_clas].[nume_metoda]

pentru metodele nestatice pentru metodele statice

97

I.5.1.2.4. Proprieti Proprietatea este un membru al clasei care ne permite s accedem sau s modificm caracteristicile unui obiect sau al clasei. Sintaxa este:
[atribut]modificatorAcces tipReturnat numeProprietate { get { } set { } }

unde: modificatorAcces - poate fi orice modificatorAcces amintit, precum i new, static, virtual, sealed, override, abstract, extern. tipReturnat - poate fi orice tip valid n C#, el specificnd tipul folosit de accesorii get (tipul valorii returnate) i set (tipul valorii atribuite). Accesorul get corespunde unei metode fr parametri, care returneaz o valoare de tipul proprietii. Accesorul set corespunde unei metode cu un singur parametru, de tipul proprietii i tip de retur void. Dac proprietatea nu este abstract sau extern, poate s apar una singur dintre cele dou metode de acces sau amndou, n orice ordine. Este o manier de lucru recomandabil aceea de a proteja datele membru (cmpuri) ale clasei, definind instrumente de acces la acestea: pentru a obine valoarea cmpului respectiv (get) sau de a memora o anumit valoare n cmpul respectiv (set). Dac metoda de acces get este perfect asimilabil cu o metod ce returneaz o valoare (valoarea datei pe care vrem s-o obinem sau valoarea ei modificat conform unei prelucrri suplimentare specifice problemei n cauz), metoda set este asimilabil cu o metod care un parametru de tip valoare (de intrare) i care atribuie (sau nu, n funcie de context) valoarea respectiv cmpului. Cum parametrul
98

corespunztor valorii transmise nu apare n structura sintactic a metodei, este de tiut c el este implicit identificat prin cuvntul value. Exemplul 74:
using System; using System.Collections.Generic; using System.Text; namespace GetSet { class ClasaMea { private int x; public int P { get { Console.WriteLine("get"); return x; } set { Console.WriteLine("set"); x = value; } } } class Program { public static void Main(string[] args) { ClasaMea obiect = new ClasaMea(); //linia urmatoare apeleaza accesorul //'set' din proprietatea P si ii //paseaza 10 lui value obiect.P = 10; int xVal = obiect.P; // linia urmatoare apeleaza accesorul //'get' din proprietatea P Console.WriteLine(xVal); Console.ReadLine();

99

I.5.1.(5) Evenimente i delegri

Evenimentele sunt membri ai unei clase ce permit clasei sau obiectelor clasei s fac notificri, adic s anune celelalte obiecte asupra unor schimbri petrecute la nivelul strii lor. Clasa furnizoare a unui eveniment public (pune la dispoziia altor clase) acest lucru printr-o declarare event care asociaz evenimentului un delegat, adic o referin ctre o funcie necunoscut creia i se precizeaz doar antetul, funcia urmnd a fi implementat la nivelul claselor interesate de evenimentul respectiv. Este modul prin care se realizeaz comunicarea ntre obiecte. Tehnica prin care clasele implementeaz metode (handler-e) ce rspund la evenimente generate de alte clase poart numele de tratare a evenimentelor. Sintaxa:

[atribut][modificatorAcces]even tipDelegat nume

unde: modificatorAcces - este la fel ca n cazul metodelor tipDelegat este un tip de date, derivat din clasa sigilat Delegate din spaiul System. Definirea unui tipDelegat se realizeaz astfel: [atribut][modificatorAcces] delegate tipRezultat nume[listaParametri])

Un delegat se poate defini i n afara clasei generatoare de evenimente i poate servi i altor scopuri n afara tratrii evenimentelor
100

Exemplul 75: dorim s definim o metod asociat unui vector de numere ntregi, metod ce verific dac vectorul este o succesiune cresctoare sau descresctoare. O implementare generic se poate realiza folosind delegri:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Delegari { public delegate bool pereche_ok(object t1, object t2); public class Vector { public const int nmax = 4; public int[] v = new int[nmax]; public Vector() { Random rand = new Random(); for (int i = 0; i < nmax; i++) v[i] = rand.Next(0, 5); } public void scrie() { for (int i = 0; i < nmax; i++) Console.Write("{0}, ", v[i]); Console.WriteLine(); } public bool aranj(pereche_ok ok)//ok e o delegare ctre o //funcie necunoscut { for (int i = 0; i < nmax - 1; i++) if (!ok(v[i], v[i + 1])) return false; return true; } } class Program { public static bool f1(object t1, object t2) { if ((int)t1 >= (int)t2) return true; else return false; } public static bool f2(object t1, object t2) { if ((int)t1 <= (int)t2) return true; else return false; } static void Main(string[] args) { Vector x; do { x = new Vector(); x.scrie(); if (x.aranj(f1)) Console.WriteLine("Monoton descrescator"); if (x.aranj(f2)) Console.WriteLine("Monoton crescator"); } while (Console.ReadKey(true).KeyChar != '\x001B'); //Escape } } }

101

Revenind la evenimente, descriem pe scurt un exemplu teoretic de declarare i tratare a unui eveniment. n clasa Vector se consider c interschimbarea valorilor a dou componente ale unui vector e un eveniment de interes pentru alte obiecte sau clase ale aplicaiei. Se definete un tip delegat TD (s zicem) cu nite parametri de interes(de exemplu indicii componentelor interschimbate) i un eveniment care are ca asociat un delegat E (de tip TD). Orice obiect x din clasa Vector are un membru E (iniial null). O clas C interesat s fie ntiinat cnd se face vreo interschimbare ntr-un vector pentru a genera o animaie (de exemplu), va implementa o metod M ce realizeaz animaia i va aduga pe M (prin intermediul unui delegat) la x.E+=new [tip_delegat](M). Cumulnd mai multe astfel de referine, x.E ajunge un fel de list de metode (handlere). n clasa Vector, n metoda sort, la interschimbarea valorilor a dou componente se invoc delegatul E. Invocarea lui E realizeaz de fapt activarea tuturor metodelor adugate la E.

I.5.1.(6) Indexatori

Sunt cazuri n care are sens s tratm o clas ca un array. Cei care au studiat C++ vor observa c este o generalizare a suprancrcrii operatorului [ ] din respectivul limbaj. Sintaxa:
[atribut][modificatorIndexator] declaratorDeIndexator { declaratiiDeAccesor }

unde: modificatorIndexator poate fi new, public, protected, internal, private,

virtual, sealed, override, abstract, extern.

102

declaratorDeIndexator are forma:

tipReturnat this [listaParametrilorFormali]

unde: listaParametrilorFormali trebuie s conin cel puin un parametru, parametru care nu trebuie s fie de tipul ref sau out.

declaratiiDeAccesor asemntoare cu cele de la proprieti, trebuie s conin accesorul get sau accesorul set. Observaie: Indexatorii i proprietile sunt asemntoare n ceea ce privete utilizarea accesorilor get i set. Un indexator poate fi privit ca o proprietate cu mai multe valori. Pe cnd o proprietate poate fi declarat static, acest lucru este interzis n cazul indexatorilor. Cnd folosim un indexator, sintaxa este asemntoare cu cea de la vectori. Totui exist deosebiri:

indexatorii pot folosi indici nenumerici, pe cnd un vector trebuie s aib indicii de tip ntreg indexatorii pot fi supradefinii, la fel ca metodele, pe cnd vectorii nu indexatorii nu pot fi folosii ca parametrii ref sau out, pe cnd vectorii da

Exemplul 76:

103

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Exemplul_76 { class ClasaMea { private string[] data = new string[6]; public string this[int index] { get { return data[index]; } set { data[index] = value; } } } class Rezultat { public static void Main() { ClasaMea v = new ClasaMea(); v[0] = "Exemplu"; v[1] = "cu"; v[2] = "indexatori"; Console.WriteLine("{0} {1} {2}.", v[0], v[1], v[2]); Console.ReadLine(); } } }

I.5.1.(7)

Operatori

Definiie: operatorul este un membru care definete semnificaia unei expresii operator care poate fi aplicat unei instane a unei clase. Pentru cei care cunosc C++, operatorul corespunde suprancrcrii din respectivul limbaj. Sintaxa:
[atribut] modificatorOperator declaratieDeOprator corpOperator

Observaia 1: Operatorii trebuiesc declarai publici sau statici. Observaia 2: Parametrii operatorilor trebuie s fie de tip valoare. Nu se admit parametri de tip ref sau out.

104

Observaia 3: n antetul unui operator nu poate aprea, de mai multe ori, acelai modificator. Se pot declara operatori: unari, binari i de conversie. Operatori unari Suprancrcarea operatorilor unari are urmtoarea sintax:
tip operatorUnarSuprancrcabil (tip identificator) corp

Operatorii unari suprancrcabili sunt: + - ! ++ true false. Reguli pentru suprancrcarea operatorilor unari: Fie T clasa care conine definiia operatorului 1. Un operator + - ! poate returna orice tip i preia un singur parametru de tip T 2. Un operator ++ sau - trebuie s returneze un rezultat de tip T i preia un singur parametru de tip T 3. Un operator unar true sau false returneaz bool i trebuie s preia un singur parametru de tip T. Operatorii true i false trebuie s fie ambii definii pentru a prevenii o eroare de compilare. Exemplul 77:
using using using using System; System.Collections.Generic; System.Linq; System.Text;

namespace Exemplul_77 { class Complex { private int x; private int y; public Complex() { } public Complex(int i, int j) { x = i; y = j; } public void Afis() { Console.WriteLine("{0} {1}i", x, y); } public static Complex operator -(Complex c) { Complex temp = new Complex(); temp.x = -c.x; temp.y = -c.y; return temp; }

105

class Program { public static void Main() { Complex c1 = new Complex(10, 13); c1.Afis(); Complex c2 = new Complex(); c2.Afis(); c2 = -c1; c2.Afis(); Console.ReadLine(); } } }

Operatori binari Suprancrcarea operatorilor binari are urmtoarea sintax:


tip operator operatorBinarSuprancrcabil (tip identificator, tip identificator) corp

Operatorii binari suprancrcabili sunt: + - * / & | ^ << >> == != > < >= <= Reguli pentru suprancrcarea operatorilor binari: 1. Cel puin unul din cei doi parametri trebuie s fie de tipul clasei n care respectivul operator a fost declarat 2. Operatorii de shift-are trebuie s aib primul parametru de tipul clasei n care se declar, iar al doilea parametru de tip int 3. Un operator binar poate returna orice tip 4. Urmtorii operatori trebuie s se declare n pereche: a. operatorii == i != b. operatorii > i < c. operatorii >= i <= Exemplul 78:

106

using using using using

System; System.Collections.Generic; System.Linq; System.Text;

namespace ExempluOperatori { class Complex { private int x; private int y; public Complex() { } public Complex(int i, int j) { x = i; y = j; } public void Afis() { Console.WriteLine("{0} {1}", x, y); }

} class Program { static void Main(string[] args) { Complex c1 = new Complex(1, 2); Console.Write("c1: "); c1.Afis(); Complex c2 = new Complex(3, 4); Console.Write("c2: "); c2.Afis(); Complex c3 = new Complex(); c3 = c1 + c2; Console.WriteLine("\nc3 = c1 + c2\n"); Console.Write("c3: "); c3.Afis(); Console.ReadLine(); } } }

public static Complex operator +(Complex c1, Complex c2) { Complex temp = new Complex(); temp.x = c1.x + c2.x; temp.y = c1.y + c2.y; return temp; }

Operatori de conversie

107

Operatorul de conversie introduce o conversie definit de utilizator. Aceast conversie nu va suprascrie conversiile predefinite. Operatorii de conversie pot fi:

implicii se efectueaz de la un tip mai mic la un tip mai mare i reuesc ntotdeauna, nepierzndu-se date explicii se efectueaz prin intermediul expresiilor de conversie, putndu-se pierde date Sintaxa:
implicit operator tip(tip parametru) corp explicit operator tip(tip parametru) corp

Un operator de acest tip va face conversia de la tipul sursa (S) (tipul parametrului din antet) n tipul destinaie (D) (tipul returnat). O clas poate s declare un operator de conversie de la un tip S la un tip D dac: 1. S i D au tipuri diferite 2. S sau D este clasa n care se face definirea 3. S i D nu sunt object sau tip interfa 4. S i D nu sunt baze una pentru cealalt Exemplu 79: conversii dintr-un tip de baz ntr-o clas i un tip clas ntr-un tip de baz folosind conversia operator:
using using using using System; System.Collections.Generic; System.Linq; System.Text;

namespace Exemplul_79 { class MyDigit { private int x; public MyDigit() { } public MyDigit(int i) { x = i; } public void ShowDigit() { Console.WriteLine("{0}", x); } public static implicit operator int(MyDigit md) { return md.x; } public static explicit operator MyDigit(int val) { return new MyDigit(val); } }
108

class Program { public static void Main(string[] args) { MyDigit md1 = new MyDigit(10); int x = md1; //Implicit Console.WriteLine(x); int y = 25; MyDigit md2 = (MyDigit)y; //Explicit md2.ShowDigit(); Console.ReadLine(); } }

Exemplul 80: Conversia dintr-un tip clas n altul folosind conversia operator:

109

using using using using

System; System.Collections.Generic; System.Linq; System.Text;

namespace OperatoriImplicitiExpliciti { class Clasa1 { public int x; public Clasa1(int a) { x = a; } public void Afis1() { Console.WriteLine(x); } public static explicit operator Clasa2(Clasa1 mc1) { Clasa2 mc2 = new Clasa2(mc1.x * 10, mc1.x * 20); return mc2; } } class Clasa2 { public float x, y; public Clasa2(float a, float b) { x = a; y = b; } public void Afis2() { Console.WriteLine(x); Console.WriteLine(y); } } class Program { public static void Main(string[] args) { Clasa1 mc1 = new Clasa1(100); mc1.Afis1(); Clasa2 mc2 = (Clasa2)mc1; mc2.Afis2(); Console.ReadLine(); } } }

110

I.6.

Clase i funcii generice

Definiie: genericele sunt abloane (templates) sau modele care ajut la reutilizarea codului. Ele descriu clase i metode care pot lucra ntr-o manier uniform cu tipuri de valori diferite. Ele permit definirea de funcionaliti i metode care se adapteaz la tipurile parametrilor pe care i primesc, ceea ce permite construirea unui ablon. Singura diferen fa de declararea n mod obinuit a unei clase, este prezena caracterelor < i >, care permit definirea tipului pe care stiva l va avea, ca i cum ar fi un parametru al clasei. La instanierea clasei trebuie s declarm tipul datelor utilizate. Tipurile generice (parametrizate) permit construirea de clase, structuri, interfee, delegai sau metode care sunt parametrizate printr-un tip pe care l pot stoca sau manipula.

Exemplul 81: S considerm clasa Stiva care permite stocarea de elemente. Aceast clas are dou metode Push() care permite introducerea de elemente i Pop() care permite extragerea de elemente din stiv.
public class Stiva<TipElement> //clasa generica { private TipElement[] element; public void Push(TipElement data) { // code corespunzator introducerii de elemente } public TipElement Pop() { // code corespunzator extragerii de elemente } } Stiva<char> StivaMea = new Stiva<char>(); StivaMea.Push("a"); char x = StivaMea.Pop();

Exemplul 82: tipurile parametrizate pot fi aplicate claselor i interfeelor

111

interface IGeneric1<T> { } class ClassGeneric1<UnTip, Altul> { } class ClassInt1 : ClassGeneric1<int, int> { } class ClassInt2<T> : ClassGeneric1<int, T> { } class ClassInt3<T, U> : ClassGeneric1<int, U> { }

Exemplul 83: tipurile parametrizate se pot aplica metodelor


class clA { public void methode1<T>() { } public T[] methode2<T>() { return new T[10]; } }

Exemplul 84:

Dorim s implementm o clas Stiva care s permit adugarea i extragerea de

elemente. Pentru a simplifica problema, vom considera c stiva nu poate conine dect un anumit numr de elemente, ceea ce ne va permite s utilizm tablouri n C#.
using using using using System; System.Collections.Generic; System.Linq; System.Text;

namespace Exemplul_84 { class Stiva { private object[] m_ItemsArray; private int m_Index = 0; public const int MAX_SIZE = 100; public Stiva() { m_ItemsArray = new object[MAX_SIZE]; } public Object Pop() { if (m_Index == 0) throw new InvalidOperationException("Nu putem extrage un element dintr-o stiva vida."); return m_ItemsArray[--m_Index]; }

112

public void Push(Object item) { if (m_Index == MAX_SIZE) throw new StackOverflowException("Nu se poate adauga un elemet: stiva este plina."); m_ItemsArray[m_Index++] = item; } } class Program { static void Main(string[] args) { Stiva stiva = new Stiva(); stiva.Push(1234); int numar = (int)stiva.Pop(); } }

Implementarea sufer de cteva probleme:


elementele clasei Stiva trebuie s fie convertite explicit atunci cnd se folosete clasa Stiva cu elemente element de tip valoare, se realizeaz implicit o operaie de boxing cu inserarea unui element i o operaie de tip unboxing cu recuperarea unui dorim s introducem n stiv elemente de tipuri diferite n aceea i instan a clasei Stiva. Acest lucru va duce la probleme de convertire care vor fi descoperite la execuie Deoarece problema conversiei nu este detectat la compilare, va produce o excepie la

execuie. Din acest motiv spunem: codul nu este type-safe. Pentru a rezolva aceste neajunsuri s-ar putea implementa un cod pentru stive cu elemente de tip int, alt cod pentru elemente de tip sir de caractere. Acest lucru duce la dublarea unor poriuni din cod. Acest lucru se va rezolva cu ajutorul tipurilor generice. C# ne permite rezolvarea unor astfel de probleme introducnd tipurile generice. Concret putem implementa o list de elemente de tip T, lsnd libertatea utilizatorului s specifice tipul T la instanierea clasei.

113

Exemplul 85:

using using using using

System; System.Collections.Generic; System.Linq; System.Text;

namespace Exemplul_85 { class Stiva<T> { private T[] m_ItemsArray; private int m_Index = 0; public const int MAX_SIZE = 100; public Stiva() { m_ItemsArray = new T[MAX_SIZE]; } public T Pop() { if (m_Index == 0) throw new InvalidOperationException("Nu putem extrage un element dintr-o stiva vida."); return m_ItemsArray[--m_Index]; } public void Push(Object item) { if (m_Index == MAX_SIZE) throw new StackOverflowException("Nu se poate adauga un elemet: stiva este plina."); m_ItemsArray[m_Index++] = item; } } class Program { static void Main(string[] args) { Stiva<int> stiva = new Stiva<T>(); stiva.Push(1234); int numar = stiva.Pop(); //nu mai este necesar cast Stiva<string> sstiva = new Stiva<string>(); sstiva.Push("4321"); string sNumar = sstiva.Pop(); } }

I.7.

Derivarea claselor (motenire)


Principiile motenirii

I.7.1.

Prin utilizarea motenirii se poate defini o clas general care definete trsturi comune la un ansamblu de obiecte. Aceast clas poate fi motenit de ctre alte clase specifice, fiecare dintre acestea adugnd elemente care-i sunt unice ei.

114

O clas care este motenit se numete clas de baz sau superclas, iar o clas care o motenete pe aceasta se numete clas derivat, sau subclas, sau clas descendent.

Pe baza a ceea ce am amintit, putem spune c o clas derivat este o versiune specializat sau extins a clasei de baz. Clasa derivat motenete toate elementele clasei de baz i-i adaug altele proprii. Clasa derivat nu poate s tearg nici un membru al clasei de baz.

Definirea unei clase derivate se face folosind sintaxa:


class ClasaDerivata : ClasaDeBaza { }

O clas derivat poate la rndul ei s fie clas de baz pentru o alt clas. n acest fel se poate defini noiunea de ierarhie de clase. Limbajul C#, spre deosebire de C++, admite doar motenirea simpl, n sensul c derivarea se admite doar dintr-o clas de baz, fiind permis doar derivarea public n contextul mecanismelor de motenire trebuie amintii modificatorii abstract i sealed aplicai unei clase, modificatori ce oblig la i respectiv se opun procesului de derivare. Astfel, o clas abstract trebuie obligatoriu derivat, deoarece direct din ea nu se pot obine obiecte prin operaia de instaniere, n timp ce o clas sigilat (sealed) nu mai poate fi derivat (e un fel de terminal n ierarhia claselor). O metod abstract este o metod pentru care nu este definit o implementare, aceasta urmnd a fi realizat n clasele derivate din clasa curent. O metod sigilat nu mai poate fi redefinit n clasele derivate din clasa curent.

Muzician

clasa de baz (clasa general)

Violonist

clasa derivat (clasa specializat)

Exemplul 86:

115

using System; using System.Collections.Generic; using System.Text; namespace Exemplul_86 { class Muzician { public void Canta(string nume) { Console.WriteLine("{0} canta", nume); } } class Violonist : Muzician { public void CantaLaVioara(string nume) { Console.WriteLine("{0} canta la vioara", nume); } } class Program { static void Main(string[] args) { Muzician m = new Muzician(); m.Canta("Ilie"); Violonist n = new Violonist(); n.Canta("Andrei"); n.CantaLaVioara("Andrei"); Console.ReadLine(); } } }

I.7.2.

Accesibilitatea membrilor motenii

Deseori, n procesul derivrii, avem nevoie de acces la membrii motenii ai clasei de baz. Pentru aceasta se va folosi o expresie de tip base access. De exemplu, dac MembruB este un membru al clasei de baz, pentru a-l folosi ntr-o clasa derivat vom folosi, n aceasta, o expresie de forma:
base.MembruB

116

Exemplul 84: apelul din clasa derivat a unui membru al clasei de baz

using System; using System.Collections.Generic; using System.Text; namespace Exemplul_87 { class Program { class ClasaDeBaza { public string sir = "Sir din clasa de baza"; } class ClasaDerivata : ClasaDeBaza { public string sir = "Sir din clasa derivata"; public void afis() { Console.WriteLine("{0}", sir); Console.WriteLine("{0}", base.sir); } } static void Main(string[] args) { ClasaDerivata cd = new ClasaDerivata(); cd.afis(); Console.ReadLine(); } } }

I.7.2.(1) Utilizarea cuvntului cheie protected


Cuvntul cheie protected permite restrngerea accesului unui membru al clasei de baz doar la clasele sale derivate. Membrii protejai motenii devin n mod automat protejai.

I.7.3. Apelul constructorilor clasei de baz


Exemplul 88:
117

class ClasaDeBaza { protected string var; public ClasaDeBaza(string var) { this.var = var; } }

//constructor

clasa Derivata : ClasaDeBaza { public ClasaDeBaza(string var) : base(var) { ... } }

I.7.3.

Metode

Prin mecanismul de motenire avem posibilitatea reutilizrii codului i redefinirii (prin polimorfism) a metodelor.

I.7.3.(1) Virtual i override


O clas declarat virtual implic faptul c o metod implementat n ea poate fi redefinit n clasele derivate. Doar metodele virtuale ne statice i/sau private pot fi redefinite ntr-o clas derivat. Aceste metode trebuie s aib aceeai signatur (nume, modificator de acces, tip returnat i parametri). Pentru declararea unei metode ca fiind virtual se folosete cuvntul cheie virtual. n clasele derivate se va folosi cuvntul cheie override pentru redefinirea metodei virtuale din clasa de baz.

Exemplul 89:

118

class ClasaDeBaza { public virtual void Metoda() { ... } } class Derivata : ClasaDeBaza { public override void Metoda() { ... } }

I.7.3.(2)

new

Exist cazuri n care n loc s redefinim o metod avem nevoie s specificm c metoda clasei derivate este o implementare nou a respectivei metode. Pentru aceasta vom folosi new cu semnificaia c metoda are aceeai signatur cu a celei din clasa de baz, dar dorim s mascm definirea ei n clasa de baz. Exemplul 90:

class ClasaDeBaza { public virtual void Metoda() { ... } } class Derivata : ClasaDeBaza { public new void Metoda() { ... } }

I.7.4.

Interfee

Interfeele sunt foarte importante n programarea orientat pe obiecte, deoarece permit utilizarea polimorfismului ntr-un sens mai extins. Definiie: O interfa este o component a aplicaiei, asemntoare unei clase, care declar prin membrii si (metode, proprieti, evenimente i indexatori) un comportament unitar aplicabil mai multor clase, comportament care nu se poate defini prin ierarhia de clase a aplicaiei. De exemplu, dac vom considera arborele din figura urmtoare, n care AVERE este o clas abstract, iar derivarea claselor a fost conceput urmrind proprietile comune ale componentelor
119

unei averi, atunci o clas VENIT nu este posibil, deoarece ea ar moteni de la toate clasele evideniate, iar motenirea multipl nu este admis n C#.

AVERE
Proprietate Imobiliara Teren Productiv Neproductiv Imobil De_folosin
I_inchiriat

Bani Bun Depunere B_inchiriat Mobilier Altul Investiie Credit_primit Actiune Cot
Credit_acordat

VENIT
(din produse, din chirii, din dobnzi, dividende) calc()

Pentru metodele din cadrul unei interfee nu se d nici o implementare, ci sunt pur i simplu specificate, implementarea lor fiind furnizat de unele dintre clasele aplicaiei. Acele clase care ader la o interfa spunem c implementeaz interfaa respectiv. Nu exist instaniere n cazul interfeelor, dar se admit derivri, inclusiv moteniri multiple. n exemplul nostru, se poate defini o interfa VENIT care s conin antetul unei metode calc (s zicem) pentru calculul venitului obinut, fiecare dintre clasele care implementeaz interfaa VENIT fiind obligat s furnizeze o implementare (dup o formul de calcul specific) pentru metoda calc din interfa. Orice clas care dorete s adere la interfa trebuie s implementeze toate metodele din interfa. Toate clasele care motenesc dintr-o clas care implementeaz o interfa motenesc, evident, metodele respective, dar le pot i redefini (de exemplu, clasa Credit_acordat redefinete metoda calc din clasa Investiie, deoarece formula de calcul implementat acolo nu i se potrivete i ei. Dac n sens polimorfic spunem c Investiie este i de tip Bani i de tip Avere, tot aa putem spune c o clas care implementeaz interfaa VENIT i clasele derivate din ea sunt i de tip VENIT). De exemplu, dac presupunem c toate clasele subliniate implementeaz interfaa VENIT, atunci pentru o avere cu aciuni la dou firme, un imobil nchiriat i o depunere la banc, putem determina venitul total: Exemplul 91:

120

Actiune act1 = new Actiune(); Actiune act2 = new Actiune(); I_inchiriat casa = new I_inchiriat(); Depunere dep=new Depunere(); Venit[] venituri = new Venit()[4]; venituri[0] = act1; venituri[1] = act2; venituri[2] = casa; venituri[3] = dep; ... int t=0; for(i=0;i<4;i++) t+=v[i].calc();

I.8.

Tratarea excepiilor n C#

Definiie: O excepie este un obiect care ncapsuleaz informaii despre o situaie anormal. Excepia se folosete pentru a semnala contextul n care apare acea situaie deosebit Observaie: Nu trebuie confundat termenul de excepie cu cel de eroare sau bug. Excepiile nu sunt concepute pentru prevenirea bug-urilor. Chiar dac programatorul elimin toate bug-urile din programul su pot aprea erori pe care el nu le poate preveni:

ncercare de deschidere a unui fiier inexistent mpriri la zero etc.

n cazul n care o metod ntlnete o astfel de excepie, atunci respectiva excepie va trebui prins n vederea tratrii (rezolvrii) ei. n C# se pot arunca ca excepii obiecte de tip System.Exception sau derivate ale lui. Pe lng ierarhia de excepii pe care limbajul C# o are inclus, programatorul i poate crea propriile sale tipuri excepie. Exception

SystemException

OutOfMemoryException

IOException

NullReferenceException

AplicationException

Ierarhia excepiilor
121

Dintre metodele i proprietile clasei Exception amintim: Metodele i proprietile clasei Exception
public Exception( ) public Exception (string) public Exception (string, Exception)

Explicaii sunt constructori

public virtual string HelpLink {get; set}

public Exception InnerException {get;} public virtual string Message {get;} public virtual string Source {get; set;}

public virtual string StackTrace {get;}

public MethodBase TargetSite {get;}

observm c o excep ie poate conine n interiorul s o instan a unei alte excepii obine sau seteaz o legtur ctre fiierul Help asociat excepiei, sau ctre o adres Web returneaz excepia care este ncorporat n excepia curent obine un mesaj care descrie excepia curent obine sau seteaz numele aplicaiei sau al obiectului care a cauzat eroarea obine o reprezentare de tip string a apelurilor de metode care au dus la apariia excepiei obine metoda care a aruncat excepia curent

C# definete cteva excepii standard derivate din System.Exception. Acestea sunt generate cnd se produc erori la execu ia programului. Dintre acestea amintim: Excepia
ArrayTypeMismatchException DivideByZeroException IndexOutOfRangeException InvalidCastException OutOfMemoryException OverflowException StackOverflowException

Explicaii Incompatibilitate ntre tipul valorii memorate i tipul tabloului ncercare de mprire la zero Indexul tabloului depete marginile definite Operatorul cast incorect la execuie Datorit memoriei insuficiente apelul lui new eueaz Depire aritmetic Depirea capacitii (definite) stivei

Observaie: Este posibil definirea de ctre programator a propriilor clase de excepii. Acestea vor fi derivate din ApplicationException.

122

I.8.1.

Aruncarea i prinderea excepiilor

I.8.1.(1) Blocurile try i catch


POO ofer o soluie pentru gestionarea erorilor: folosirea blocurilor try i catch. n

scrierea codului, programatorul va separa acele instruciuni care sunt sigure (adic nu pot fi generatoare de excepii), de cele care sunt susceptibile s conduc la erori. Partea de program care poate genera excepii o vom plasa ntr-un bloc try, iar partea corespunztoare tratrii excepiei, ntr-un bloc catch. n cazul n care blocul try genereaz o excepie, Runtime ntrerupe execuia i caut un bloc catch apropiat care, n funcie de tipul su s poat trata respectiva eroare. n cazul n care este gsit respectivul bloc catch programul continu cu instruciunile din corpul catch. n cazul n care nu se gsete nici un catch corespunztor, execuia programului este ntrerupt. Avnd n vedere c ntr-un corp try pot s apar excepii diferite, n program pot exista mai multe blocuri corespunztoare catch.

Exemplul 91:
using using using using System; System.Collections.Generic; System.Linq; System.Text;

namespace Exceptii1 { class Program { static void Main(string[] args) { try { Console.Write("Introduceti un numar "); int i = int.Parse(Console.ReadLine()); Console.Write("Introduceti inca un numar "); int j = int.Parse(Console.ReadLine()); int x = i / j; } catch (OverflowException e) { Console.WriteLine("Numarul nu este intreg"); //Console.WriteLine(e); }

//(1) //(2)

123

/* catch (DivideByZeroException e) { //Console.WriteLine(e); //(3) Console.WriteLine("Exceptia DivideByZero"); //(4) }*/ Console.WriteLine("Programul ruleaza in continuare");//(5)

S analizm puin programul de mai sus:

Dac liniile (2) i (3) nu sunt comentate, n urma execuii programului, respectivele linii afieaz informaii despre excepiile aprute. Liniile (1) i (4) au fost puse pentru a personaliza informaiile referitoare la excepiile aprute. Linia (5) a fost pus n program pentru a demonstra rularea fr probleme, n cazul n care blocurile catch exist. ncercai s comentai unul dintre blocurile catch, introducei date care s produc excepia pe care blocul comentat ar trata-o i vei observa ntreruperea, cu mesaj de eroare a rulrii programului. Observaie: Pentru a intercepta orice excepii, indiferent de tipul lor se va folosi catch fr

parametru. Prin aceasta se va crea o rutin care va intercepta i trata toate excepiile.

I.8.1.(2) Instruciunea throw


Programatorul poate s-i compun modaliti proprii de aruncare a erorilor folosind instruciunea throw: throw new NumeExceptie(exceptie); unde: NumeExceptie trebuie s fie numele unei clase apropiate de excepia avut n vedere excepie este un mesaj care apare n cazul n care apare excepia, iar aceasta nu este prins cu catch

124

Exemplul 92:
class Program { static void Main(string[] args) { try //(1) { //(2) Console.Write("Introduceti o cifra "); int i = int.Parse(Console.ReadLine()); if (i < 0 || i > 9) { string exceptie = i + " nu este o cifra"; //(0) throw new ArgumentOutOfRangeException(exceptie); } } //(3) catch (ArgumentOutOfRangeException) //(4) { //(5) Console.WriteLine("Nu este cifra"); //(6) } //(7) Console.WriteLine("Programul ruleaza in continuare"); } } }

S analizm programul de mai sus:

Dac comentm liniile (1), (2), (3), (4), (5), (6), (7) i la rularea programului introducem un numr n loc de o cifr, programul se oprete din execuie, iar ca mesaj apare utilizator n linia (0) irul definit de

Dac vom comenta doar liniile aferente blocului catch (4), (5), (6), (7), apare un mesaj de eroare privind faptul c se ateapt un bloc catch sau finally Dac nici una dintre liniile programului nu este comentat, la rulare, chiar dac introduce un numr n loc de o cifr vom obine:

125

I.8.1.(3) Blocul finally


Limbajul C# permite ca la ieirea dintr-un bloc try s fie executate obligatoriu, n cazul n care programatorul dorete acest lucru, anumite instruciuni. Pentru acest lucru, respectivele instruciuni vor fi plasate ntr-un bloc finally. Blocul finally este util fie pentru a evita scrierea unor instruciuni de mai multe ori, fie pentru a elibera resursele dup prsirea excepiei.

I.9.

Polimorfism
I.9.1. Introducere

n Capitolul 3 defineam noiunea de polimorfism, folosind o extensie a sensului etimologic: un obiect polimorfic este cel capabil s ia diferite forme, s se afle n diferite stri, s aib comportamente diferite. Polimorfismul obiectual, care trebuie s fie abstract, se manifest n lucrul cu obiecte din clase aparinnd unei ierarhii de clase, unde, prin redefinirea unor date sau metode, se obin membri diferii avnd ns acelai nume. Pentru a permite acest mecanism, metodele care necesit o decizie contextual (n momentul apelului), se declar ca metode virtuale (cu modificatorul virtual). n mod curent, n C# modificatorului virtual al funciei din clasa de baz, i corespunde un specificator override al funciei din clasa derivat ce redefinete funcia din clasa de baz. O metod ne-virtual nu este polimorfic i, indiferent de clasa creia i aparine obiectul, va fi invocat metoda din clasa de baz.
126

Limbajul C# admite trei tipuri de polimorfism:


polimorfism parametric polimorfism ad-hoc polimorfism de motenire

I.9.2.

Polimorfismul parametric

Aceast form de polimorfism este preluat de la limbajele neobiectuale: Pascal, C. Prin aceast form de polimorfism, o funcie va prelucra orice numr de parametri. Pentru aceasta se va folosi un parametru de tip params. Exemplul 93: S considerm o funcie F cu un parametru formal, de tip vector, declarat folosind modificatorul params. Acest lucru va permite folosirea mai multor parametri actuali, la apelul funciei, prin intermediul acelui singur parametru formal.

using using using using

System; System.Collections.Generic; System.Linq; System.Text;

namespace Exemplul_93 { class Program { static void F(params int[] arg) { Console.WriteLine("Apelul functiei F cu {0} parametri:", arg.Length); for (int i = 0; i < arg.Length; i++) { Console.WriteLine("arg[{0}] = {1}", i, arg[i]); } Console.WriteLine(""); } static void Main(string[] args) { F(); F(2); F(4, 6); F(new int[] { 1, 2, 3 }); } } }

127

I.9.3.

Polimorfismul ad-hoc

Acest tip de polimorfism se mai numete i suprancrcarea metodelor. Prin acest mecanism se pot defini n cadrul unei clase mai multe metode, toate avnd acelai nume, dar cu tipul i numrul de parametri diferii. La compilare, n funcie de parametri folosii la apel, se va apela o funcie sau alta. Exemplul 94:
using using using using System; System.Collections.Generic; System.Linq; System.Text;

namespace PolimorfismAdHoc { class Program { static void F() { Console.WriteLine("Functia F fara parametri\n"); } static void F(int a, int b) { Console.WriteLine("Functia F cu doi parametri: int si respectiv int\n"); } static void F(int a, double b) { Console.WriteLine("Functia F cu doi parametri: int si respectiv float\n"); } static void Main(string[] args) { F(); F(2, 3); F(4, 6.3); } } }
128

I.9.4.

Polimorfismul de motenire

n cazul acestui tip de motenire vom discuta ntr-o ierarhie de clase. n acest caz ne punem problema apelrii metodelor, avnd aceeai list de parametri formali, metode ce fac parte din clase diferite.
Exemplul 95:
using using using using System; System.Collections.Generic; System.Linq; System.Text;

namespace Exemplul_95 { class Baza { public void Afis() { Console.WriteLine("Apelul functiei Afis din clasa de baza\n"); } } class Derivata : Baza { public void Afis() { Console.WriteLine("Apelul functiei Afis din clasa derivata\n"); } } class Program { static void Main(string[] args) { Derivata obiect2 = new Derivata(); Baza obiect1 = obiect2; obiect1.Afis(); //(1) obiect2.Afis(); //(2) } } }
129

S discutm despre prima linie afiat (cea de-a doua este evident). Apelul lui Afis() se rezolv n momentul compilrii pe baza tipului declarat al obiectelor. Deci linia (1) din program va duce la apelul lui Afis() din clasa Baza, chiar dac obiect1 a fost instaniat pe baza unui obiect din clasa Derivata.

I.9.5.

Modificatorii virtual i override

n cazul n care se dorete ca apelul metodelor s se fac la rulare i nu la compilare vom reconsidera exemplul anterior n care funcia Afis( ) din clasa de baz o declarm virtual, iar funcia Afis( ) din clasa derivat o considerm ca suprascriere a lui Afis( ) din clasa de baz: Exemplul 96:
using using using using System; System.Collections.Generic; System.Linq; System.Text;

namespace Exemplul_96 { class Baza { public virtual void Afis() { Console.WriteLine("Apelul functiei Afis din clasa de baza\n"); } } class Derivata : Baza { public override void Afis() { Console.WriteLine("Apelul functiei Afis din clasa derivata\n"); } } class Program { static void Main(string[] args) { Derivata obiect2 = new Derivata(); Baza obiect1 = obiect2; obiect1.Afis(); //(1) obiect2.Afis(); //(2) } } }
130

I.9.6.

Modificatorul new

n cazul n care se dorete ca o metod dintr-o clas derivat s aib aceeai semntur cu o metod dintr-o clas de baz, dar s nu fie considerat o suprascriere a ei, vom folosi modificatorul new. Exemplul 97:
using using using using System; System.Collections.Generic; System.Linq; System.Text;

namespace PolimorfismDeMostenire { class Baza { public virtual void Afis() { Console.WriteLine("Apelul functiei Afis din clasa de baza\n"); } } class Derivata : Baza { public new void Afis() // !!! new { Console.WriteLine("Apelul functiei Afis din clasa derivata\n"); } } class Program { static void Main(string[] args) { Derivata obiect2 = new Derivata(); Baza obiect1 = obiect2; obiect1.Afis(); //(1) obiect2.Afis(); //(2) } } }

131

I.9.7.

Metoda sealed

O metod avnd tipul override poate fi declarat sealed. n acest fel ea nu mai poate fi suprascris ntr-o clas derivat

Exemplul 98:
using System; using System.Collections.Generic; using System.Text; namespace Exemplul_98 { class Baza { public virtual void Afis() { Console.WriteLine("Apelul functiei Afis din } } class Derivata : Baza { sealed override public void Afis() { Console.WriteLine("Apelul functiei Afis din } } class Derivata2 : Derivata { override public void Afis() //!!! EROARE { Console.WriteLine("Apelul functiei Afis din } } class Program { static void Main(string[] args) { Derivata obiect2 = new Derivata(); Baza obiect1 = new Derivata(); Derivata2 obiect3 = new Derivata2(); obiect1.Afis(); obiect2.Afis(); obiect3.Afis(); } } }
132

clasa de baza\n");

clasa derivata\n");

!!! clasa Derivata2\n");

//(1) //(2)

Va genera eroare, deoarece modificatorul sealed al metodei Afis(), din clasa Derivata, va mpiedic suprascrierea acestei metode n clasa Derivata2.

II. Programare vizual II.1. Concepte de baz ale programrii vizuale

Programarea vizual trebuie privit ca un mod de proiectare a unui program prin operare direct asupra unui set de elemente grafice (de aici vine denumirea de programare vizual). Aceast operare are ca efect scrierea automat a unor secvene de program, secvene care, mpreun cu secvenele scrise textual vor forma programul. Spunem c o aplicaie este vizual dac dispune de o interfa grafic sugestiv i pune la dispoziia utilizatorului instrumente specifice de utilizare (drag, clic, hint etc.) Realizarea unei aplicaii vizuale nu const doar n desenare i aranjare de controale, ci presupune n principal stabilirea unor decizii arhitecturale, decizii ce au la baz unul dintre modelele arhitecturale de baz. n realizarea aplicaiei mai trebuie respectate i principiile proiectrii interfeelor:

Simplitatea: Interfaa trebuie s fie ct mai uor de neles i de nvat de ctre utilizator i s permit acestuia s efectueze operaiile dorite n timp ct mai scurt. n acest sens, este vital culegerea de informaii despre utilizatorii finali ai aplicaiei i a modului n care acetia sunt obinuii s lucreze. Poziia controalelor: Locaia controalelor dintr-o fereastr trebuie s reflecte importana relativ i frecvena de utilizare. Astfel, cnd un utilizator trebuie s introduc nite informaii unele obligatorii i altele opionale este indicat s organizm controalele astfel nct primele s fie cele care preiau informaii obligatorii. Consistena: Ferestrele i controalele trebuie s fie afiate dup un design asemntor (template) pe parcursul utilizrii aplicaiei. nainte de a implementa interfaa, trebuie decidem cum va arta aceasta, s definim template-ul. Estetica: Interfaa trebuie s fie pe ct posibil plcut i atrgtoare.

133

II.2.

Mediul de dezvoltare Visual C# (prezentarea interfeei)

Mediul de dezvoltare Microsoft Visual C# dispune de instrumente specializate de proiectare, ceea ce permite crearea aplicaiilor n mod interactiv, rapid i uor. Pentru a construi o aplicaie Windows (FileNew Project) se selecteaz ca template Windows Forms Application.

O aplicaie Windows conine cel puin o fereastr (Form) n care se poate crea o interfa cu utilizatorul aplicaiei. Componentele vizuale ale aplicaiei pot fi prelucrate n modul Designer (Shift+F7) pentru a plasa noi obiecte, a le stabili proprietile etc. Codul din spatele unei componente vizuale este accesibil n modul Code (F7). n fereastra Solution Explorer sunt afiate toate fiierele pe care Microsoft Visual C# 2008 Express Edition le-a inclus n proiect. Form1.cs este formularul creat implicit ca parte a proiectului. Fiierul Form1.cs conine un formular (fereastra Form1 derivata din clasa Form) care este reprezentat n cadrul din dreamt n formatul Design (Form1.cs[Design], adic ntr-un format in
134

care se poate executa proiectare vizual, prin inserarea controalelor necesare selectate din fereastra Toolbox, care se activeaz atunci cnd este atins cu mouse-ul. Fiierul Form1.cs poate fi vzut ca fiier text surs prin selectarea lui n fereastra Solution Explorer, clic dreapta cu mouse-ul i selecia opiunii View Code. Fereastra Properties (Ctrl+W,P) este utilizat pentru a schimba proprietile obiectelor. Toolbox (Ctrl+W,X) conine controale standard drag-and-drop i componente utilizate n crearea aplicaiei Windows. Controalele sunt grupate n categoriile logice din imaginea alturat. Ferestrele care sunt afiate in fereastra principal se pot stabili prin selecie din meniul View.

La crearea unei noi aplicaii vizuale, Microsoft Visual C# 2008 Express Edition genereaz un spaiu de nume care conine clasa static Program, cu metoda static ce constituie punctul de intrare (de lansare) a aplicaiei:
static void Main() { } ... Application.Run(new Form1());

Clasa Application este responsabil cu administrarea unei aplicaii Windows, punnd la dispoziie proprieti pentru a obine informaii despre aplicaie, metode de lucru cu aplicaia i altele. Toate metodele i proprietile clasei Application sunt statice. Metoda Run creeaz un formular implicit, aplicaia rspunznd la mesajele utilizatorului pn cnd formularul va fi nchis. Compilarea modulelor aplicaiei i asamblarea lor ntr-un singur fiier executabil se realizeaz cu ajutorul opiunilor din meniul Build, uzual fiind Build Solution (F6).
135

Odat implementat, aplicaia poate fi lansat, cu asisten de depanare sau nu (opiunile Start din meniul Debug). Alte faciliti de depanare pot fi folosite prin umrirea pas cu pas, urmrirea pn la puncte de ntrerupere etc. (celelalte opiuni ale meniului Debug). Ferestre auxiliare de urmrire sunt vizualizate automat n timpul procesului de depanare, sau pot fi activate din submeniul Windows al meniului Debug. Proiectarea vizual a formularului se poate face insernd controale selectate din fereastra de instrumente (Toolbox) i setnd proprietile acestora.

II.3.

Elementele POO n context vizual

n cele ce urmeaz pentru explicaiile care vor avea loc vom considera o aplicaie Windows numit Test:

n urma generrii proiectului Test avem:

136

Fereastra Toolbox

Fereastra Windows Forms Designer n care s-a creat Form1

Fereastra Solution Explorer

Fereastra pentru afiarearea Listei de erori Bara de unelte

Fereastra Properties

Bara de meniuri

Toate ferestrele, au n partea dreapt o piunez, care, dac este n poziie vertical fixez fereastra deschis. n caz contrar sau stng a mediului de programare. Orice fereastr poate fi aranjat ntr-o poziie dorit de utilizator. Pentru aceasta dm clic pe una dintre barele de titlu ale ferestrelor menionale mai sus (Solution Explorer, Properties, Toolbox sau Error List) si o deplasm n poziia dorit. n acest proces vei fi ghidat de sgeile
137

fereastra se nchide, retrgndu-se n partea dreapt

care apar central i pe margini. De preferat ar fi ca aceste ferestre s rmn n poziiile lor implicite.

Barele de instrumente
Implicit, la crearea unui proiect windows, apar dou bare de instrumente Prima bar de unelte

unde: Icoana Semnificaie proiect nou (Ctrl+Shift+A)

138

Icoana

Semnificaie

adugare de noi itemi (Ctrl+Shift+A) deschide fiier (Ctrl+O) salveaz Form1.cs (Ctrl+S) salveaz tot proiectul (Ctrl+Shift+O)

cut (Ctrl+X) copy (Ctrl+C) paste (Ctrl+V) undo (un pas napoi) (Ctrl+Z) redo (un pas nainte) (Ctrl + Y) navigare napoi n cod sau ferestre (Ctrl + -) navigare nainte n cod sau ferestre (Ctrl + Shift -) Start debugging (F5) Compileaz proiectul i-l lanseaz n modul debug Solution Configuration Solution Platform

cutare i nlocuire (Ctrl + Shift + F)


139

Icoana

Semnificaie fereastra pentru cutare fereastra Solution Explorer (Ctrl + W, S) fereastra Properties (Ctrl + W, P) fereastra Object Browser (Ctrl + W, J) fereastra Toolbox (Ctrl + W, X) fereastra de start Start Page fereastra Document Outline (Ctrl + W, U)

A doua bar de instrumente se folosete atunci cnd dorim s acionm asupra mai multor controale din fereastra noastr, i anume pentru: alinieri, spaieri, redimensionri, aducerea n fa/spate a unora dintre controalele existente. Icoanele aflate pe aceast bar sunt deosebit de sugestive pentru aciunea pe care o realizeaz.

Fereastra Toolbox
Revenind la fereastra Toolbox. Putem s

deschidem una dintre opiunile din fereastr apsnd semnul plus din fa. De exemplu, dac deschidem Common Controls n fereastr apar controale mai des folosite. Orice control poate fi adus pe Form-ul nostru (i vom putea spune, n egal msur, fereastr, interfa, formular) prin dublu clic pe respectivul control, sau prin drag and drop n Form.

140

Fereastra Solution Explorer


Vom observa c n momentul n care dm clic pe Form sau pe un control, fereastra din dreapta, Properties, se va referi la acesta control sau aceast fereastr. Fereastra Solution Explorer, din partea

dreapt se refer, printre altele la ferestra Designer sau la fereastra n care utilizatorul va scrie propriul cod. n cazul n care fereastra Designer este nchis, putem apela la opiunea Open i va reaprea n fereastra central. Dac dorim s vedem codul, apsm pe opiunea View Code, iar n fereastra principal se va lucru deschide, l putem nc spune o i ferestr despre corespunztoare codului dorit. Acelai Properties.cs, din aceeai fereastr. n toate cazurile menionate mai sus, pentru a obine efectul afiat i n imagini, se va aciona butonul din dreapta al mouse-ului. Despre opiunile care apar n cazul n care dm clic dreapta pe Test, vom discuta, la modul concret, n unele dindre exemplele are urmeaz

Fereastra Properties
Aminteam mai sus c n Toolbox exist toate tipurile de controale care i sunt necesare unui programator pentru a realiza o aplicaie. Cele mai multe controale sunt obiecte acestui
141

de fapt

clase multe

derivate dintre

din

clasa i

System.Windows.Forms.Control.

Datorit

proprietile

evenimentele diverselor controale vor fi identice. Vom vedea, n aplicaiile care urmeaz, c exit clase care definesc controale i care pot fi clase de baz pentru alte controale. Fereastra Properties, din interfaa mediului de programare, vom observa c va conine att proprietile ct i evenimentele ataate controalelor. comune controalelor, proprieti furnizate de ctre clasa Control: Proprietatea Anchor BackColor Bottom Dock Enabled ForeColor Height Left Name Parent Right TabIndex TabStop Tag Top Visible Width Descrierea proprietii se refer la posibilitatea de a ancora controlul fa de o margine (sau toate) permite stabilirea culorii de fundal a controlului permite stabilirea distanei dintre marginea de sus a ferestrei i control ataeaz controlul la una dintre marginile ferestrei permite controlului s recepioneze evenimente de la utilizator permite stabilirea culorii textului permite definirea nlimii controlului permite stabilirea distanei dintre marginea din stnga a ferestrei i marginea stnga a controlului permite denumirea controlului pentru a-l putea mai uor vizualiza i manipula n codul surs printele controlului permite stabilirea distanei dintre marginea din dreapta a ferestrei i marginea din dreapta a controlului prin numrul de ordine care i se ataeaz se stabilete ordinea activrii controlului la apsarea tastei TAB permite sau nu ca respectivul control s fie activat prin apsarea tastei TAB se refer la un ir de caractere pe care controlul l poate stoca n interiorul su permite stabilirea distanei dintre marginea de sus a ferestrei i marginea de sus a controlului stabilete dac respectivul control, care exit n fereastr, este (TRUE) sau nu vizibil stabilete limea controlului Proprietile controalelor, sunt motenite sau supranscrise din clasa de baz Control. Tabelul de mai jos prezint proprietile

Aplicaiile pe care le crem trebuie s fie capabile, prin intermediul controalelor, s sesizeze aciunea utilizatorului asupra respectivelor controale. i o serie de evenimente la care controalele vor reaciona: n funcie de tipul aciunii vor reaciona, printr-o secven de cod sau alta. Tot clasa Control amintit mai sus, implementeaz

Evenimentul Clic DoubleClic DragDrop

Descrierea evenimentului se genereaz cnd se d clic asupra unui control se genereaz cnd se d dublu clic asupra unui control. Excepie fcnd Button asupra cruia nu se va putea face dublu clic, deoarece controlul acioneaz la primul clic se genereazla finalizarea lui drag and drop
142

Evenimentul DragEnter DragLeave DragOver KeyDown KeyPress KeyUp GotFocus LostFocus MouseDown MouseMove MouseUp Paint Validated Validating

Descrierea evenimentului se genereaz atunci cnd obiectul, printr-un drag and drop, ajunge n interiorul controlului se genereaz atunci cnd obiectul, printr-un drag and drop, ajunge s prseasc controlului se genereaz atunci cnd obiectul, printr-un drag and drop, ajunge deasupra controlului se genereaz atunci cnd o tast este apsat n timp ce controlul este activ. Se va furniza codul ASCII al tastei apsate. Se genereaz nainte de evenimentele KeyPress i KeyUp se genereaz atunci cnd o tast este apsat n timp ce controlul este activ. Se va furniza codul de scanare al tastei apsate. Se genereaz dup KeyDown i nainte de KeyUp se genereaz cnd o tast este eliberat n timp ce controlul este activ. Se genereaz dup KeyDown i KeyPress se genereaz cnd controlul devine activ (se mai spune: cnd controlul primete input focusul) se genereaz cnd controlul devine inactiv (se mai spune: cnd controlul pierde input focusul) se genereaz cnd cursorul mouse-ului este deasupra controlului i se apas un buton al mouse-ului se genereaz cnd trecem cu mouse-ul deasupra controlului se geereaz cnd mouse-ul este deasupra controlului i eliberm un buton al mouse-ului se genereaz la desenarea controlului se genereaz cnd un control este pe cale s devin activ. Se genereaz dup terminarea evenimentului Validating, indicnd faptul c validarea controlului este complet se genereaz cnd un control este pe cale s devin activ

II.4.

Construirea interfeei utilizator

II.4.1.

Ferestre

Spaiul Forms ne ofer clase specializate pentru: creare de ferestre sau formulare (System.Windows.Forms.Form), elemente specifice (controale) cum ar fi butoane (System.Windows.Forms.Button), casete de text (System.Windows.Forms.TextBox) etc. Proiectarea unei ferestre are la baz un cod complex, generat automat pe msur ce noi desemnm componentele i comportamentul acesteia. n fapt, acest cod realizeaz: derivarea unei clase proprii din System.Windows.Forms.Form, clas care este nzestrat cu o colecie de controale (iniial vid). Constructorul ferestrei realizeaz instanieri ale claselor Button, MenuStrip, Timer etc. (orice plasm noi n fereastr) i adaug referinele acestor obiecte la colecia de controale ale ferestrei.
143

Dac modelul de fereastr reprezint ferestra principal a aplicaiei, atunci ea este instaniat automat n programul principal (metoda Main). Dac nu, trebuie s scriem noi codul care realizeaz instanierea.

Clasele derivate din Form motenesc o serie de proprieti care determin atributele vizuale ale ferestrei (stilul marginilor, culoare de fundal, etc.), metode care implementeaz anumite comportamente (Show, Hide, Focus etc.) i o serie de metode specifice (handlere) de tratare a evenimentelor (Load, Click etc.).

O fereastr poate fi activat cu form.Show() sau cu form.ShowDialog(), metoda a doua permind ca revenirea n fereastra din care a fost activat noul formular s se fac numai dup ce noul formular a fost nchis (spunem c formularul nou este deschis modal).

Un propietar este o fereastr care contribuie la comportarea formularului deinut. Activarea propietarului unui formular deschis modal va determina activarea formularului deschis modal. Cnd un nou formular este activat folosind form.Show() nu va avea nici un deintor, acesta stabilinduse direct :

public Form Owner { get; set; } F_nou form=new F_nou(); form.Owner = this; form.Show();

Formularul deschis modal va avea un proprietar setat pe null. Deintorul se poate stabili setnd proprietarul nainte s apelm Form.ShowDialog() sau apelnd From.ShowDialog() cu proprietarul ca argument.

F_nou form = new F_nou(); form.ShowDialog(this);

Vizibilitatea unui formular poate fi setat folosind metodele Hide sau Show. Pentru a ascunde un formular putem folosi :

this.Hide();

// setarea propietatii Visible indirect sau

this.Visible = false; // setarea propietatii Visible direct

144

Printre cele mai uzuale proprieti ale form-urilor, reamintim: StartPosition determin poziia ferestrei atunci cnd aceasta apare prima dat. Poziia poate fi setat Manual, sau poate fi sau Windows-ul va centrat pe desktop (CenterScreen), stabilit de Windows, dimensiunea iniial i locaia pentru formular formularul avnd dimensiunile i locaia stabilite de programator (WindowsDefaultLocation) stabili (WindowsDefaultBounds) sau, centrat pe formularul care l-a afiat (CenterParent) atunci cnd formularul va fi afiat modal.

Location (X,Y) reprezint coordonatele colului din stnga sus al formularului relativ la colul stnga sus al containerului. (Aceast propietate e ignorat dac StartPosition = Manual). Micarea formularului ( i implicit schimbarea locaiei) poate fi tratat n evenimentele Move i LocationChanged . Locaia formularului poate fi stabilit relativ la desktop astfel:
void Form_Load(object sender, EventArgs e) { this.Location = new Point(1, 1); this.DesktopLocation = new Point(1, 1); } //formularul in desktop

Size (Width i Height) reprezint dimensiunea ferestrei. Cnd se schimb propietile Width i Height ale unui formular, acesta se va redimensiona automat, aceast redimensionare fiind tratat n evenimentele Resize sau in SizeChanged. Chiar dac propietatea Size a formularului indic dimensiunea ferestrei, formularul nu este n totalitate responsabil pentru desenarea ntregului coninut al su. Partea care este desenat de formular mai este denumit i Client Area. Marginile, titlul i scrollbar-ul sunt desenate de Windows. MaxinumSize i MinimumSize sunt utilizate pentru a restriciona dimensiunile unui formular.
void Form_Load(object sender, EventArgs e) { this.MinimumSize = new Size(200, 100);... this.MaximumSize = new Size(int.MaxValue, 100);...}

ControlBox precizeaz dac fereastra conine sau nu un icon, butonul de nchidere al ferestrei i meniul System (Restore,Move,Size,Maximize,Minimize,Close).

HelpButton-precizeaz dac butonul

va aprea sau nu lng butonul de nchidere al

formularului (doar dac MaximizeBox=false, MinimizeBox=false). Dac utilizatorul apas acest buton i apoi apas oriunde pe formular va aprea evenimentul HelpRequested (F1).

Icon reprezint un obiect de tip *.ico folosit ca icon pentru formular. MaximizeBox i MinimizeBox precizeaz dac fereastra are sau nu butonul Maximize i respectiv Minimize Opacity indic procentul de opacitate

145

ShowInTaskbar precizeaz dac fereastra apare in TaskBar atunci cnd formularul este minimizat.

SizeGripStyle specific tipul pentru Size Grip (Auto, Show, Hide). Size grip dreapta jos) indic faptul c aceast fereastr poate fi redimensionat. TopMost precizeaz dac fereastra este afisat n faa tuturor celorlalte ferestre. TransparencyKey identific o culoare care va deveni transparent pe form.

(n colul din

Definirea unei funcii de tratare a unui eveniment asociat controlului se realizeaz prin selectarea grupului mentului dorit. Dac nu scriem nici un nume pentru funcia de tratare, ci efectum dublu clic n csua respectiv, se genereaz automat un nume pentru aceast funcie, innd cont de numele controlului i de numele evenimentului (de exemplu button1_Click). Dac n Designer efectum dublu clic pe un control, se va genera automat o funcie de tratare pentru evenimentul implicit asociat controlului (pentru un buton evenimentul implicit este Clic, pentru TextBox este TextChanged, pentru un formular Load etc.). Printre evenimentele cele mai des utilizate, se numr :

Events din ferestra Properties a controlului respectiv i alegerea eveni-

Load apare cnd formularul este pentru prima data ncrcat n memorie. FormClosed apare cnd formularul este nchis. FormClosing apare cnd formularul se va inchide ca rezultat al aciunii utilizatorului asupra butonului Close (Dac se seteaz CancelEventArgs.Cancel =True atunci se va opri nchiderea formularului). Activated apare pentru formularul activ. Deactivate apare atunci cnd utilizatorul va da clic pe alt formular al aplicatiei.

II.4.2.

Controale

Unitatea de baz a unei interfee Windows o reprezint un control. Acesta poate fi gzduit de un container ce poate fi un formular sau un alt control. Un control este o instan a unei clase derivate din System.Windows.Forms i este reponsabil cu desenarea unei pri din container. Visual Studio .NET vine cu o serie de controale standard, disponibile n Toolbox. Aceste controale pot fi grupate astfel:

146

Controale form. Controlul form este un container. Scopul su este de a gzdui alte controale. Folosind proprietile, metodele i evenimentele unui formular, putem personaliza programul nostru. n tabelul de mai jos vei gsi o list cu controalele cel mai des folosite i cu descrierea lor. Exemple de folosire a acestor controale vor urma dup explicarea proprietilor comune al controalelor i formularelor.

Funcia controlului buton calendar caset de validare etichet caset cu list imagine pointer buton radio

Numele controlului Button MonthCalendar CheckBox Label ListBox PictureBox Pointer RadioButton

Descriere Sunt folosite pentru a executa o secven de instruciuni n momentul activrii lor de ctre utilizator Afieaz implicit un mic calendar al lunii curente. Acesta poate fi derulat i nainte i napoi la celelalte luni calendaristice. Ofer utilizatorului opiunile : da/nu sau include/exclude Sunt folosite pentru afiarea etichetelor de text, i a pentru a eticheta controalele. Afieaz o list de articole din care utilizatorul poate alege. Este folosit pentru adugarea imaginilor sau a altor resurse de tip bitmap. Este utilizat pentru selectarea, mutarea sau redimensionarea unui control. Este folosit pentru ca utilizatorul s selecteze un singur element dint-un grup de selecii. Este utilizat pentru afiarea textului generat de o aplicaie sau pentru a primi datele introduse de la tastatur de ctre utilizator.

caset de text TextBox

II.5.

Aplicaii
Numere pare

II.5.1.

Acest exemplu afieaz numerele pare din intervalul [0,n) unde n este o variabil global a crei valoare este introdus de la tastatur. Se deschide o aplicaie Windows Forms pe care o vei denumi Numere pare. Din fereastra Properties modificai numele formularului. Stabilii dimensiunea formularului i culoarea de fond alegnd una dintre cele predefinite din opiunea BackColor. Cu ajutorul metodei Drag and drop plasai pe formular un buton pe care vei introduce textul START, dou controale TextBox, dou controale label pe care vei introduce textele din exemplul de mai jos

147

Executai dublu clic pe butonul START i editai codul surs conform exemplului de mai jos:

private void button1_Click(object sender, EventArgs e) { n = Convert.ToInt32(textBox1.Text); for (;i<n;i=i+2) { textBox2.Text = textBox2.Text + " " + Convert.ToString(i); } }

n fereastra Solution Explorer executai dublu clic pe Form1.Designer.cs pentru a declara variabilele globale n i i, n zona de declaraii a funciei InitializeComponent().

private System.Windows.Forms.Label label1; private System.Windows.Forms.Label label2; private System.Windows.Forms.TextBox textBox1; private System.Windows.Forms.TextBox textBox2; private System.Windows.Forms.Button button1; int i=0,n;

n acest moment aplicaia este gata. Din meniul File alegei opiunea Save All i rulai aplicaia.

148

II.5.2.

Proprieti comune ale controalelor i formularelor:

Proprietatea Text Aceast proprietate poate fi setat n timpul proiectrii din fereastra Properties, sau programatic, introducnd o declaraie n codul programului.

public Form1(){ InitializeComponent(); this.Text = "Primul formular"; }

Proprietile ForeColor i BackColor. Prima proprietate enunat seteaz culoare textului din formular, iar cea de a doua seteaz culoarea formularului. Toate acestea le putei modifica dup preferine din fereastra Properties.

Proprietatea BorderStyle. Controleaz stilul bordurii unui formular. ncercai s vedei cum se modific setnd proprietatea la Fixed3D (tot din fereastra Properties).

Proprietatea FormatString v permite s setai un format comun de afiare pentru toate obiectele din cadrul unei ListBox. Aceasta se gsete disponibil n panoul Properties.

Proprietatea Multiline schimb setarea implicit a controlului TextBox de la o singur linie, la mai multe linii. Pentru a realiza acest lucru tragei un TextBox ntr-un formular i modificai valoarea proprietii Multiline din panoul Properties de la False la true.

Proprietatea AutoCheck cnd are valoarea true, un buton radio i va schimba starea automat la executarea unui clic.

Proprietatea AutoSize folosit la controalele Label i Picture, decide dac un control este redimensionat automat, pentru a-i cuprinde ntreg coninutul.
149

Proprietatea Enabled determin dac un control este sau nu activat ntr-un formular. Proprietatea Font determin fontul folosit ntr-un formular sau control. Proprietatea ImageAlign specific alinierea unei imagini aezate pe suprafaa controlului. Proprietatea TabIndex seteaz sau returneaz poziia controlului n cadrul aranjrii taburilor. Proprietatea Visible seteaz vizibilitatea controlului. Proprietatea Width and Height permite setarea nlimii i a limii controlului.

II.5.3.

Metode i evenimente

Un eveniment este un mesaj trimis de un obiect atunci cnd are loc o anumit aciune. Aceast actiune poate fi: interaciunea cu utilizatorul (mouse click) sau interaciunea cu alte entiti de program. Un eveniment (event) poate fi apsarea unui buton, o selecie de meniu, trecerea unui anumit interval de timp, pe scurt, orice ce se intampl n sistem i trebuie s primeasc un raspuns din partea programului. Evenimentele sunt proprieti ale clasei care le public. Cuvantul-cheie event contoleaz cum sunt accesate aceste proprieti.

Metodele Show() i Close(). Evenimentul Click


Cnd dezvoltm programe pentru Windows, uneori trebuie s afim ferestre adiionale. De asemenea trebuie s le facem s dispar de pe ecran. Pentru a reui acest lucru folosim metodele Show() i Close() ale controlului. Cel mai important eveniment pentru Button este Clic (desemnnd aciunea clic stnga pe buton).

Exemplul 2: Deschidere i nchidere de formulare Deschidei o nou aplicaie Windows Forms, tragei un control de tip Button pe formular. Din meniul Project selectai Add Windows Form, iar n caseta de dialog care apare adugai numele Form2, pentru noul formular creat. n acest moment ai inclus n program dou formulare. Tragei un buton n Form2 i executai dublu clic pe buton, pentru a afia administratorul su de evenimente. Introducei acum n el linia de cod this.Close();.

private void button1_Click(object sender, EventArgs e) { this.Close(); }

Numele metodei button1_Clic este alctuit din numele controlului button1, urmat de numele evenimentului: Clic.
150

Acum ar trebui s revenii la Form1 i executai dublu clic pe butonul din acest formular pentru a ajunge la administratorul su de evenimente. Editai administratorul evenimentului conform exemplului de mai jos:

private void button1_Click(object sender, EventArgs e) { Form2 form2 = new Form2();form2.Show(); }

n acest moment rulai programul apsnd tasta F5 i vei observa c la executarea unui clic pe butonul din Form1 se deschide Form2 iar la executarea unui clic pe butonul din Form2 acesta se nchide.

Exemplul 3: Imagini Deschidei o nou aplicaie Windows Forms, tragei dou controale de tip Button pe formular pe care le redenumii cu DA i cu NU, un control de tip PictureBox i un control de tip Label pe care scriei textul: Te crezi inteligent?.

Textul pentru fiecare control l vei introduce utiliznd proprietatea Text. Va trebui sa avei dou imagini diferite salvate ntr-un folder pe calculatorul vostru. Executai dublu clic pe butonul DA i folosii urmtorul cod pentru administratorul evenimentului Clic:

151

private void button1_Click(object sender, EventArgs e) {pictureBox1.Image = Image.FromFile("C:\\Imagini \\line.gif"); pictureBox1.Visible = true;}

Va trebui s completai corect calea spre folder-ul n care ai salvat imaginea pentru importul cu succes al ei. Executai dublu clic pe butonul NU i folosii urmtorul cod pentru administratorul evenimentului Clic:

private void button2_Click(object sender, EventArgs e) { pictureBox1.Image = Image.FromFile("C:\\Imagini\\rat.gif"); pictureBox1.Visible = true; }

Vei obine la rularea aplicaiei afiarea uneia din cele dou imagini, n funcie de butonul apsat.

sau

Exemplul 4: Caset de text

Tot n cadrul evenimentului Clic, oferim acum un exemplu de afiare ntr-un TextBox a unui mesaj, n momentul n care se execut clic pe un buton. Deschidei o nou aplicaie Windows Forms. Tragei un control de tip Button pe formular i un control de tip TextBox. Modificai textul ce apare pe buton, conform imaginii, i executai dublu clic pe el, pentru a ajunge la administratorul su de evenimente. Modificai codul surs al controlului Button, conform exemplului de mai jos.

private void button1_Click(object sender, EventArgs e) {string a = "PLATFORMA .NET";textBox1.Text = a;}

n acest moment rulai programul apsnd tasta F5 i facei clic pe buton.

152

Exemplul 5: Caset de mesaj Pentru a crea o caset mesaj, apelm metoda MessageBox.Show();.ntr-o nou aplicaie Windows Forms, tragei un control de tip Button n formular, modificai textul butonului cum dorii sau ca n imaginea alturat va apare un mesaj, executai dublu clic pe buton i adugai n administratorul evenimentului Clic linia de program: MessageBox.Show("ti-am spus");. Apoi rulai aplicaia.

Exemplul 6: Este un exemplu de utilizare a Propietatea Checked controalelor de selecie CheckBox i RadioButton.

indic dac am selectat controlul. Dac proprietatea ThreeState este

setat, atunci se schimb funcionalitatea acestor controale, n sensul c acestea vor permite setarea unei alte stri. n acest caz, trebuie verificat propietatea CheckState(Checked, Unchecked, Indeterminate) pentru a vedea starea controlului CheckBox. Soluia unei probleme cu mai multe variante de rspuns este memorat cu ajutorul unor checkbox-uri cu proprietatea ThreeState. Apsarea butonului Verific determin afiarea unei etichete i a butoanelor radio DA i NU. Rspunsul este afiat ntr-un MessageBox.

153

Dup adugarea controalelor pe formular i setarea proprietilor Text i ThreeState n cazul checkbox-urilor stabilim evenimentele clic pentru butonul Verifica i pentru butonul radio cu eticheta DA:

private void radioButton1_Click(object sender, System.EventArgs e){ if (checkBox1.CheckState==CheckState.Checked && checkBox2.CheckState==CheckState.Checked && checkBox3.CheckState==CheckState.Checked && checkBox5.CheckState==CheckState.Checked && checkBox4.CheckState==CheckState.Unchecked) MessageBox.Show("CORECT"); else MessageBox.Show("Indicatie> Daca punem un sac in altul...."); label2.Visible=false; radioButton1.Checked=false; radioButton2.Checked=false; radioButton1.Visible=false; radioButton2.Visible=false;} private void button1_Click(object sender, System.EventArgs e) {label2.Visible=true;radioButton1.Visible=true;radioButton2.Visible=true; }

Exemplul 7: Construcia Fractalului Se deschide o aplicaie Windows Forms pe care o vei denumi Fractal. Stabilii dimensiunea formularului la 740 cu 540, stabilii culoarea de fond a formularului alegnd una dintre cele predefinite din opiunea BackColor. Cu ajutorul metodei Drag and drop plasai pe formular: dou controale de tip Label n care vei introduce urmtoarele texte Construirea unui fractal (pentru eticheta poziionat n partea de sus a formularului) i Introducei numrul de ptrate (pentru cea de a doua etichet pe care e bine s o poziionai la o distan nu prea mare de prima), plasai pe formular i un control de tip TextBox, un control de tip Button, i un control de tip Timer pentru care setai intervalul la 50.

154

Executnd dublu clic pe butonul Start va fi deschis codul surs. n funcia button1_Clic iniializm variabila m cu valoarea 1 i pornim timer-ul.

private void button1_Click(object sender, EventArgs e) { m = 1; timer1.Start(); }

n aceeai fereastr de cod scriem funcia recursiv patrat care va genera fractalul.

void patrat(int n, int x, int y, int l) { int l2 = l / 2; int l4 = l / 4; int l3 = l2 + l4;

if (n > 1) { patrat(n - 1, x - l4, y - l4, l2); patrat(n - 1, x - l4, y + l3, l2); patrat(n - 1, x + l3, y - l4, l2); patrat(n - 1, x + l3, y + l3, l2); } Graphics graph = this.CreateGraphics(); Pen penc; if (n % 2 == 0) penc = new Pen(Color.Red); else penc = new Pen(Color.BlueViolet); Point[] p = new Point[4]; p[0].X = x; p[0].Y = y; p[1].X = x; p[1].Y = y + l; p[2].X = x + l; p[2].Y = y + l; p[3].X = x + l; p[3].Y = y; graph.DrawPolygon(penc, p); }

155

Se execut acum dublu clic pe obiectul timer de pe formular pentru a completa funcia
timer1_Tick cu apelul funciei recursive patrat.

private void timer1_Tick(object sender, EventArgs e) { if (m <= Convert.ToInt32(textBox1.Text)) { int x = 300, y = 300, l = 150; patrat(m, x, y, l); m = m + 1; } }

n fereastra Solution Explorer executai dublu clic pe Form1.Designer.cs pentru a declara variabila global m, n zona de declaraii a funciei InitializeComponent().

private System.Windows.Forms.Label label1; private System.Windows.Forms.Label label2; private System.Windows.Forms.TextBox textBox1; private System.Windows.Forms.Button button1; private System.Windows.Forms.Timer timer1; int m;

n acest moment aplicaia este gata. Din meniul File alegei opiunea Save All i rulai aplicaia.

Metodele ShowDialog() i Clear(). Evenimentul MouseEnter.


Exemplul 8: Casete de dialog

156

Creai o nou aplicaie Windows Forms, apoi tragei un buton n formular i setai proprietatea Text a butonului la : s avem un dialog, iar apoi executai dublu clic pe buton i modificai numele metodei din button1_click n button1_MouseEnter apoi folosii urmtorul cod pentru administratorul evenimentului MouseEnter.

private void button1_MouseEnter(object sender, EventArgs e) { Form2 w = new Form2(); w.ShowDialog(); }

Intrai n codul surs pentru Form1.Designer.cs i modificai linia de program:


this.button1.Click += new System.EventHandler(this.button1_Click);

astfel:
this.button1.MouseEnter += new System.EventHandler(this.button1_MouseEnter);

Acest eveniment al controlului Button v permite ca la o simpl plimbare pe buton fr a executa clic pe el, s se execute codul surs al metodei. Creai un alt formular la acest proiect (alegei Add Windows Forms din meniul Project), apoi n ordine: setai proprietatea ControlBox la valoarea false, setai proprietatea Text la caset de dialog, tragei n formular un control de tip Label i setai proprietatea Text la scrie text, adugai un control TextBox n formular, adugai dou controale de tip Button, setai proprietatea Text a butonului din stnga la OK iar al celui din dreapta la Cancel, setai proprietatea DialogResult a butonului din stanga la OK iar al celui din dreapta la Cancel, executai clic pe formularul casetei de dialog i setai proprietatea AcceptButton la button1 iar proprietatea CancelButton la button2. Acum executai dublu clic pe butonul OK i folosii urmtorul cod pentru administratorul evenimentului Clic:

private void button1_Click(object sender, EventArgs e) {textBoxText = textBox1.Text;this.Close();}

Executai dublu clic pe butonul Cancel i folosii urmtorul cod pentru administratorul evenimentului Clic:
private void button2_Click(object sender, EventArgs e) {Form2 v = new Form2(); v.ShowDialog(); if (v.DialogResult != DialogResult.OK){ this.textBox1.Clear(); }}

157

La nceputul clasei Form2 adugai declaraia: public string textBoxText; iar la sfritul clasei Form2 adugai proprietatea:
public string TextBoxText {get{ return(textBoxText);}

Acum putei rula acest program.

Metoda Start(). Evenimentul MouseLeave. Exemplul 9: Schimb culoarea


n acest exemplu este prezentat modalitatea de schimbare aleatoare a culorii unei etichete. Se deschide o aplicaie Windows Forms pe care o vei denumi Schimb culoarea. Din fereastra Properties redenumii formularul. Stabilii dimensiunea formularului i culoarea de fond alegnd una dintre cele predefinite din opiunea BackColor. Cu ajutorul metodei Drag and drop plasai pe formular: un control de tip Button pe care vei introduce textul START, un control de tip Button pe care vei introduce textul STOP, un control de tip Label pe care vei introduce textul Schimb culoarea, un control de tip Timer.

158

Executai dublu clic pe butonul START i editai administratorul evenimentului conform exemplului de mai jos:

private void button1_MouseLeave(object sender, EventArgs e) {timer1.Start();}

Intrai n codul surs pentru Form1.Designer.cs i modificai linia de program:


this.button1.Click += new System.EventHandler(this.button1_Click);

astfel:
this.button1.MouseLeave += new System.EventHandler(this.button1_MouseLeave);

Evenimentul MouseLeave va permite executarea codului surs a metodei n momentul n care vei plimba mouse-ul pe deasupra imaginii butonului i nu la executarea clic-ului. Executai dublu clic pe butonul STOP i inserai linia de cod timer1.Stop(); Declarai urmtoarea variabil ca fiind variabil local pentru clasa Form1
Random r = new Random(200);

Executai dublu clic pe controlul Timer i inserai linia de cod care va permite schimbarea aleatoare a culorilor pentru controlul Label conform exemplului de mai jos:

private void timer1_Tick(object sender, EventArgs e) {label1.BackColor = Color.FromArgb(r.Next(255), r.Next(255), r.Next(255));}

n acest moment aplicaia este gata. Din meniul File alegei opiunea Save All i rulai aplicaia.

159

Exemplul 10: Trei culori Acest exemplu afieaz un grup alctuit din 3 butoane, etichetate A,B respectiv C avnd iniial culoarea roie. Apsarea unui buton determin schimbarea culorii acestuia n galben. La o nou apsare butonul revine la culoare iniial. Acionarea butonului Starea butoanelor determin afiarea ntr-o caset text a etichetelor butoanelor galbene. Caseta text devine vizibil atunci cnd apsm prima oar acest buton. Culoarea butonului mare (verde/portocaliu) se schimb atunci cnd mouse-ul este poziionat pe buton. Dup adugarea butoanelor i a casetei text pe formular, stabilim evenimentele care determin schimbarea culoriilor i completarea casetei text.

private void button1_Click(object sender, System.EventArgs e) { if (button1.BackColor== Color.IndianRed) button1.BackColor=Color.Yellow; else button1.BackColor= Color.IndianRed;} private void button4_MouseEnter(object sender, System.EventArgs e) {button4.BackColor=Color.YellowGreen;button4.Text="Butoane apasate";} private void button4_MouseLeave(object sender, System.EventArgs e) {textBox1.Visible=false;button4.Text="Starea butoanelor"; button4.BackColor=Color.Orange;} private void button4_Click(object sender, System.EventArgs e) {textBox1.Visible=true;textBox1.Text=""; if( button1.BackColor==Color.Yellow)textBox1.Text=textBox1.Text+'A'; if( button2.BackColor==Color.Yellow)textBox1.Text=textBox1.Text+'B'; if( button3.BackColor==Color.Yellow)textBox1.Text=textBox1.Text+'C'; }

160

Exemplul 11: Hyperlink LinkLabel afieaz un text cu posibilitatea ca anumite pri ale textului (LinkArea) s fie desenate ca i hyperlink-uri. Pentru a face link-ul funcional trebuie tratat evenimentul LinkCliced. n acest exemplu, prima etichet permite afiarea coninutului discului C:, a doua legtur este un link ctre pagina www.microsoft.com/romania i a treia acceseaz Notepad.

161

private void linkLabel1_LinkCliced (object sender, LinkLabelLinkClicedEventArgs e ) { linkLabel1.LinkVisited = true; System.Diagnostics.Process.Start( @"C:\" );} private void linkLabel2_LinkCliced( object sender, LinkLabelLinkClicedEventArgs e ) { linkLabel2.LinkVisited = true; System.Diagnostics.Process.Start("IExplore", "http://www.microsoft.com/romania/" );} private void linkLabel3_LinkCliced( object sender, LinkLabelLinkClicedEventArgs e ) { linkLabel3.LinkVisited = true; System.Diagnostics.Process.Start( "notepad" );}

Exemplul 12: Curba Beziers Se deschide o aplicaie Windows Forms pe care o vei denumi Culori. Din fereastra Properties modificai numele formularului redenumindu-l. Stabilii dimensiunea formularului i culoarea de fond alegnd una dintre cele predefinite din opiunea BackColor. Cu ajutorul metodei Drag and drop plasai pe formular: un control de tip Button pe care vei introduce textul START, un control de tip Timer iar din caseta Properties intervalul l setai la 50. Executai dublu clic pe suprafaa formularului i completai clasa Form1 cu declararea variabilelor locale conform modelului de mai jos:

Random r = new Random(); PointF[] v = new PointF[4]; Graphics graf;

Executai dublu clic pe controlul timer i completai funcia timer1_Tick conform modelului de mai jos:

162

private void timer1_Tick(object sender, EventArgs e) { double u = 2 * i * Math.PI / 100; v[0].X = cx / 2 + cx / 2 * (float)Math.Cos(u); v[0].Y = 5 * cy / 8 + cy / 16 * (float)Math.Sin(u); v[1] = new PointF(cx / 2, -cy);v[2] = new PointF(cx / 2, 2 * cy); u += Math.PI / 4;v[3].X = cx / 2 + cx / 4 * (float)Math.Cos(u); v[3].Y = cy / 2 + cy / 16 * (float)Math.Sin(u); Pen p = new Pen(Color.FromArgb(r.Next(2), r.Next(200), r.Next(2))); graf.DrawBeziers(p, v); i++; }

Executai dublu clic pe butonul START i completai funcia button1_Click conform modelului de mai jos:
private void button1_Click(object sender, EventArgs e) {graf = this.CreateGraphics(); timer1.Start(); }

n fereastra Solution Explorer executai dublu clic pe Form1.Designer.cs pentru a declara variabilele globale i,cx,cy n zona de declaraii a funciei InitializeComponent().

private System.Windows.Forms.Button button1; private System.Windows.Forms.Timer timer1; int i = 0, cx = 300, cy = 300;

n acest moment aplicaia este gata. Din meniul File alegei opiunea Save All i rulai aplicaia.

Metoda Dispose()

Exemplul 13:
163

Se adaug pe un formular dou butoane i o caset text. Apsarea primului buton va determina afiarea textului din TextBox ntr-un MessageBox iar apsarea celui de-al doilea buton va nchide aplicaia (metoda Dispose() va nchide aplicaia). Dup adugarea celor dou butoane i a casetei text a fost schimbat textul afiat pe cele dou butoane au fost scrise funciile de tratare a evenimentului Clic pentru cele dou butoane:

private void button1_Click(object sender, System.EventArgs e) { MessageBox.Show(textBox1.Text); } private void button2_Click(object sender, System.EventArgs e) { Form1.ActiveForm.Dispose(); }

Metodele Clear() i Add()


Exemplul 14: Controale pentru listare (ListBox, CheckedListBox, ComboBox, ImageList) ce pot fi legate de un DataSet, de un ArrayList sau de orice tablou (orice surs de date ce implementeaz interfaa IEnumerable). n acest exemplu elementele selectate din CheckedListBox se adaug n ListBox. Dup adugarea pe formular a CheckedListBox-ului, stabilim colecia de itemi (Properties-ItemsCollection), butonul Selecie i ListBox-ul. Evenimentul Click asociat butonului Selectie golete mai nti listBox-ul (listBox1.Items.Clear();) i dup aceea adaug n ordine fiecare element selectat din

CheckedListBox. Suplimentar se afieaz o etichet cu itemii selectai.

164

void button1_Click(object source, System.EventArgs e) { String s = "Am selectat si am adaugat itemii: "; listBox1.Items.Clear(); foreach ( object c in checkedListBox1.CheckedItems) {listBox1.Items.Add(c); s = s + c.ToString();s = s + " "; } label1.Text = s; }

Exemplul 15: este un exemplu de utilizare a controlului ListView. ListView este folosit pentru a afia o colecie de elemente n unul din cele 4 moduri (Text, Text+Imagini mici, Imagini mari, Detalii). Acesta este similar grafic cu ferestrele n care se afieaz fiierele dintr-un anumit director din Windows Explorer. Fiind un control complex, conine foarte multe proprieti, printre care:

View ( selecteaz modul de afiare (LargeIcon, SmallIcon, Details, List)), LargeImageList, SmallImageList (icon-urile de afiat n modurile LargeIcon, SmallIcon), Columns (utilizat doar n modul Details, pentru a defini coloanele de afiat), Items (elementele de afiat). Exemplul acesta afi eaz ntr-un ListView o list de elevi. Clasa Elev con ine i o metod

static ce returneaz o list de elevi (ne putem imagina c lista respectiv e citit din baza de date), este aceasta:
class Elev { public string Nume { get; set; } public string Prenume { get; set; } public int Nota { get; set; } public static List<Elev> CitesteElevi() { List<Elev> elevi = new List<Elev>(); elevi.Add(new Elev() { Nume = "Nume 1", Nota = 9 }); elevi.Add(new Elev() { Nume = "Nume 2", Nota = 10 }); elevi.Add(new Elev() { Nume = "Nume 3", Nota = 8 }); elevi.Add(new Elev() { Nume = "Nume 4", Nota = 9 }); return elevi; } }
165

Prenume = "Prenume 1", Prenume = "Prenume 2", Prenume = "Prenume 3", Prenume = "Prenume 4",

Proiectul nostru con ine Form1.cs este acesta:

i un Form unde am aezat un control de tip ListView. Codul din

public Form1() { InitializeComponent(); SeteazaLista(); } private void SeteazaLista() { listViewTest.Columns.Add("Nume", 200, HorizontalAlignment.Left); listViewTest.Columns.Add("Prenume", 200, HorizontalAlignment.Left); listViewTest.Columns.Add("Nota", 200, HorizontalAlignment.Left); listViewTest.View = View.Details; listViewTest.Sorting = SortOrder.Ascending; listViewTest.AllowColumnReorder = true; } private void Form1_Load(object sender, EventArgs e) { this.listViewTest.BeginUpdate(); ListViewItem lvi; ListViewItem.ListViewSubItem lvsi; foreach (Elev elev in Elev.CitesteElevi()) { lvi = new ListViewItem(); lvi.Text = elev.Nume; lvsi = new ListViewItem.ListViewSubItem(); lvsi.Text = elev.Prenume; lvi.SubItems.Add(lvsi); lvsi = new ListViewItem.ListViewSubItem(); lvsi.Text = elev.Nota.ToString(); lvi.SubItems.Add(lvsi); listViewTest.Items.Add(lvi); } this.listViewTest.EndUpdate(); } }

Metoda SeteazaLista pregte te lista pentru datele care i vor fi servite: mai nti i adaug 3 coloane, iar apoi seteaz propriet i care in de modul de afo are al acesteia. La Form1_Load (adic atunci cnd form-ul se ncarc) se vor lega datele (lista de elevi) de controlul de interfa .

166

Metoda Draw()
Exemplul 16: Aplicaia este un exemplu de utilizare a controlului ImageList. Acesta este un control care conine o list de imagini, care poate fi setat la design (proprietatea Collection):

Controlul ImageList dispune de o metod care permite desenarea imaginilor pe care le conine. Iat exemplul (metod executat la clic pe un buton):
private void btnDeseneaza_Click(object sender, EventArgs e) { Graphics graphic = this.CreateGraphics(); for (int i=0; i < imageList1.Images.Count;i++) { imageList1.Draw(graphic, i * 120, 60, i); } graphic.Dispose(); }

n urma rulrii aplicaiei vei obine:

167

Evenimentul DateSelected
Exemplul 17: MonthCalendar MonthCalendar afieaz un calendar prin care se poate selecta o dat (zi, luna, an) n mod grafic. Proprietile mai importante sunt: MinDate, MaxDate, TodayDate ce reprezint data minim/maxim selectabil i data curent (care apare afiat difereniat sau nu n funcie de valorile proprietilor ShowToday,ShowTodayCircle. Exist 2 evenimente pe care controlul le expune: DateSelected i DateChanged. n rutinele de tratare a acestor evenimente, programatorul are acces la un obiect de tipul DateRangeEventArgs care conine proprietile Start i End (reprezentnd intervalul de timp selectat). Formularul din aplicaie conine un calendar pentru care putem selecta un interval de maximum 30 de zile, sunt afiate sptmnile i ziua curent. Intervalul selectat se afieaz prin intermediul unei etichete. Dac se selecteaz o dat atunci aceasta va fi adugat ca item ntr-un ComboBox (orice dat poate aprea cel mult o dat n list). Dup adugarea celor 3 controale pe formular, stabilim proprietile pentru monthCalendar1 (ShowWeekNumber-True, MaxSelectionCount-30, etc.) i precizm ce se execut atunci cnd selectm un interval de timp:
private void monthCalendar1_DateSelected(object sender, System.Windows.Forms.DateRangeEventArgs e) { this.label1.Text = "Interval selectat: Start = " +e.Start.ToShortDateString() + " : End = "+ e.End.ToShortDateString(); if (e.Start.ToShortDateString()==e.End.ToShortDateString()) {String x=e.Start.ToShortDateString(); if(!(comboBox1.Items.Contains(x)))comboBox1.Items.Add(e.End.ToShortDateString ());} }

168

Evenimentele MouseDown, MouseUp, MouseMove


Grupuri de controale Toolbar (ToolStrip) afieaz o bar de butoane n partea de sus a unui formular. Se pot introduce vizual butoane (printr-un designer, direct din Visual Studio.NET IDE), la care se pot seta att textul afiat sau imaginea. Evenimentul cel mai util al acestui control este ButtonClic (care are ca parametru un obiect de tip ToolBarButtonClicEventArgs, prin care programatorul are acces la butonul care a fost apsat).

Exemplul 18: Modificare proprieti n aplicaia urmtoare cele 3 butoane fontului se realizeaz cu ajutorul ColorDialog().
FontDialog fd = new FontDialog(); fd.ShowColor = true; fd.Color = Color.IndianRed; fd.ShowApply = true; fd.Apply += new EventHandler(ApplyFont); if(fd.ShowDialog() != System.Windows.Forms.DialogResult.Cancel) { this.richTextBox1.Font= fd.Font; this.richTextBox1.ForeColor=fd.Color; } ColorDialog cd = new ColorDialog(); cd.AllowFullOpen = true; cd.Color = Color.DarkBlue; if(cd.ShowDialog() == System.Windows.Forms.DialogResult.OK) this.richTextBox1.ForeColor = cd.Color;

ale toolbar-ului permit modificarea proprietilor utilizeaz

textului introdus n caset. Toolbar-ul se poate muta fr a depi spaiul ferestrei. Schimbarea unui control FontDialog(), iar schimbarea culorii

Mutarea toolbar-ul este dirijat de evenimentele produse atunci cnd apsm butonul de mouse i/sau ne deplasm pe suprafaa ferestrei.

169

private void toolBar1_MouseDown(object sender, MouseEventArgs e) { // am apasat butonul de mouse pe toolbar am_apasat = true; forma_deplasata = new Point(e.X, e.Y); toolBar1.Capture = true;}

private void toolBar1_MouseUp(object sender, MouseEventArgs e) { am_apasat = false;toolBar1.Capture = false;}

private void toolBar1_MouseMove(object sender, MouseEventArgs e) { if (am_apasat) { if(toolBar1.Dock == DockStyle.Top || toolBar1.Dock == DockStyle.Left) { // daca depaseste atunci duc in stanga sus if (forma_deplasata.X < (e.X-20) || forma_deplasata.Y < (e.Y-20)) { am_apasat = false;// Disconect toolbar toolBar1.Dock = DockStyle.None;toolBar1.Location = new Point(10, 10); toolBar1.Size = new Size(200, 45); toolBar1.BorderStyle = BorderStyle.FixedSingle; } } else if (toolBar1.Dock == DockStyle.None) {toolBar1.Left = e.X + toolBar1.Left - forma_deplasata.X; toolBar1.Top = e.Y + toolBar1.Top - forma_deplasata.Y; if (toolBar1.Top < 5 || toolBar1.Top>this.Size.Height-20) { am_apasat = false;toolBar1.Dock = DockStyle.Top; toolBar1.BorderStyle = BorderStyle.Fixed3D;} else if (toolBar1.Left < 5 || toolBar1.Left > this.Size.Width - 20) { am_apasat = false;toolBar1.Dock = DockStyle.Left; toolBar1.BorderStyle = BorderStyle.Fixed3D; }}}}

Metoda ShowDialog()

Exemplul 18: Fiiere

170

Exemplul permite, prin intermediul unui meniu, scrierea unui fiier Notpad, afiarea continutului acestuia ntr-o caset text, schimbarea fontului i culorii de afiare, tergerea coninutului casetei, afiarea unor informaii teoretice precum i Help dinamic. Au fost definite chei de acces rapid pentru accesarea componentelor meniului. File New permite scrierea unui fiier notepad nou
System.Diagnostics.Process.Start( "notepad" );

File Open selecteaz i afieaz n caseta text coninutul unui fiier text.

OpenFileDialog of = new OpenFileDialog(); of.Filter = "Text Files (*.txt)|*.txt"; of.Title = "Fisiere Text"; if (of.ShowDialog() == DialogResult.Cancel)return; richTextBox1.Text=""; richTextBox1.Visible=true; FileStream strm; try{strm = new FileStream (of.FileName, FileMode.Open, FileAccess.Read); StreamReader rdr = new StreamReader (strm); while (rdr.Peek() >= 0) {string str = rdr.ReadLine (); richTextBox1.Text=richTextBox1.Text+" "+str; }} catch (Exception) {MessageBox.Show ("Error opening file", "File Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);}

File Close terge coninutul casetei text, File Exit nchide aplicaia Window Font i Window Color permit stabilirea fontului/culorii textului afiat. Help DinamicHelp acceseaz
System.Diagnostics.Process.Start("IExplore", "http://msdn2.microsoft.com/en-us/default.aspx");

Help About PV afieaz n caseta text informaii despre implementarea unui meniu.

171

II.5.4.

Obiecte grafice

Spaiul System.Drawing conine tipuri care permit realizarea unor desene 2D i au rol deosebit n proiectarea interfeelor grafice. Un obiect de tip Point este reprezentat prin coordonatele unui punct ntr-un spaiul bidimensional Exemplu:
Point myPoint = new Point(1, 2);

Point este utilizat frecvent nu numai pentru desene, ci i pentru a identifica n program un punct dintr-un anumit spaiu. De exemplu, pentru a modifica poziia unui buton n fereastr putem asigna un obiect de tip Point proprietii Location indicnd astfel poziia colului din stnga-sus al butonului Exemplu:
button.Location = new Point(100, 30);

Putem construi un obiect de tip Point pentru a redimensiona un alt obiect.

Size mySize = new Size(15, 100); Point myPoint = new Point(mySize); Console.WriteLine("X: " + myPoint.X + ", Y: " + myPoint.Y);

Structura Color conine date, tipuri i metode utile n lucrul cu culori. Fiind un tip valoare (struct) i nu o clas, aceasta conine date i metode, ns nu permite instaniere, constructori, destructor, motenire.
Color myColor = Color.Brown; button1.BackColor = myColor;

Substructura FromArgb a structurii Color returneaz o culoare pe baza celor trei componente ale oricrei culori (red, green, blue). Clasa Graphics este o clas sigilat reprezentnd o arie rectangular reprezentri grafice. De exemplu, o linie frnt se poate realiza astfel: care permite

172

Point[] points = new Point[4]; points[0] = new Point(0, 0);points[1] = new Point(0, 120); points[2] = new Point(20, 120);points[3] = new Point(20, 0); Graphics g = this.CreateGraphics(); Pen pen = new Pen(Color.Yellow, 2);g.DrawLines(pen, points);

Exemplul 19: Desen Aplicaia este un exerciiu care deseneaz cercuri de raze i culori aleatoare i emite sunete cu frecven aleatoare.
Random x = new Random(); Console.Beep(300 + x.Next(1000), 150); Graphics g = this.CreateGraphics(); int i = 1 + x.Next(30); Pen p = new Pen(Color.FromArgb(x.Next(256), x.Next(256), x.Next(256))); g.DrawEllipse(p, x.Next(100), x.Next(100), i, i); Thread.Sleep(200);

Exemplul 19: Pictogram n exemplul urmtor se construiete o pictogram pe baza unei imagini.

Image thumbnail; private void Thumbnails_Load(object sender, EventArgs e) { try{Image img = Image.FromFile("C:\\Imagini\\catel.jpg"); int latime=100, inaltime=100; thumbnail=img.GetThumbnailImage(latime, inaltime,null, IntPtr.Zero);} catch{MessageBox.Show("Nu exista fisierul");} } private void Thumbnails_Paint(object sender, PaintEventArgs e) {e.Graphics.DrawImage(thumbnail, 10, 10);}

173

II.5.5.

Validarea informaiilor de la utilizator

nainte ca informaiile de la utilizator s fie preluate i transmise ctre alte clase, este necesar s fie validate. Acest aspect este important, pentru a preveni posibilele erori. Astfel, dac utilizatorul introduce o valoare real (float) cnd aplicaia ateapt un ntreg (int), este posibil ca aceasta s se comporte neprevzut abia cteva secunde mai trziu, i dup multe apeluri de metode, fiind foarte greu de identificat cauza primar a problemei.

II.5.5.(1) Validarea la nivel de cmp


Datele pot fi validate pe msur ce sunt introduse, asociind o prelucrare unuia dintre handlerele asociate evenimentelor la nivel de control (Leave, Textchanged, MouseUp etc.)

private void textBox1_KeyUp(object sender, System.Windows.Forms.KeeyEventArgs e) {if(e.Alt==true) MessageBox.Show ("Tasta Alt e apasata"); // sau if(Char.IsDigit(e.KeyChar)==true) MessageBox.Show("Ati apasat o cifra"); }

II.5.5.(2) Validarea la nivel de utilizator


n unele situaii (de exemplu atunci cnd valorile introduse trebuie s se afle ntr-o anumit relaie ntre ele), validarea se face la sfritul introducerii tuturor datelor la nivelul unui buton final sau la nchiderea ferestrei de date.

174

private void btnValidate_Click(object sender, System.EventArgs e) { foreach(System.Windows.Forms.Control a in this.Controls) { if( a is System.Windows.Forms.TextBox & a.Text=="") { a.Focus();return;} } }

II.5.5.(3) ErrorProvider
O manier simpl de a semnala erori de validare este aceea de a seta un mesaj de eroare pentru fiecare control .

myErrorProvider.SetError(txtName," Numele nu are spatii in stanga");

II.5.6.

MessageBox

Ne propunem ca n cele ce urmeaz s realizm o aplicaie simpl, n care vom folosi cteva controale i vom explica ceea ce se ntmpl din punct de vedere al programrii orientate obiect. Ne propunem s construim o fereastr cu un buton, pe care, dac-l apsm, s deschid o alt fereastr cu un mesaj: BUNA ZIUA! Pe fereastra care apare la iniializarea proiectului nostru, vom plasa un buton pe care scriem: APASATI. Dm dublu clic pe respectivul buton i scriem codul n funcia generat de aceast aciune:
MessageBox.Show("BUNA ZIUA!");

Pentru a compila i executa apsm F5. Obinem:

175

S analizm puin codul nostru, aducndu-ne aminte de noiunile de programare orientat obiect studiate:

MessageBox este o clas din spaiul de nume System.Windows.Forms, derivat din clasa Object Show este o metod static din clasa MessageBox

n momentul n care se apas butonul OK, fereastra cu acest mesaj se nchide, metoda Show cednd controlul. Metoda Show are mai multe forme n clasa MessageBox, fiind supradefinit. Apelul acestei funcii se va face n funcie de parametri. S considerm acum apelul funciei Show cu doi parametri: al doilea parametru se va referi la textul care apare pe bara de titlu n fereastr de mesaje:
MessageBox.Show("BUNA ZIUA!", "Salut");

176

S considerm n continuare apelul funciei Show cu trei parametri: al treilea parametru se va referi la butoanele care pot s apar n fereastra de mesaje (sunt ase variante):
MessageBox.Show("BUNA ZIUA!", "Salut", MessageBoxButtons.YesNo);

S mai ncercm o alt form supradefinit a metodei Show, folosind patru parametri: al patrulea se va referi la icoana care s apar, alturi de textul BUNA ZIUA. Avem la dispoziie 9 icoane.
MessageBox.Show("BUNA ZIUA!", "Salut", MessageBoxButtons.YesNo, MessageBoxIcon.Asterisk);

177

II.5.7.

Interfa definit de ctre utilizator

Sunt multe aplicaii n care, poate, dorim s ne realizm o interfa proprie, ca form, n locul celei dreptunghiulare propus de Visual C#. Dac da, exemplul de mai jos ne va da o idee asupra a ce trebuie s facem n acest caz. n primul rnd trebuie s ne desenm propria fereastr de viitoare aplicaii. Pentru aceasta vom folosi, de exemplu, aplicaia Paint. Desenm o figur geometric care va constitui viitoarea noastr fereastr. Presupunem c dorim ca fereastra s aib forma de oval.

178

Colorm ovalul cu o culoare dorit, iar pentru fundal alegem orice culoare, reinnd codul ei RGB

179

n cazul nostru: Red: 255 Greeen: 255 Blue: 0 Salvm desenul cu extensia gif: oval.gif S trecem acum la Visual C#. Alegem: File | New Project | Windows Forms Application, iar ca nume InterfataUtilizator Aduc controlul PictureBox. Din PictureBox Task aleg imaginea care s apar: oval.jpg

iar la Size Mode aleg StretchImage astfel nct imaginea s fie toat n PictureBox Deformez PictureBox-ul astfel nct ovalul desenat s ocupe o suprafa care s corespund esteticii programatorului

180

Selectez Form1, iar la proprietile corespunztoare voi selecta: BackColor 255;255;0 n acest moment fundalul ferestrei coincide ca i culoare cu fundalul desenului nostru TransparencyKey 255;255;0 - (aceleai valori ca i la culoarea fundalului)

Dac vom compila observm c obinem, deocamdat, o fereastr n care exist ovalul desenat de noi, iar fundalul este transparent. Aceast fereastr o putem deplasa, deocamdat doar folosind proprietatea barei de titlul atunci cnd inem cursorul mouse-ului apsat pe ea.

181

nchidem fereastra rezultat i ne continum proiectul. Aducem n Fereastra noastr un buton pe care-l vom folosi pentru nchiderea ferestrei rezultat

182

Scriem codul corespunztor dnd dublu clic pe buton: this.Close(); Includem biblioteca User32.dll n codul nostru: User32.dll este o bibliotec ce conine rutine pentru interfaa utilizator (ferestre, meniuri, mesaje etc.) [DllImport("User32.dll")] public static extern bool ReleaseCapture(); [DllImport("User32.dll")] public static extern int SendMessage(IntPtr Handle, int Msg, int Param1, int Param2);

Dm clic pe PictureBox, ne ducem la Fereastra Properties i selectm evenimentele legate de acest control. Dm dublu clic pe evenimentul MouseDown i scriem n Fereastra Form1.cs codul corespunztor butonului stnga al mouse-ului, cod ce se refer la posibilitatea de a putea prinde i deplasa interfaa noastr:

if (e.Button == MouseButtons.Left) { ReleaseCapture(); SendMessage(Handle, 0xA1, 0x2, 0); } Mai includem n sursa noastr i:
183

using System.Runtime.InteropServices;

n final codul arat: using using using using using using using using System; System.Collections.Generic; System.ComponentModel; System.Data; System.Drawing; System.Text; System.Windows.Forms; System.Runtime.InteropServices;

namespace Interfata3 { public partial class Form1 : Form { [DllImport("User32.dll")] public static extern bool ReleaseCapture(); [DllImport("User32.dll")] public static extern int SendMessage(IntPtr Handle, int Msg, int Param1, int Param2); public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { this.Close(); } private void pictureBox1_MouseDown(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { ReleaseCapture(); SendMessage(Handle, 0xA1, 0x2, 0); } } } }

Revenim n fereastra Form1.cs[Designer], selectm Form1, iar la Properties alegem: FormBorderStyle None

184

Apsm F5 i surpriz (plcut ): obinem ceea ce ne-am propus:

185

II.5.8.

Browser creat de ctre utilizator

O aplicaie interesant const n a ne crea propriul browser. n Visual C# alegem: File | New Project | Windows Forms Application, iar ca nume BrowserUtilizator. n Form1, n Fereastra Properties, la Text scriem B R O W S E R, cuvnt care va apare pe bara de titlu. n aceast fereastr aducem: TextBox la care, la TextBox Tasks bifm MultiLine

Button la care-i schimbm Text-ul n GO WebBrowser pe care l aliniem dup laturile din stnga, dreapta i jos a ferestrei.

Dm dublu clic pe butonul GO i scriem codul necesar navigrii:


webBrowser1.Navigate(textBox1.Text);

Rulm programul i n TextBox vom scrie o adres web. Surpriz plcut, navigatorul nostru funcioneaz!

186

Necazurile ncep n momentul n care ncercm s maximizm fereastra browser-ului pentru a putea vizualiza mai bine informaiile afiate. Din pcate n acel moment obinem:

187

Observm c fereastra WebBrowser-ului nu s-a maximizat odat cu cea a ferestrei aplicaiei. Rezult c aceast ncercare de a realiza un browser propriu nu este corect. Vom ncerca alt metod. De la grupul de controale Container aleg SplitContainer. De la opiunea Split Container Task aleg Horizontal splitter orientation

188

Deformez cele dou panouri ale containerului astfel ncnt panoul de mai sus s fie mai mic, iar Panoul 2 s ocupe o suprafa mai mare din fereastra noastr. n Panoul 1 vom plasa TextBox-ul i Button-ul, iar n Panoul 2 WebBrowser-ul. Pentru WebBrowser aleg proprietatea Doc in parent container, moment n care WebBrowser-ul se va lipi (va adera) de marginile marginile Panoului 2 Dm dublu clic pe butonul GO i scriem acelai cod ca mai nainte. Rulm programul i observm c dac maximizm fereastra WebBrowser-ul rmne lipit de marginile ferestrei. Singurul lucru care nu ne mulumete este faptul c la maximizarea ferestrei TextBox-ul i Button-ul rmn pe loc i nu ader la marginile ferestrei. S corectm acest lucru. Selectm TextBox-ul. dup care din fereastra Properties dm clic n csua corespunztoare proprietii Anchor. Suntem asistai grafic pentru a stabili partea n care dorim ca TextBox-ul s fie lipit de margini.

189

Alegem Stnga, Dreapta i Sus dnd clic pe segmentele corespunztoare. La fel procedm pentru butonul GO, unde alegem Sus i Dreapta Din acest moment cele dou controale aflate n Panoul 1 se vor deplasa odat cu marginile ferestrei. Browserul nostru poate fi mbuntit, n sensul adugrii de noi butoane care s ofere utilizatorului opiuni suplimentare: pentru navigarea napoi n lista de adrese pentru navigarea nainte n lista de adrese pentru pagina de start

Cele patru butoane le putem alinia i aduce la aceeai dimensiune folosind opiunile de pe bara de instrumente:

Selectarea tuturor butoanelor se poate face fie cu clic i Ctrl pe fiecare, fie nconjurnd cu mouse-ul respectivele butoane (n acest timp butonul stng al mouse-ului este apsat). Pe butoane fiecare poate s pun, dup gustul su, imagini n loc de aceste simboluri.
190

Vom scrie n continuare codul corespunztor fiecrui buton, dnd dublu clic pe respectivul control:

webBrowser1.GoBack(); webBrowser1.GoForward(); webBrowser1.GoHome(); //pagina goala sau webBrowser1.Navigate("www.google.com");//sau orice alta //adresa web

O alt metod pentru deformarea proporional a WebBrowser-ului, mpreun cu ferestra aplicaiei, o putem realiza doar folosind proprietatea Anchor pentru toate elementele din fereastr. control textBox button webBrowser Anchor Top, Left, Right Top, Right Top, Bottom, Left, Right

II.5.9.

Ceas

Utilizatorul nu are drept de control asupra tuturor controalelor. Exist controale de control al executrii (Timer) sau de dialog (OpenFileDialog, SaveFileDialog, ColorDialog, FontDialog, ContextMenu). Dintre acestea vom studia n cele ce urmeaz controlul Timer asupra cruia are drept de interaciune doar cel care dezvolt aplicaia. Observm c aducnd din Toolbox controlul Timer, acesta nu se afieaz pe formular, el aprnd ntr-o zon gri a suprafeei de lucru (Designer).

191

Vom stabili urmtoarele proprieti legate de Timer: Proprietate (Name) Valoare aplCeas Explicaie

Enabled Interval

True 1.000

Activarea controlului de timp Numrul de milisecunde dintre apelurile la metoda de tratare a evenimentului. Se stabileste, n cazul de fa numrtoarea din secund n secund

Aducem n formular un control Label cu urmtoarele proprieti: Control label1 Proprietate (Name) AutoSize BorderStyle FontSize Location Valoare labelCeas False Fixed3D 16,25, Bold 82;112
192

Text Size TextAlign

129;42 MiddleCenter

Dm clic pe icoana de la timer care are numele aplCeas, iar la Events, la Tick selectm aplCeas_Tick

Dm dublu clic pe aplCeas_Tick i inserm codul:


private void lblCeas_Tick(object sender, EventArgs e) { DateTime OraCurenta = DateTime.Now; lblCeas.Text=OraCurenta.ToLongTimeString(); }

Compilm

obinem

ntr-o

fereastr

vizualizarea orei sistemului

193

II.6.

Accesarea i prelucrarea datelor prin intermediul SQL Server


Crearea unei baze de date. Conectare i deconectare.

II.6.1.

nainte de a crea orice obiect al unei baze de date trebuie s crem baza de date. Pentru a realiza acest lucru trebuie s deschidei aplicaia Microsoft SQL Server Management Studio Express, i s acceptai conectarea la server-ul local.

n momentul deschiderii aplicaiei fereastra acestei aplicaii va conine fereastra Object Explorer, fereastra Sumarry i fereastra Properties.

Pentru a crea o nou baz de date din fereastra Object Explorer ce se afl n stnga ferestrei principale, executai clic pe butonul din dreapta al mouse-ului dup selectarea folderului Databases, de unde alegei opiunea New Database..

194

Denumii aceast baz de date (n exemplul de mai jos noi i-am spus CLASA). Creai un tabel alegnd n acelai mod ca i cel prezentat mai sus opiunea New Table, din folder-ul Table.

Definii coloanele tabelului prin stabilirea componentelor: numele coloanei acesta trebuie s fie unic n cadrul tabelei tipul de date tipul de date trebuie s fie un tip de date valid, din acest motiv este bine s utilizai unul dintre tipurile de date ce v apar n lista derulant

Stabilii cheia primar a tabelei prin selectarea rndului unde dorii s stabilii cheia primar i apoi prin executarea unui clic pe butonul din dreapta al mouse-ului i alegerea opiunii Set Primary Key.

195

Pentru a salva tabela creat pn acum executai clic dreapta pe numele tabelei, alegei opiunea Save Table i stabilii cu aceast ocazie i numele nou al tabelei.

II.6.2.

Popularea bazei de date

Pentru a introduce date n tabel chiar de la crearea ei executai clic dreapta pe butonul mouse-ului dup selectarea fiierului i alegei opiunea Open Table.

196

Deconectarea de la baza de date se realizeaz prin alegerea opiunii Disconect Object Explorer din meniul File al aplicaie, iar n cazul n care aplicaia este deschis i dorim reconectarea la baza de date alegem din meniul File opiunea Connect Object Explorer.

II.6.3.

Introducere n limbajul SQL

II.6.3.(1) Introducere ANSI SQL


Anumite instruciuni cum ar fi Alter sau Create nu sunt accesibile din meniu. Va trebui s apelai la scrierea lor n cod. Acest lucru poate fi realizat cu ajutorul procedurilor stocate sau cu ajutorul opiunii SQLCMD. O procedur stocat este o secven de instruciuni SQL, salvat in baza de date, care poate fi apelata de aplicaii diferite. Sql Server compileaz procedurile stocate, ceea ce creste eficiena utilizrii lor. De asemenea, procedurile stocate pot avea parametri. Dac operaiile efectuate pe server sunt mai multe (calcule complexe de ex.) atunci e mai simplu s apelai la procesarea n Stored Procedures i s returnai doar o list mic de rezultate, gata procesate. Asta mai ales cnd procesarea necesit prelucrarea unui volum mare de date. Pentru a realiza acest lucru va trebui s alegei opiunea New Stored Procedure executnd clic pe butonul din dreapta al mouse-ului pe folderul Stored Procedures din folderul Programmability al bazei de date pe care o prelucrai.

197

II.6.3.(2) Select
Forma instruciunii SELECT conine dou clauze: SELECT[DISTINCT] specific lista coloanelor ce urmeaz s fie returnate n setul de rezultate. Pentru a selecta toate coloanele se poate folosi simbolul asterisc *. Cuvntul cheie DISTINCT adugat dup cuvntul cheie SELECT elimin rndurile duplicat din rezultatele nregistrrii. FROM specific lista tabelelor sau vizualizrilor de unde selectm date.
SELECT [ID] ,[NUME] FROM [elev].[dbo].[T1]

Exemplul 1: am cerut s vizualizez nregistrarile din coloanele ID i NUME ale tabelului Elev din baza de date CLASA.

Exemplul 2: procesarea mai multor comenzi cu SQLCMD

198

II.6.3.(3) Insert
Instruciunea Insert este folosit pentru inserarea noilor rnduri de date n tabele. Ea poate fi folosit n dou variante: pentru a crea un singur rnd la fiecare rulare, n acest caz valorile pentru rndul de date respectiv sunt specificate chiar n instruciune INSERT INTO nume_tabel [(lista_de_coloane)] VALUES (lista_de_valori); Observaie: - lista de coloane este opional, dar dac este inclus trebuie s fie ncadrat ntre paranteze - cuvntul cheie NULL poate fi folosit n lista de valori pentru specificarea unei valori nule pentru o coloan Exemplul2: de utilizare a instruciunii INSERT cu includerea listei de coloane. Pentru a

vizualiza modificarea folosii instruciunea SELECT.


INSERT INTO [elev].[dbo].[T1] ([ID] ,[NUME]) VALUES (<ID, numeric,> ,<NUME, nvarchar(50),>)

pentru a insera rnduri multiple ntr-un tabel se folosete o instruciune SELECT intern

Exemplul 3: n acest exemplu instruciunea SELECT va gsi valoarea maxim de pe coloana ID, va incrementa aceast valoare cu o unitate, obinnd astfel cheia primar a unei noi nregistrri, nregistrare care va primi pe coloana NUME valoarea POPESCU. Pentru a vizualiza modificarea folosii instruciunea SELECT.
199

INSERT INTO elev.dbo.CLASA (ID ,NUME) SELECT MAX(ID)+1,'POPESCU' FROM elev.dbo.CLASA

Observaie: - lista de coloane este opional, dar dac este inclus trebuie s fie ncadrat ntre paranteze - cuvntul cheie NULL poate fi folosit n instruciunea SELECT pentru specificarea unei valori nule pentru o coloan

II.6.3.(4) Update
Instruciunea Update este folosit pentru actualizarea datelor din coloanele unui tabel Sintaxa ei este urmtoarea:
UPDATE [elev].[dbo].[CLASA] SET [ID] = <ID, numeric,> ,[NUME] = <NUME, nvarchar(50),> WHERE <Search Conditions,,>

Exemplul 4: presupunem c am greit ID-ul elevului POPESCU n loc de 7 ar fi trebuit s introducem 21. Cu ajutorul instruciunii Update vom modifica acest ID. Pentru a vizualiza modificarea folosii instruciunea SELECT.

200

Observaii: - clauza SET conine o list cu una sau mai multe coloane, mpreun cu o expresie care specific noua valoare pentru fiecare coloan - clauza WHERE conine o expresie care limiteaz rndurile ce vor fi actualizate. Dac o omitem se vor actualiza toate rndurile tabelului.

II.6.3.(5) DELETE
Instruciunea DELETE terge unul sau mai multe rnduri dintr-un tabel. n instruciunea DELETE nu sunt referite niciodat coloane, deoarece instruciunea terge rnduri ntregi de date, inclusiv toate valorile datelor din rndurile afectate.
DELETE FROM [elev].[dbo].[CLASA] WHERE <Search Conditions,,>

Exemplul 5: modificai numele elevului cu ID-ul 2 din ADAM n POPESCU, pentru a avea dou nregistrri cu acelai nume.
UPDATE elev.dbo.CLASA SET NUME = 'POPESCU' WHERE ID=2

Folosii acum instruciunea DELETE astfel:


DELETE FROM elev.dbo.CLASA WHERE NUME='POPESCU'

Observaii: - clauza WHERE este opional, dar ATENIE dac vei renuna la ea se vor terge toate nregistrrile existente - atunci cnd includei clauza WHERE ea specific rndurile care urmeaz a fi terse. Va fi tears orice nregistrare pentru care condiia indicat este adevrat.

II.6.3.(6) Comenzi de manipulare tabele


MODIFY ne permite modificarea numelui unei coloane, modificarea tipului de date al unui rnd, sau modificarea cheii primare.
201

ALTER Dup ce ai creat un tabel, aproape tot ceea ce ai specificat n instruciunea CREATE TABLE poate fi modificat folosind instruciunea ALTER TABLE. Cu ajutorul ei se pot specifica toate restriciile necesare(cheie primar, cheie extern, unicitate, verificare, etc).
ALTER TABLE <nume tabela> ADD|DROP|MODIFY (specificaii privind coloana modificata sau nou creata);

Exemplul 6: dorim s adugm o coloan la un tabel creat anterior.


alter table nume_tabel add <definitie coloana> unde <definitie coloana>=nume_tabel tip_de_date

CREATE
CREATE [TEMPORARY] TABLE [IF NOT EXISTS] nume_tabela Nume_camp tip_camp [NOT NULL | NULL] [DEFAULT default_value] AUTO_INCREMENT] [PRIMARY KEY] [reference_definition]

Pentru fiecare cmp se stabilete numele i tipul acestuia, putnd nominaliza o serie de parametri facultativi (sunt acceptate sau nu valorile nule, setarea valorii implicite, cmpul sa fie autoincrementat sau sa fie creat drept cheie primar). Exemplul 7:

202

Pentru a executa aceasta comanda faceti clic pe butonul Pentru a vizualiza efectul acestei comenzi folosii comanda Select ca in exemplul de mai jos iar apoi executai clic pe mouse pe butonul

Dup cum observai se pot vizualiza cmpurile definite n tabela Flori. Pentru a popula aceasta tabel trebuie s o deschidei cu Open.

II.6.3.(7) Manipularea datelor


FUNCIA COUNT returneaz numrul de cmpuri dintr-o tabel care corespund interogrii. Sintaxa instruciunii este:
SELECT COUNT (nume coloana) FROM nume tabel WHERE <Search Conditions,,>

Exemplul 8: pentru tabela Salarii am cerut cte persoane au salariu mai mare dect 1200.

203

Funcia SUM returneaz suma total dintr-o coloan a crei tip de date a fost declarat iniial numeric. SELECT SUM(column_name) FROM table_name Exemplul 9: pentru tabela Salarii cerem suma tuturor salariilor nregistrate pe coloana Salar.

Funcia Max returneaz cea mai mare valoare nregistrat pe o coloan Sintaxa: SELECT MAX(column_name) FROM table_name Exemplul 10: cerem s se afieze cel mai mare salariu din tabela Salarii.

Funcia Min returneaz cea mai mic valoare nregistrat pe o coloan Sintaxa: SELECT MIN(column_name) FROM table_name Exemplul 11: cerem s se afieze cel mai mare salariu din tabela Salarii.

204

Ordonarea datelor dintr-o tabel se poate realiza cu ajutorul instruciunii Order By Sintaxa:
SELECT column_name(s) FROM table_name

ORDER BY column_name(s) ASC|DESC Exemplul 12: am cerut s se ordoneze alfabetic datele nregistrate pe coloana Nume din tabela Salarii.

II.7.

Accesarea i prelucrarea datelor cu ajutorul mediului vizual


Mediul de dezvoltare Visual Studio dispune de instrumente puternice i sugestive pentru

utilizarea bazelor de date n aplicaii. Conceptual, n spatele unei ferestre n care lucrm cu date preluate dintr-una sau mai multe tabele ale unei baze de date se afl obiectele din categoriile Connection, Command, DataAdapter i DataSet prezentate. La vedere se afl controale de tip DataGridView, sau TableGridView, BindingNavigator etc. Meniul Data i fereastra auxiliar Data Sources ne sunt foarte utile n lucrul cu surse de date externe.

II.7.1.

Conectare i deconectare.

Dup crearea unei baze de date n SQL informaiile nregistrate n tabela sau tabelele bazei de date pot fi utilizate ntr-o aplicaie din Visual C# ntr-un formular sau ntr-o aplicaie consol. Vom prezenta acum modul n care se poate utiliza o baz de date ntr-un formular creat n Windows Forms. Pentru a realiza acest lucru dup deschiderea aplicaiei din fereastra Toolbox tragei pe formular cu ajutorul procedeului drag-and-drop o DataGridView, conform exemplului de mai jos.

205

Alegei sursa de date pentru acest proiect executnd clic pe butonul AddProject Data Source din fereastra DataGridView Task, alegei imediat dup aceasta sursa de date i baza de date urmrind exemplele de mai jos.

nainte de a finaliza prin executarea unui clic pe butonul Ok din fereastra Add Connection, nu uitai s verificai conexiunea executnd clic pe butonul Test Connection.

Conexiunea la baza de date se finalizeaz prin alegerea obiectului pe care dorii s l utilizai n formularul creat.

206

Dup finalizarea conexiunii sursa generat o putei vizualiza n Form1.cs. Pentru exemplul nostru am ales o baz de date numit SALARII, tabela utilizat fiind SALAR_ANGAJAT. Exemplul 1:
namespace WindowsFormsApplication1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { this.sALAR_ANGAJATTableAdapter.Fill(this.sALARIIDataSet.SALAR_ANGAJAT ); }}}

Rulai aplicaia alegnd opiunea Start Debugging din meniul Debug i vei obine afiarea datelor ntr-un formular ca n exemplul de mai jos.

Afiarea nregistrrilor din tabel se poate obine i prin alegerea opiunii Preview din fereastra DataGridView Task i executnd clic pe butonul Preview din fereastra care se deschide Preview Data .

Cheia primar se poate stabili din fereastra SalariiDataset executnd clic pe butonul din dreapta al mouse-ului i alegnd opiunea Set Primary Key pentru cmpul respectiv.

207

Stabilii cheia primar a tabelei prin selectarea rndului unde dorii s stabilii cheia primar i apoi prin executarea unui clic pe butonul din dreapta al mouse-ului i alegerea opiunii Set Primary Key.

Dup cum observai opiunile prezente n acest meniu v mai pot ajuta s tergei o coloan n tabel, s inserai o coloan din tabel s stabilii sau s modificai proprietile unei coloane deja definite sau s vizualizai codul generat.

II.7.2.

Operaii specifice prelucrrii tabelelor

Atunci cnd ntr-un formular utilizm un tabel trebuie s avem posibilitatea de a utiliza funciile ce opereaz asupra datelor incluse n el. Toate instruciunile prezentate n capitolul Introducere n limbajul SQL pot fi accesate i pe un formular. Prin "tragerea" unor obiecte din fereastra Data Sources n fereastra noastr nou, se creeaz automat obiecte specifice. n partea de jos a figurii se pot observa obiectele de tip Dataset, TableAdapter, BindingSource, BindingNavigator i, n fereastr, TableGridView. BindingNavigator este un tip ce permite, prin instaniere, construirea barei de navigare care faciliteaz operaii de deplasare, editare, tergere i adugare n tabel. Se observ c reprezentarea vizual a fiecrui obiect este nzestrat cu o sget n partea de sus, n dreapta. Un clic pe aceast sgeat activeaz un meniu contextual cu lista principalelor operaii ce se pot efectua cu obiectul respectiv. Meniul contextual asociat grilei n care vor fi vizualizate datele permite configurarea modului de lucru cu grila (sursa de date, operaiile permise i altele).
208

Prezentm un exemplu pentru inserarea unor noi date n tabelul Salar_Angajat: alegai opiunea Add Query din SALAR_ANGATTableAdapter Tasks

introducei instruciunea INSERT n forma dorit, executai clic pe butonul Query Builder pentru a vizualiza efectul, si clic pe butonul Execute Query pentru a o lansa n execuie

confirmarea introducerii noii nregistrri o vei obine imediat

pentru a vizualiza efectul acestei instruciuni putei lansa n execuie aplicaia n acelai mod se pot utiliza celelalte instruciuni i funcii ale limbajului SQL.

II.8.

Accesarea i prelucrarea datelor cu ajutorul ADO.NET


ADO.NET (ActiveX Data Objects) reprezint o parte component a nucleului .NET

Framework ce permite conectarea la surse de date diverse, extragerea, manipularea i actualizarea datelor.

209

De obicei, sursa de date este o baz de date, dar ar putea de asemenea s fie un fiier text, o foaie Excel, un fiier Access sau un fiier XML. In aplicaiile tradiionale cu baze de date, clienii stabilesc o conexiune cu baza de date i menin aceast conexiune deschis pn la ncheierea executrii aplicaiei. Conexiunile deschise necesit alocarea de resurse sistem. Atunci cnd meninem mai multe conexiuni deschise server-ul de baze de date va rspunde mai lent la comenzile clienilor ntruct cele mai multe baze de date permit un numr foarte mic de conexiuni concurente. ADO.NET permite i lucrul n stil conectat dar i lucrul n stil deconectat, aplicaiile conectndu-se la server-ul de baze de date numai pentru extragerea i actualizarea datelor. Acest lucru permite reducerea numrului de conexiuni deschise simultan la sursele de date. ADO.NET ofer instrumentele de utilizare i reprezentare XML pentru transferul datelor ntre aplicaii i surse de date, furniznd o reprezentare comun a datelor, ceea ce permite accesarea datelor din diferite surse de diferite tipuri i prelucrarea lor ca entiti, fr s fie necesar s convertim explicit datele n format XML sau invers. Aceste caracteristici sunt determinate n stabilirea beneficiilor furnizate de ADO.NET: Interoperabilitate. ADO.NET poate interaciona uor cu orice component care suport XML. Durabilitate. ADO.NET permite dezvoltarea arhitecturii unei aplicaii datorit modului de transfer a datelor ntre nivelele arhitecturale. Programabilitate. ADO.NET simplific programarea pentru diferite task-uri cum ar fi comenzile SQL, ceea ce duce la o cretere a productivitii i la o scdere a numrului de erori. Performan. Nu mai este necesar conversia explicit a datelor la transferul ntre aplicaii, fapt care duce la crete performanelor acestora. Accesibilitate. Utilizarea arhitecturii deconectate permite accesul simultan la acelai set de date. Reducerea numrului de conexiuni deschise resurselor. simultan determin utilizarea optim a

II.8.1.

Arhitectura ADO.NET

Componentele principale ale ADO.NET sunt DataSet i Data Provider. Ele au fost proiectate pentru accesarea i manipularea datelor.

210

II.8.2.

Furnizori de date (Data Providers)

Din cauza existenei mai multor tipuri de surse de date este necesar ca pentru fiecare tip de protocol de comunicare s se foloseasc o bibliotec specializat de clase. .NET Framework include SQL Server.NET Data Provider pentru interaciune cu Microsoft SQL Server, Oracle Data Provider pentru bazele de date Oracle i OLE DB Data Provider pentru accesarea bazelor de date ce utilizeaz tehnologia OLE DB pentru expunerea datelor (de exemplu Access, Excel sau SQL Server versiune mai veche dect 7.0). Furnizorul de date permite unei aplicaii s se conecteze la sursa de date, execut comenzi i salveaz rezultate. Fiecare furnizor de date cuprinde componentele Connection, Command, DataReader i DataAdapter.

II.8.3.

Conectare

nainte de orice operaie cu o surs de date extern, trebuie realizat o conexiune (legtur) cu acea surs. Clasele din categoria Connection (SQLConnection, OleDbConnection etc.) conin date referitoare la sursa de date (locaia, numele i parola contului de acces, etc.), metode pentru deschiderea/nchiderea conexiunii, pornirea unei tranzacii etc. Aceste clase se gsesc n subspaii (SqlClient, OleDb etc.) ale spaiului System.Data. n plus, ele implementeaz interfaa IdbConnection. Pentru deschiderea unei conexiuni prin program se poate instania un obiect de tip conexiune, precizndu-i ca parametru un ir de caractere coninnd date despre conexiune. Toate exemplele pe care le vom prezenta n continuare vor avea la baz o tabel cu urmtoarea structur:

Exemplul 2: conexiunea se face introducnd explicit numele serverului ca n exemplul de mai jos
SqlConnection con = new SqlConnection("DATA SOURCE=DANAD90FDEF1A8\\SQLEXPRESS;Initial Catalog=SALARII;IntegratedSecurity=SSPI");

Sau implicit :
211

SqlConnection co = new SqlConnection(".\\SQLEXPRESS;Initial Catalog=SALARII;IntegratedSecurity=SSPI");

ConnectionString (String, cu accesori de tip get i set ) definete un ir care permite identificarea tipului i sursei de date la care se face conectarea i eventual contul i parola de acces. Conine lista de parametri necesari conectrii sub forma parametru=valoare, separai prin ;. Descriere Specific furnizorul de date pentru conectarea la sursa de date. Acest furnizor Provider trebuie precizat doar dac se folosete OLE DB .NET Data Provider, i nu se specific pentru conectare la SQL Server. Data Source Identific serverul, care poate fi local, un domeniu sau o adresa IP. Initial specific numele bazei de date. Baza de date trebuie s se gseasc pe serverul Catalog dat n Data Source Integrated Logarea se face cu user-ul configurat pentru Windows. Security User ID Numele unui user care are acces de logare pe server Password Parola corespunztoare ID-ului specificat. ConnectionTimeout (int, cu accesor de tip get): specific numrul de secunde pentru care un obiect de conexiune poate s atepte pentru realizarea conectrii la server nainte de a se genera o excepie. (implicit 15). Se poate specifica o valoare diferit de 15 n ConnectionString folosind parametrul Connect Timeout, Valoarea Timeout=0 specific ateptare nelimitat. Parametru

Exemplul 3:
SqlConnection con = new SqlConnection(".\\SQLEXPRESS;Initial Catalog=SALARII; Connect Timeout=30;IntegratedSecurity=SSPI");

unde: Database (string, read-only): returneaz numele bazei de date la care sa fcut conectarea. Este necesar pentru a arta unui utilizator care este baza de date pe care se face operarea Provider (de tip string, read-only): returneaz furnizorul de date ServerVersion (string, read-only): returneaz versiunea de server la care sa fcut conectarea. State (enumerare de componente ConnectionState, read-only): returneaz starea curent a conexiunii. Valorile posibile: Broken, Closed, Connecting, Executing, Fetching, Open.

II.8.3.(1) Metode
Open(): deschide o conexiune la baza de date Close() i Dispose(): nchid conexiunea i elibereaz toate resursele alocate pentru ea BeginTransaction(): pentru executarea unei tranzacii pe baza de date; la sfrit se apeleaz Commit() sau Rollback().

212

ChangeDatabase(): se modific baza de date la care se vor face conexiunile. Noua baz de date trebuie s existe pe acelai server ca i precedenta. CreateCommand(): creeaz o comand (un obiect de tip Command) valid asociat conexiunii curente.

II.8.3.(2) Evenimente
StateChange: apare atunci cnd se schimb starea conexiunii. Handlerul corespunztor (de tipul delegat StateChangeEventHandler) spune ntre ce stri s-a fcut tranziia. InfoMessage: apare cnd furnizorul trimite un avertisment sau un mesaj ctre client.

II.8.4.

Comenzi

Clasele din categoria Command (SQLCommand, OleDbCommand etc.) conin date referitoare la o comand SQL (SELECT, INSERT, DELETE, UPDATE) i metode pentru executarea unei comenzi sau a unor proceduri stocate. Aceste clase implementeaz interfaa IDbCommand. Ca urmare a interogrii unei baze de date se obin obiecte din categoriile DataReader sau DataSet. O comand se poate executa numai dup ce s-a stabilit o conxiune cu baza de date corespunztoare. Obiectele de tip SQLCommand pot fi utilizate ntr-un scenariu ce presupune deconectarea de la sursa de date dar i n operaii elementare care presupun obinerea unor rezultate imediate. Vom exemplifica utilizarea obiectelor de tip Command n operaii ce corespund acestui caz.

II.8.4.(1) Proprieti
CommandText (String): conine comanda SQL sau numele procedurii stocate care se execut pe sursa de date. CommandTimeout (int): reprezint numrul de secunde care trebuie s fie ateptat pentru executarea comenzii. Dac se depeste acest timp, atunci se genereaz o excepie. CommandType (enumerare de componente de tip CommandType): reprezint tipul de comand care se execut pe sursa de date. Valorile pot fi: StoredProcedure (apel de procedur stocat), Text (comand SQL obinuit), TableDirect (numai pentru OleDb) Connection (System. Data. [Provider].PrefixConnection): conine obiectul de tip conexiune folosit pentru legarea la sursa de date. Parameters (System.Data.[Provider].PrefixParameterCollection): returneaz o colecie de parametri care s-au transmis comenzii. Transaction (System.Data.[Provider].PrefixTransaction): permite accesul la obiectul de tip tranzacie care se cere a fi executat pe sursa de date.

II.8.5.

DataReader

213

Datele pot fi explorate n mod conectat (cu ajutorul unor obiecte din categoria DataReader), sau pot fi preluate de la surs (dintr-un obiect din categoria DataAdapter) i nglobate n aplicaia curent (sub forma unui obiect din categoria DataSet). Clasele DataReader permit parcurgerea ntr-un singur sens a sursei de date, fr posibilitate de modificare a datelor la surs. Dac se dorete modificarea datelor la surs, se va utiliza ansamblul DataAdapter + DataSet. Datorit faptului c citete doar nainte (forward-only) permite acestui tip de date s fie foarte rapid n citire. Overhead-ul asociat este foarte mic (overhead generat cu inspectarea rezultatului i a scrierii n baza de date). Dac ntr-o aplicaie este nevoie doar de informaii care vor fi citite o singura dat, sau rezultatul unei interogri este prea mare ca sa fie reinut n memorie (caching) DataReader este soluia cea mai bun. Un obiect DataReader nu are constructor, ci se obine cu ajutorul unui obiect de tip Command i prin apelul metodei ExecuteReader() (vezi exerciiile de la capitolul anterior). Evident, pe toat durata lucrului cu un obiect de tip DataReader, conexiunea trebuie s fie activ. Toate clasele DataReader (SqlDataReader, OleDbDataReader etc.) implementeaz interfaa IDataReader.

II.8.5.(1) Proprieti:
IsClosed (boolean, read-only)- returnez true dac obiectul este deschis i fals altfel HasRows (boolean,read-only)- verific dac reader-ul conine cel puin o nregistrare Item (indexator de cmpuri) FieldCount-returneaz numrul de cmpuri din nregistrarea curent

II.8.5.(2) Metode:
Close() nchidere obiectului i eliberarea resurselor; trebuie s precead nchiderea conexiunii. GetBoolean(), GetByte(), GetChar(), GetDateTime(), GetDecimal(), GetDouble(), GetFloat(), GetInt16(), GetInt32(), GetInt64(), GetValue(), GetString() returneaz valoarea unui cmp specificat, din nregistrarea curent GetBytes(), GetChars() citirea unor octei/caractere dintr-un cmp de date binar GetDataTypeName(), GetName() returneaz tipul/numele cmpului specificat IsDBNull() returneaz true dac n cmpul specificat prin index este o valoare NULL NextResult()determin trecerea la urmtorul rezultat stocat n obiect (vezi exemplul) Read() determin trecerea la urmtoarea nregistrare, returnnd false numai dac aceasta nu exist; de reinut c iniial poziia curent este naintea primei nregistrri.
DataReader obine datele ntr-un stream secvenial. Pentru a citi aceste informaii trebuie

apelat metoda Read; aceasta citete un singur rnd din tabelul rezultat. Metoda clasic de a citi informaia dintr-un DataReader este de a itera intr-o bucla while.

214

II.8.6.
SqlCommand()

Constructori i metode asociate obiectelor de tip comand

SqlCommand cmd = new SqlCommand();

SqlCommand(string CommandText, SqlConnection con )


SqlCommand cmd = new SqlCommand("DELETE FROM SALAR_ANGAJAT WHERE nume = PREDA",co);

Cancel() oprete o comand aflat n executare. Dispose() distruge obiectul comand. ExecuteNonQuery() execut o comand care nu returneaz un set de date din baza de date. n cazul n care comanda a fost de tip INSERT, UPDATE, DELETE, se returneaz numrul de nregistrri afectate. Exemplul 4: se va terge nregistrarea cu numele PREDA i se va returna un obiect afectat
SqlConnection co = new SqlConnection("DATA SOURCE=DANAD90FDEF1A8\\SQLEXPRESS;Initial Catalog=SALARII;Integrated Security=SSPI"); co.Open(); SqlCommand cmd = new SqlCommand("DELETE FROM SALAR_ANGAJAT WHERE nume = PREDA",co); cmd.ExecuteNonQuery(); Console.ReadLine(); co.Close();

ExecuteReader() execut comanda i returneaz un obiect de tip DataReader. Exemplul 5: Se obine coninutul tabelei ntr-un obiect de tip SqlDataReader.
SqlConnection co = new SqlConnection("DATA SOURCE=DANAD90FDEF1A8\\SQLEXPRESS;Initial Catalog=SALARII;Integrated Security=SSPI"); co.Open(); SqlCommand cmd = new SqlCommand("SELECT * FROM SALAR_ANGAJAT", co); SqlDataReader reader = cmd.ExecuteReader(); while (reader.Read()) Console.WriteLine(String.Format("\t{0}\t{1}\t{2} \t {3} \t {4}", reader[0],reader[1],reader[2],reader[3],reader[4])); Console.ReadLine(); reader.Close();

215

Exemplul 6: Am construit o nou tabel tot n baza de date salarii numit telefoane. Coninutul ei este prezentat mai jos.

De data aceasta vom afia coninutul ambelor tabele.


SqlConnection co = new SqlConnection("DATA SOURCE=DANAD90FDEF1A8\\SQLEXPRESS;Initial Catalog=SALARII;Integrated Security=SSPI"); SqlCommand cmd = new SqlCommand("select * from salar_angajat;select * from telefoane", co); co.Open();SqlDataReader reader = cmd.ExecuteReader(); Console.WriteLine("Datele din tabela SALARII"); Console.WriteLine(" ID NUME PRENUME VECHIME"); Console.WriteLine(); do { while (reader.Read()) { Console.WriteLine(String.Format("\t{0}\t{1}\t{2} \t {3} ", reader[0], reader[1], reader[2], reader[3])); } Console.WriteLine("Datele din tabela TELEFOANE"); Console.WriteLine(); Console.WriteLine(" ID NUME PRENUME TELEFON"); Console.WriteLine(); } while (reader.NextResult()); Console.WriteLine(); Console.ReadLine();

Metoda

ExecuteReader()

mai

are

un

argument

opional

de

tip

enumerare,

CommandBehavior, care descrie rezultatele i efectul asupra bazei de date: - CloseConnection (conexiunea este nchis atunci cnd obiectul DataReader este nchis), - KeyInfo (returnez informaie despre coloane i cheia primar), - SchemaOnly (returnez doar informaie despre coloane),
216

- SequentialAccess (pentru manevrarea valorilor binare cu GetChars() sau GetBytes()), - SingleResult (se returneaz un singur set de rezultate), - SingleRow (se returneaz o singur linie). DataReader implementeaz i indexatori. Nu este foarte clar pentru cineva care citete codul care sunt coloanele afiate dect dac s-a uitat i n baza de date. Din aceasta cauz este preferat utilizarea indexatorilor de tipul string. Valoarea indexului trebuie s fie numele coloanei din tabelul rezultat. Indiferent c se folosete un index numeric sau unul de tipul string indexatorii ntorc totdeauna un obiect de tipul object fiind necesar conversia.

Exemplul 7: cele dou surse scrise mai jos sunt echivalente. Ele afieaz datele nregistrate pe coloana NUME.
SqlConnection co = new SqlConnection("DATA SOURCE=DANAD90FDEF1A8\\SQLEXPRESS;Initial Catalog=SALARII;Integrated Security=SSPI"); co.Open(); SqlCommand cmd = new SqlCommand("select * from salar_angajat", co); SqlDataReader rdr =cmd.ExecuteReader(); while (rdr.Read()) { Console.WriteLine(rdr[1]); } rdr.Close(); Console.ReadLine();

sau
SqlConnection co = new SqlConnection("DATA SOURCE=DANAD90FDEF1A8\\SQLEXPRESS;Initial Catalog=SALARII;Integrated Security=SSPI"); co.Open(); SqlCommand cmd = new SqlCommand("select * from salar_angajat", co); SqlDataReader rdr =cmd.ExecuteReader(); while (rdr.Read()) { Console.WriteLine(rdr["nume"]); } rdr.Close(); Console.ReadLine();

ExecuteScalar() execut comanda i returneaz valoarea primei coloane de pe primul rnd a setului de date rezultat. Este folosit pentru obinerea unor rezultate statistice. Exemplul 8:

217

Int32 var = 0; SqlConnection co = new SqlConnection("DATA SOURCE=DANAD90FDEF1A8\\SQLEXPRESS;Initial Catalog=SALARII;Integrated Security=SSPI"); co.Open(); SqlCommand cmd = new SqlCommand("SELECT COUNT(*) FROM SALAR_ANGAJAT",co); var=(Int32) cmd.ExecuteScalar(); Console.WriteLine(var); Console.ReadLine();

II.8.7.

Interogarea datelor

Pentru extragerea datelor cu ajutorul unui obiect SqlCommand trebuie s utilizm metoda ExecuteReader care returneaz un obiect SqlDataReader.
// Instaniem o comand cu o cerere i precizm conexiunea SqlCommand cmd = new SqlCommand("select salar from salar_angajat", co); // Obinem rezultatul cererii SqlDataReader rdr = cmd.ExecuteReader();

II.8.8.

Inserarea datelor

Pentru a insera date ntr-o baz de date utilizm metoda ExecuteNonQuery a obiectului SqlCommand .
// irul care pstreaz comanda de inserare string insertString = @"insert into salar_angajat(ID,NUME,PRENUME,VECHIME,SALAR) values (6 ,'BARBU' ,'EUGENIU', 17,1993)"; // Instaniem o comand cu acest cerere i precizm conexiunea SqlCommand cmd = new SqlCommand(insertString, co); // Apelm metoda ExecuteNonQuery pentru a executa comanda cmd.ExecuteNonQuery();

218

Exemplul 9: vom insera n tabela salar_angajat o nou nregistrare i vom afia tot coninutul tabelei
SqlConnection co = new SqlConnection("DATA SOURCE=DANAD90FDEF1A8\\SQLEXPRESS;Initial Catalog=SALARII;Integrated Security=SSPI"); try {co.Open(); string insertString = @"insert into salar_angajat(ID ,NUME ,PRENUME ,VECHIME ,SALAR)values (6,'BARBU','EUGENIU',17,1993)"; SqlCommand cmd = new SqlCommand(insertString, co); cmd.ExecuteNonQuery();} finally {if (co != null) { co.Close(); }} SqlCommand comand = new SqlCommand("SELECT * FROM SALAR_ANGAJAT", co); co.Open(); SqlDataReader reader = comand.ExecuteReader(); while (reader.Read()) Console.WriteLine(String.Format("\t{0}\t{1}\t{2} \t {3} \t {4}", reader[0], reader[1], reader[2], reader[3], reader[4])); Console.ReadLine(); reader.Close(); }

II.8.9.

Actualizarea datelor
n tabela

Exemplul 10: vom modifica numele unui angajat, din BARBU n BIBIRE SALAR_ANGAJAT i vom afia tot coninutul tabelei

SqlConnection co = new SqlConnection("DATA SOURCE=DANAD90FDEF1A8\\SQLEXPRESS;Initial Catalog=SALARII;Integrated Security=SSPI"); co.Open(); string updateString = @"update SALAR_ANGAJAT set NUME = 'BIBIRE' where NUME = 'BARBU'"; SqlCommand cmd = new SqlCommand(updateString); cmd.Connection = co; // Stabilim conexiunea cmd.ExecuteNonQuery();//Apelm ExecuteNonQuery pentru executarea comenzii SqlCommand comand = new SqlCommand("SELECT * FROM SALAR_ANGAJAT", co); SqlDataReader reader = comand.ExecuteReader(); while (reader.Read()) Console.WriteLine(String.Format("\t{0}\t{1}\t{2} \t {3} \t {4}",reader[0], reader[1], reader[2], reader[3], reader[4])); Console.ReadLine();reader.Close(); }

219

II.8.10. tergerea datelor


Se utilizeaz aceeai metod ExecuteNonQuery. Exemplul 11: vom terge nregistrarea cu numele BIBIRE din tabela SALAR_ANGAJAT i vom afia tot coninutul tabelei
SqlConnection co = new SqlConnection("DATA SOURCE=DANAD90FDEF1A8\\SQLEXPRESS;Initial Catalog=SALARII;Integrated Security=SSPI"); co.Open(); // irul care pstreaz comanda de tergere string deleteString = @"delete from SALAR_ANGAJAT where NUME = 'BIBIRE'"; // Instaniem o comand SqlCommand cmd = new SqlCommand(); // Setm proprietatea CommandText cmd.CommandText = deleteString; // Setm proprietatea Connection cmd.Connection = co; // . Executm comanda cmd.ExecuteNonQuery(); SqlCommand comand = new SqlCommand("SELECT * FROM SALAR_ANGAJAT", co); SqlDataReader reader = comand.ExecuteReader(); while (reader.Read()) Console.WriteLine(String.Format("\t{0}\t{1}\t{2} \t {3} \t {4}", reader[0], reader[1], reader[2], reader[3], reader[4])); Console.ReadLine(); reader.Close(); }

Exemplul 12: Realizai o conexiune la baza de date SALAR_ANGAJAT i afiai cea mai mare vechime i suma tuturor salariilor nregistrate.
Int32 var = 0; Int32 suma = 0; SqlConnection co = new SqlConnection("DATA SOURCE=DANAD90FDEF1A8\\SQLEXPRESS;Initial Catalog=SALARII;Integrated Security=SSPI"); co.Open(); SqlCommand comand1 = new SqlCommand("select MAX(VECHIME) FROM SALAR_ANGAJAT",co); var = (Int32)comand1.ExecuteScalar(); Console.Write(" CEA MAI MARE VECHIME A UNUI ANGAJAT ESTE DE :"); Console.Write(var); Console.WriteLine(" ANI"); SqlCommand comand2 = new SqlCommand("select SUM(SALAR) FROM SALAR_ANGAJAT", co); suma = (Int32)comand2.ExecuteScalar(); Console.Write(" SUMA SALARIILOR TUTUROR ANGAJATILOE ESTE: "); Console.Write(suma); Console.WriteLine(" RON"); Console.ReadLine();

220

Exemplul 12: Realizai funcii care s implementeze operaiile elementare asupra unei baze de date i verificai funcionalitatea lor. conexiunea la baza de date
class program { SqlConnection conn; public program() { conn = new SqlConnection("DATA SOURCE=DANAD90FDEF1A8\\SQLEXPRESS;Initial Catalog=SALARII;Integrated Security=SSPI");}

apelarea din funcia main a funciilor care vor realiza afiarea datelor, inserarea unei noi valori, tergerea unor valori, actualizare
static void Main() { program scd = new program(); Console.WriteLine("SALARII ANGAJATI"); scd.ReadData(); scd.Insertdata(); Console.WriteLine("AFISARE DUPA INSERT"); scd.ReadData(); scd.UpdateData(); Console.WriteLine("AFISARE DUPA UPDATE"); scd.ReadData(); scd.DeleteData(); Console.WriteLine("AFISARE DUPA DELETE"); scd.ReadData(); int number_inregistrari = scd.GetNumberOfRecords(); Console.WriteLine("Numarul de inregistrari: {0}", number_inregistrari); Console.ReadLine(); }

funcia de citire i afiare a datelor


public void ReadData() { SqlDataReader rdr = null; try { conn.Open(); SqlCommand cmd = new SqlCommand("select * from salar_angajat", conn); rdr = cmd.ExecuteReader(); while (rdr.Read()) Console.WriteLine(String.Format("\t{0}\t{1}\t{2} \t {3} \t {4}", rdr[0], rdr[1], rdr[2], rdr[3], rdr[4])); } finally { if (rdr != null) { rdr.Close(); } if (conn != null) { conn.Close(); } } }

funcia care realizeaz inserarea unei noi valori

221

public void Insertdata() { try {conn.Open(); string insertString = @"insert into salar_angajat(ID ,NUME ,PRENUME ,VECHIME ,SALAR)values (6,'BARBU','EUGENIU',17,1993)"; SqlCommand cmd = new SqlCommand(insertString, conn); cmd.ExecuteNonQuery();} finally { if (conn != null) { conn.Close(); } }}

funcia care actualizeaz anumite valori specificate


public void UpdateData() { try { conn.Open(); string updateString = @"update SALAR_ANGAJAT set PRENUME = 'MARIA' where PRENUME = 'DANIELA'"; SqlCommand cmd = new SqlCommand(updateString); cmd.Connection = conn; cmd.ExecuteNonQuery(); } finally { if (conn != null) { conn.Close(); } } }

funcia care terge una sau mai multe nregistrri n funcie de condiia impus
public void DeleteData() { try { conn.Open(); string deleteString = @"delete from SALAR_ANGAJAT where NUME = 'BARBU'"; SqlCommand cmd = new SqlCommand(); cmd.CommandText = deleteString; cmd.Connection = conn; cmd.ExecuteNonQuery(); } finally { if (conn != null) { conn.Close(); } } }

funcia care numr nregistrrile din tabel


public int GetNumberOfRecords() { int count = -1; try { conn.Open(); SqlCommand cmd = new SqlCommand("select count(*) from SALAR_ANGAJAT", conn); count = (int)cmd.ExecuteScalar(); } finally { if (conn != null) { conn.Close(); } } return count; }
222

II.8.11. DataAdapter i DataSet


Folosirea combinat a obiectelor DataAdapter i DataSet permite operaii de selectare, tergere, modificare i adugare la baza de date. Clasele DataAdapter genereaz obiecte care funcioneaz ca o interfa ntre sursa de date i obiectele DataSet interne aplicaiei, permind prelucrri pe baza de date. Ele gestioneaz automat conexiunea cu baza de date astfel nct conexiunea s se fac numai atunci cnd este imperios necesar. Un obiect DataSet este de fapt un set de tabele relaionate. Folosete serviciile unui obiect DataAdapter pentru a-i procura datele i trimite modificrile napoi ctre baza de date. Datele sunt stocate de un DataSet n format XML, acelai folosit i pentru transferul datelor. n exemplul urmtor se preiau datele din tablele salar_angajat i telefoane:
SqlDataAdapter de=new SqlDataAdapter("SELECT nume,prenume FROM salar_angajat, conn); de.Fill(ds," salar_angajat ");//transfer tabele locale numite salariu_angajat SqlDataAdapter dp=new SqlDataAdapter("SELECT nume,telefon FROM telefoane,conn); dp.Fill(ds," telefoane ");//transfer datele n datasetul ds sub forma unei tabele locale numite telefoane datele n datasetul ds sub forma unei

Proprieti DeleteCommand, InsertCommand, SelectCommand, UpdateCommand (Command), conin comenzile ce se execut pentru selectarea sau modificarea datelor n sursa de date. MissingSchemaAction (enumerare) determin ce se face atunci cnd datele aduse nu se potrivesc peste schema tablei n care sunt depuse. Poate avea urmtoarele valori: Add - implicit, DataAdapter adaug coloana la schema tablei AddWithKey se adaug coloana i informaii relativ la cheia primar Ignore - se ignor lipsa coloanei respective, ceea ce duce la pierdere de date
223

Error - se genereaz o excepie de tipul InvalidOperationException. Metode Constructori:SqlDataAdapter()|SqlDataAdapter(obiect_comanda)|


SqlDataAdapter(string_comanda, conexiune);

Fill() permite umplerea unei tabele dintr-un obiect DataSet cu date. Permite specificarea obiectului DataSet n care se depun datele, eventual a numelui tablei din acest DataSet, numrul de nregistrare cu care s se nceap popularea (prima avnd indicele 0) i numrul de nregistrri care urmeaz a fi aduse. Update() permite transmiterea modificrilor efectuate ntr-un DataSet ctre baza de date. Un DataSet este format din Tables (colecie format din obiecte de tip DataTable este compus la rndul lui DataTable; dintr-o colecie de DataRow i DataColumn), Relations

(colecie de obiecte de tip DataRelation pentru memorarea legturilor printecopil) i ExtendedProperties ce conine proprieti definite de utilizator. Scenariul uzual de lucru cu datele dintr-o tabel conine urmtoarele etape: popularea succesiv a unui DataSet prin intermediul unuia sau mai multor obiecte DataAdapter, apelnd metoda Fill procesarea datelor din DataSet folosind numele tabelelor stabilite la umplere, ds.Tables["salar_angajat"], sau indexarea acestora, ds.Tables[0], ds.Tables[1] actualizarea datelor prin obiecte comand corespunztoare operaiilor INSERT, UPDATE i DELETE. Un obiect CommandBuilder poate construi automat o combinaie de comenzi ce reflect modificrile efectuate.
Aadar, DataAdapter deschide o conexiune doar atunci cnd este nevoie i o nchide

imediat aceasta nu mai este necesar. De exemplu DataAdapter realizeaz urmtoarele operaiuni atunci cnd trebuie sa populeze un DataSet:deschide conexiunea, populeaz DataSet-ul,nchide conexiunea i urmtoarele operaiuni atunci cnd trebuie sa fac update pe baza de date: deschide conexiunea, scrie modificrile din DataSet n baza de date, nchide conexiunea. ntre operaiunea de populare a
DataSet-ului i cea de update conexiunile sunt nchise. Intre aceste operaii n DataSet se poate

scrie sau citi. Crearea unui obiect de tipul DataSet se face folosind operatorul new. DataSet dsProduse = new DataSet (); Constructorul unui DataSet nu necesit parametri. Exist totui o suprancrcare a acestuia care primete ca parametru un string i este folosit atunci cnd trebuie s se fac o serializare a datelor ntr-un fiier XML. n exemplul anterior avem un DataSet gol i avem nevoie de un DataAdapter pentru a-l popula. Un obiect DataAdapter conine mai multe obiecte Command (pentru inserare, update,
delete i select) i un obiect Connection pentru a citi i scrie date.

224

n exemplul urmtor construim un obiect de tipul DataAdapter, daSALAR. Comanda SQL specific cu ce date va fi populat un DataSet, iar conexiunea co trebuie s fi fost creat anterior, dar nu i deschis. DataAdapter-ul va deschide conexiunea la apelul metodelor Fill i Update. SqlDataAdapter daSALAR =
new SqlDataAdapter ("SELECT NUME, SALAR SALARIU_ANGAJAT", co);

Prin intermediul constructorului putem instania doar comanda de interogare. Instanierea celorlalte se face fie prin intermediul proprietilor pe care le expune DataAdapter, fie folosind obiecte de tipul CommandBuilder.
SqlCommandBuilder cmdBldr = new SqlCommandBuilder (daSALAR);

La iniializarea unui CommandBuilder se apeleaz

un constructor care primete ca

parametru un adapter, pentru care vor fi construite comenzile. SqlCommandBuilder are nu poate construi dect comenzi simple i care se aplica unui singur tabel. Atunci cnd trebui ca sa facem comenzi care vor folosi mai multe tabele este recomandata construirea separat a comenzilor i apoi ataarea lor adapterului folosind proprieti. Popularea DataSet-ului se face dup ce am construit cele dou instane:
daSALAR.Fill (dsNUME, "NUME");

n exemplul urmtor va fi populat DataSet-ul dsNUME. Cel de-al doilea parametru (string) reprezint numele tabelului (nu numele tabelului din baza de date, ci al tabelului rezultat n
DataSet) care va fi creat. Scopul acestui nume este identificarea ulterioar a tabelului. n cazul n

care nu sunt specificate numele tabelelor, acestea vor fi adugate n DataSet sub numele Table1, Table2, ... Un DataSet poate fi folosit ca surs de date pentru un DataGrid din Windows Forms sau ASP.Net .
DataGrid dgANGAJAT = new DataGrid(); dgANGAJAT.DataSource = dsNUME; dgANGAJAT.DataMembers = "NUME";

Dup ce au fost fcute modificri ntr-un DataSet acestea trebuie scrise i n baza de date. Actualizarea se face prin apelul metodei Update.
daSALAR.Update (dsNUME, "NUME");

225

II.9.

Aplicaie final
Pentru a realiza aceast aplicaie trebuie s creai o baz de date (noi am numit-o

salarii) baz n care trebuie s creai o tabel (noi am anumit-o salar_angajat) cu cinci cmpuri (ID, NUME, PRENUME, VECHIME, SALAR) pe care o putei popula cu cteva nregistrri. Noi ne-am propus s crem o aplicaie care s: - insereze una sau mai multe nregistrri, - s tearg una sau mai multe nregistrri, - s afieze permanent numrul de astfel de modificri efectuate, - s afieze coninutul tabelei dup fiecare modificare, - s calculeze suma salariilor din tabel - s afieze cel mai mare salar - s afieze cea mai mic vechime - s afieze nregistrrile n ordine lexicografic Pentru a realiza i voi acelai lucru va trebui s parcurgei paii explicai n continuare. Din meniul File al aplicaiei Microsoft Visual C# 2008 Express Edition alegei New Project/Windows Forms Application. Pe formular va trebui s tragei un buton (INSERARE), cinci etichete(ID, NUME, PRENUME, VECHIME, SALAR), cinci casete de text poziionate sub fiecare etichet, o etichet n care s introducei textul NUMR DE MODIFICRI, iar n dreptul ei o caset de text. Urmrii imaginea din figura de mai jos:

n sursa din spatele formularului declarai o variabil de tip int nrmodificari care va contoriza permanent numrul de modificri aduse tabelei (tergeri, inserri) i conexiunea la baza de date.
public partial class Form1 : Form { int nrmodificari = 0; SqlConnection co; public Form1() { InitializeComponent();
226

co = new SqlConnection(@"Data D90FDEF1A8\SQLEXPRESS;Database=dana;Trusted_Connection=yes;"); co.Open(); }

Source=DANA-

Executai ciclk dublu pe butonul INSERARE i completai sursa lui cu instruciunile care vor permite inserarea unor nregistrri noi n tabel. Numrul de inserri l vei putea vizualiza n caseta de text asociat etichetei cu numele NUMR DE MODIFICRI.
private void button1_Click(object sender, EventArgs e) { string insertsql; insertsql="insert into salar_angajat (id,nume,prenume,vechime,salar) values ('";insertsql+=textBox1.Text+"','"+textBox2.Text+"','"+textBox3.Text+"','"+textB ox4.Text+"','"+textBox5.Text+"')"; SqlCommand cmd = new SqlCommand(insertsql, co); nrmodificari = nrmodificari+cmd.ExecuteNonQuery(); textBox6.Text =Convert.ToString(nrmodificari);} }

Pentru a vizualiza i coninutul tabelei pe formular va trebui s mai tragei un buton AFISARE , patru etichete (pentru nume,prenume,vechime i salar), iar n sursa butonului AFISARE s completai codul de mai jos, cod care v va permite afiarea celor patru cmpuri din tabel.

227

private void button2_Click(object sender, EventArgs e) { string selectSQL = "SELECT * FROM salar_angajat"; SqlCommand cmd = new SqlCommand(selectSQL, co); SqlDataAdapter adapter = new SqlDataAdapter(cmd); DataSet ds = new DataSet(); adapter.Fill(ds, "salar_angajat"); label7.Text = "NUME"; label8.Text = "PRENUME"; label9.Text = "VECHIME"; label10.Text = "SALAR"; foreach (DataRow r in ds.Tables["salar_angajat"].Rows) { label7.Text = label7.Text +"\n" + r["nume"] + "\n"; label8.Text = label8.Text + "\n"+r["prenume"] + "\n"; label9.Text = label9.Text +"\n"+ r["vechime"] + "\n"; label10.Text = label10.Text + "\n"+r["salar"] + "\n"; } }

V ntoarcei acum pe formular n mod design, i mai adugai un buton pe care noi lam numit STERGERE, o etichet n care va trebui s introducei textul INTRODUCETI NUMELE ANGAJATULUI CE TREBUIE STERS i o caset de text, pe care o vei poziiona n dreptul etichetei.

Executai clic dublu pe butonul STERGE i completai sursa cu codul care v va permite tergerea unui angajat al crui nume va fi preluat din caseta de text.
private void button3_Click(object sender, EventArgs e) { string deletesql; deletesql = "delete from salar_angajat where nume='"; deletesql += textBox7.Text+ "'"; SqlCommand cmd = new SqlCommand(deletesql, co); nrmodificari = nrmodificari + cmd.ExecuteNonQuery(); textBox6.Text = Convert.ToString(nrmodificari); }

Pentru a obine suma salariilor din tabel va trebui s completai formularul n mod design cu nc un buton cel pe care noi l+am numit SUMA SALARII, n dreptul lui s adugai o

228

caset de text i s completai sursa butonului cu codul care v va permite obinerea sumei salariilor nregistrate n tabel apelnd funcia SUM.
private void button4_Click(object sender, EventArgs e) { int suma; SqlCommand cmd = new SqlCommand("select SUM(SALAR) FROM SALAR_ANGAJAT", co); suma= (int)cmd.ExecuteScalar(); textBox8.Text = Convert.ToString(suma); }

n acest moment pregtii suprafaa formularului pentru includerea unor noi butoane, casete de text i etichete, prin : modificarea poziiilor celor deja existente adugarea a patru etichete pe care vor fi introduse textele NUME, PRENUME, VECHIME, SALAR

229

Adugai dou butoane i dou casete de text pe care ncercai s le poziionai sub butonul SUMA SALARII. Textul celor dou butoane va fi: Cea mai mica vechime, respectiv Cel mai mare salariu.

Sursele din spatele celor dou butoane vor fi cele din exemplele de mai jos:
private void button5_Click(object sender, EventArgs e) { int min; SqlCommand cmd = new SqlCommand("select min(vechime) FROM SALAR_ANGAJAT", co); min = (int)cmd.ExecuteScalar(); textBox9.Text = Convert.ToString(min); } private void button6_Click(object sender, EventArgs e) { int max; SqlCommand cmd = new SqlCommand("select max(SALAR) FROM SALAR_ANGAJAT", co); max = (int)cmd.ExecuteScalar(); textBox10.Text = Convert.ToString(max); }

n dreptul butonului AFISARE adugai un buton pe care vei insera textul: AFISARE IN ORDINE LEXICOGRAFICA, i completai sursa lui cu urmtorul cod.
private void button1_Clic_1(object sender, EventArgs e) { string selectSQL = "select * FROM SALAR_ANGAJAT ORDER BY NUME ASC"; SqlCommand cmmd = new SqlCommand(selectSQL, co); SqlDataAdapter adapter = new SqlDataAdapter(cmmd); DataSet ds = new DataSet(); adapter.Fill(ds, "salar_angajat"); label7.Text = ""; label8.Text = ""; label9.Text = ""; label10.Text = ""; foreach (DataRow r in ds.Tables["salar_angajat"].Rows) { label7.Text = label7.Text + "\n" + r["nume"] + "\n"; label8.Text = label8.Text + "\n" + r["prenume"] + "\n";
230

label9.Text = label9.Text + "\n" + r["vechime"] + "\n"; label10.Text = label10.Text + "\n" + r["salar"] + "\n"; } }

n acest moment putei spune c ai creat o aplicaie care v ajut s gestionai ntr-o oarecare msur o tabel a unei baze de date. Toate funciile i comenzile SQL prezentate n acest capitol se pot regsi ntr-o aplicaie de acest gen. Totul este s v stabilii prioritile nainte de a v apuca de lucru, iar dac pe parcurs mai dorii s adugai sau s modificai aplicaia ai observat c acest lucru este posibil.

231

También podría gustarte