Documente Academic
Documente Profesional
Documente Cultură
Microsoft Dot Net
Microsoft Dot Net
Programarea Vizual
.NET
Microsoft
Framework
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
.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.
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.
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.
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) { } } }
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
I.2.3.
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 */
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).
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.
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;
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(); } } }
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);
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
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 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:
19
Conversia din ir de caractere n numr se realizeaz cu ajutorul metodei Parse tot din clasa Object. Exemplul 12:
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
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
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"); }
Exemplul 17: Prin conversia de tip unboxing, obiectul ob poate fi asignat variabilei ntregi i:
int i = 13; object ob = i; i = (int)ob;
22
Observaie: n cazul n care irul de caractere nu reprezint un numr valid, conversia acestui ir la numr va eua.
Exemplul 18:
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();
} } }
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(); } } }
26
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;
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(); } } }
"
este echivalent cu
T? var;
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.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
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
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;
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;
");
");
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
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; } } }
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);
41
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; } } }
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("@"); }
44
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"}
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
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; }
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(); } } }
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.
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(); } } } }
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
Prin aceast declaraie nu se aloc i spaiu pentru memorare. Pentru aceasta, tabloul trebuie instaniat:
nume = new Tip[NumarElemente];
sau
int[] v = {1,2,3);
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
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; } } }
iar instanierea:
nume = new Tip[Linii,Coloane];
Accesul:
nume[indice1,indice2]
58
sau
int[,] mat = {{1,2,3},{4,5,6},{7,8,9}};
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 = {
};
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
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
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
Compare CompareOrdinal CompareTo EndsWith StartsWith IndexOf LastIndexOf Concat CopyTo Insert Join PadLeft PadRight Remove Replace Split Substring ToLower ToUpper Trim TrimEnd TrimStart
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
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()); } } }
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
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();
} } }
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
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.
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:
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.
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.
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#.
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
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
83
} 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
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 ...
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
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 } } }
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
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
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.
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:
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
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 }
Cmpuri volatile Cmpurile volatile se declar cu ajutorul cuvntului volatile, care poate fi ataat doar urmtoarelor tipuri:
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:
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(); }
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(); } } }
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 }]
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:
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]
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
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:
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
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(); } } }
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
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
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.
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();
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 84:
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(); } }
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:
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.
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.
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
Violonist
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.
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(); } } }
class ClasaDeBaza { protected string var; public ClasaDeBaza(string var) { this.var = var; } }
//constructor
I.7.3.
Metode
Prin mecanismul de motenire avem posibilitatea reutilizrii codului i redefinirii (prin polimorfism) a metodelor.
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:
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)
public Exception InnerException {get;} public virtual string Message {get;} public virtual string Source {get; set;}
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.
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)
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.
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"); } } }
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.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
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.
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.
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");
//(1) //(2)
Va genera eroare, deoarece modificatorul sealed al metodei Afis(), din clasa Derivata, va mpiedic suprascrierea acestei metode n clasa Derivata2.
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 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.
n cele ce urmeaz pentru explicaiile care vor avea loc vom considera o aplicaie Windows numit Test:
136
Fereastra Toolbox
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
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
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
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
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 s u 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
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.
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.
Vizibilitatea unui formular poate fi setat folosind metodele Hide sau Show. Pentru a ascunde un formular putem folosi :
this.Hide();
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).
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 :
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.
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.
Proprietatea Text Aceast proprietate poate fi setat n timpul proiectrii din fereastra Properties, sau programatic, introducnd o declaraie n codul programului.
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.
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();.
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:
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:
Vei obine la rularea aplicaiei afiarea uneia din cele dou imagini, n funcie de butonul apsat.
sau
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.
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.
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.
n aceeai fereastr de cod scriem funcia recursiv patrat care va genera fractalul.
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.
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.
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:
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);}
158
Executai dublu clic pe butonul START i editai administratorul evenimentului conform exemplului de mai jos:
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:
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:
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().
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(); }
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",
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(); }
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
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;
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_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()
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);
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.
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.
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"); }
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 .
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!");
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.
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
185
II.5.8.
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.
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
129;42 MiddleCenter
Dm clic pe icoana de la timer care are numele aplCeas, iar la Events, la Tick selectm aplCeas_Tick
Compilm
obinem
ntr-o
fereastr
193
II.6.
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.
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.
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.
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
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
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
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.
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);
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.
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.
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.
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
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.
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.
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
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()
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.
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
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(); }
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 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(); } } }
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
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);
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
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