Sunteți pe pagina 1din 266

3

Cuprins

Capitolul 1. Compilarea, decompilarea i obscurizarea
programelor C#

1. Obiective ............................................................................................................................... 9
2. Structura general a unui program C# ................................................................... 10
2.1. Clase ............................................................................................................................ 10
2.2. Clase statice i membri statici .......................................................................... 11
2.3. Cmpuri constante ................................................................................................ 13
2.4. Structuri .................................................................................................................... 14
2.5. Trimiterea argumentelor prin referin ...................................................... 16
2.6. Operaiile de boxing i unboxing ..................................................................... 16
2.7. Enumeraii ................................................................................................................ 17
3. Compilarea, decompilarea i obscurizarea codului .......................................... 18
3.1. Compilarea. Limbajul Intermediar Comun ................................................. 18
3.2. Decompilarea. Programul .NET Reflector .................................................... 19
3.3. Compilarea n modurile Debug i Release ................................................... 23
3.4. Obscurizarea codului. Dotfuscator ................................................................. 29
4. Aplicaii ................................................................................................................................ 30

Capitolul 2. Stilul de scriere a codului. Tratarea excepiilor.
Interfaa grafic cu utilizatorul

1. Obiective ............................................................................................................................. 35
2. Stilul de scriere a codului ............................................................................................. 35
2.1. Acoladele ................................................................................................................... 36
2.2. Standarde de programare .................................................................................. 37
2.3. Convenii pentru nume ....................................................................................... 39
3. Tratarea excepiilor ........................................................................................................ 42
3.1. Tratarea excepiilor pe firul de execuie al aplicaiei ............................. 46
4. Interfaa cu utilizatorul ................................................................................................. 47
4.1. Proiectarea comenzilor i interaciunilor ................................................... 47
4.2. Considerente practice .......................................................................................... 48
4.3. Profilurile utilizatorilor ...................................................................................... 50
5. Interfaa grafic cu utilizatorul n Microsoft Visual Studio .NET ................. 51
6. Elemente de C# ................................................................................................................ 58
6.1. Clase pariale ........................................................................................................... 58
6.2. Proprieti. Accesori ............................................................................................. 59
6.2.1. Accesorul get ................................................................................................. 60
6.2.2. Accesorul set .................................................................................................. 61
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com

4
6.2.3. Aspecte mai complexe ale lucrului cu proprieti ................................ 62
7. Aplicaii ................................................................................................................................ 65

Capitolul 3. Reutilizarea codului cu ajutorul DLL-urilor

1. Obiective ............................................................................................................................. 69
2. Bibliotecile legate dinamic .......................................................................................... 69
3. Crearea DLL-urilor n C# .............................................................................................. 70
3.1. Legarea static ........................................................................................................ 72
3.2. Legarea dinamic................................................................................................... 72
3.3. Depanarea unui DLL ............................................................................................. 74
4. Grafic n C# ...................................................................................................................... 75
5. Aplicaii ................................................................................................................................ 77

Capitolul 4. Documentarea unui proiect. Fiiere de ajutor

1. Obiective ............................................................................................................................. 81
2. Crearea de fiiere de ajutor ......................................................................................... 81
2.1. Crearea de fiiere HLP ......................................................................................... 81
2.2. Crearea de fiiere CHM ........................................................................................ 86
3. Activarea unui fiier de ajutor prin program ....................................................... 88
3.1. Process.Start ............................................................................................................. 88
3.2. HelpProvider ........................................................................................................... 88
3.3. Help .............................................................................................................................. 89
4. Generarea automat a documentaiei API ............................................................ 90
5. Comentariile ...................................................................................................................... 92
6. Lucrul cu fiiere n C#: ncrcare, salvare ............................................................. 95
7. Aplicaii ................................................................................................................................ 96

Capitolul 5. Diagrame UML

1. Obiective .......................................................................................................................... 105
2. Diagrame principale ale UML .................................................................................. 105
2.1. Diagrama cazurilor de utilizare .................................................................... 105
2.2. Diagrama de clase............................................................................................... 107
2.2.1. Dependena ................................................................................................. 107
2.2.2. Asocierea ...................................................................................................... 108
2.2.3. Agregarea i compunerea ..................................................................... 110
2.2.4. Motenirea ................................................................................................... 110
2.2.5. Metode abstracte i virtuale ................................................................. 112
2.2.6. Interfee ........................................................................................................ 113
2.2.7. Trsturi statice ........................................................................................ 113
2.3. Diagrame de activiti....................................................................................... 114
2.4. Diagrama de secvene ....................................................................................... 117
3. Altova UModel ................................................................................................................ 118
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com

5
3.1. Diagrama de clase............................................................................................... 119
3.1.1. Generarea de cod ......................................................................................... 120
3.1.2. Crearea diagramei unui proiect existent ........................................... 125
3.1.3. Aranjarea automat a elementelor din diagrame .......................... 128
3.2. Celelalte diagrame .............................................................................................. 128
4. Aplicaii ............................................................................................................................. 128

Capitolul 6. Arhitectura MVC

1. Obiective ........................................................................................................................... 131
2. Introducere. Arhitectura cu trei straturi ............................................................ 131
3. Arhitectura MVC ............................................................................................................ 133
4. Arhitectura MVP ............................................................................................................ 135
4.1. Variante de actualizare a Vizualizrii ......................................................... 136
5. Aplicaii ............................................................................................................................. 138

Capitolul 7. ablonul de proiectare Metoda Fabric

1. Obiective .......................................................................................................................... 151
2. ablonul creaional Metoda Fabric ..................................................................... 151
3. Exemplu de implementare ....................................................................................... 152
4. Motenirea i polimorfismul .................................................................................... 154
4.1. Polimorfismul ...................................................................................................... 154
4.2. Clase abstracte ..................................................................................................... 154
4.3. Interfee .................................................................................................................. 155
4.4. Membri virtuali ................................................................................................... 156
4.5. Clase sigilate i membri sigilai .................................................................... 158
4.6. nlocuirea unui membru cu ajutorul cuvntului cheie new .............. 159
4.7. Accesarea clasei de baz cu ajutorul cuvntului cheie base ............. 160
5. Aplicaii ............................................................................................................................. 161

Capitolul 8. abloanele de proiectare Singleton i Prototip

1. Obiective .......................................................................................................................... 167
2. ablonul creaional Singleton .................................................................................. 167
2.1. Exemplu de implementare ............................................................................. 168
3. ablonul creaional Prototip .................................................................................... 169
3.1. Exemplu de implementare ............................................................................. 170
4. Aplicaii ............................................................................................................................. 172

Capitolul 9. ablonul de proiectare Faad

1. Obiectiv ............................................................................................................................. 185
2. Scop i motivaie ........................................................................................................... 185
3. Aplicabilitate .................................................................................................................. 186
4. Analiza ablonului ........................................................................................................ 187
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com

6
5. Exemplu de implementare ....................................................................................... 188
6. Aplicaie ............................................................................................................................ 190

Capitolul 10. ablonul de proiectare Proxy

1. Obiectiv ............................................................................................................................. 193
2. Scop i motivaie ........................................................................................................... 193
3. Aplicabilitate .................................................................................................................. 194
4. Analiza ablonului ........................................................................................................ 195
5. Exemplu de implementare ....................................................................................... 196
6. Aplicaii ............................................................................................................................. 197

Capitolul 11. ablonul de proiectare Comand

1. Obiective .......................................................................................................................... 211
2. Scop i motivaie ........................................................................................................... 211
3. Aplicabilitate .................................................................................................................. 214
4. Analiza ablonului ........................................................................................................ 215
5. Exemplu de implementare ....................................................................................... 216
6. Aplicaie ............................................................................................................................ 218

Capitolul 12. Evaluarea vitezei de execuie a unui program

1. Obiective .......................................................................................................................... 231
2. Metoda DateTime.......................................................................................................... 231
3. Pointeri n C# ................................................................................................................. 232
4. Metoda PerformanceCounter ................................................................................... 234
4.1. Metode de accelerare ........................................................................................ 235
5. Metoda Stopwatch ........................................................................................................ 236
6. Compilarea JIT ............................................................................................................... 236
7. Aplicaii ............................................................................................................................. 238

Capitolul 13. Testarea unitilor cu NUnit

1. Obiectiv ............................................................................................................................. 243
2. Testarea unitilor ....................................................................................................... 243
3. Utilizarea platformei NUnit ...................................................................................... 244
4. Aplicaii ............................................................................................................................. 249

Capitolul 14. Rapoarte de testare

1. Obiective .......................................................................................................................... 253
2. Testarea unei ierarhii de clase ................................................................................ 253
3. Aplicaie ............................................................................................................................ 256

Referine .................................................................................................................... 263
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com

7


Cuvnt nainte

n anul 2001 am nceput s predau laboratoarele de Ingineria
programrii la Facultatea de Automatic i Calculatoare de la Universitatea
Tehnic Gheorghe Asachi din Iai. La acel moment, n unele faculti de
profil din Romnia, aceste laboratoare se concentrau pe programare vizual
Windows, astfel nct n primii ani coninutul s-a axat pe programare
folosind Borland C++ Builder i Microsoft Visual Studio cu Microsoft
Foundation Classes (MFC). Pe lng aspectele de programare vizual, am
prezentat nc de pe atunci chestiuni legate de modularizare, utilizarea
DLL-urilor, crearea aplicaiilor COM, tratarea excepiilor, realizarea de
fiiere de ajutor (help), diagrame UML i evaluarea vitezei de execuie a
programelor.
n anul 2003 am introdus limbajul C# pentru partea de programare a
laboratoarelor, limbaj de care m-am ataat nc de la apariia sa, n 2002, i
pe care am continuat s l utilizez de atunci pentru toate proiectele de
programare de natur profesional sau personal.
Din 2008, odat cu rescrierea cursurilor de Ingineria programrii,
am modificat i laboratoarele, adugnd o parte substanial legat de
proiectarea i testarea aplicaiilor. Astfel, un laborator trateaz abloane
arhitecturale, cinci se refer la abloane de proiectare i dou la testarea
unitilor. Laboratoarele, n forma lor actual, constituie rezultatul
experienei acumulate n timp, ncercnd s ofer o viziune practic asupra
problemelor complexe legate de realizarea produselor software comerciale.
Sunt recunosctor tuturor studenilor pentru semnalarea neclaritilor
i erorilor strecurate n laboratoare. De asemenea, mulumesc studenilor
Veridiana Mrtic, Simona Scripcaru, Liudmila Tofan, Florin Alexandru
Hodorogea i Alexandru Gologan pentru observaiile asupra versiunii
preliminare a acestui ghid.


Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#


8

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com



9

Capitolul 1

Compilarea, decompilarea i
obscurizarea programelor C#

1. Obiective
2. Structura general a unui program C#
3. Compilarea, decompilarea i obscurizarea codului
4. Aplicaii

1. Obiective

Aplicaiile de ingineria programrii nu se doresc a fi, n primul rnd,
aplicaii de programare n C#. Din pcate, programe complexe la standarde
comerciale nu se pot termina n dou ore, deci problemele vor avea o natur
academic surprinznd ns chestiuni ce se pot regsi n aplicaiile din
industrie i care trebuie rezolvate n principal la standarde nalte de calitate.
Accentul principal al prezentului ghid cade pe proiectarea
programelor, folosind de exemplu abloane de proiectare, pe modul cum se
gndete i se scrie un program, pe testare i pe crearea diverselor tipuri de
documente aferente.
Vom utiliza limbajul C# pentru c este un limbaj modern, special
destinat dezvoltrii rapide de aplicaii. Cnd vom considera necesar, vom
prezenta i noiuni de programare n C#, mai ales n primele trei capitole. Ca
mediu de dezvoltare, vom ntrebuina Microsoft Visual Studio 2005.
Obiectivele primului capitol sunt urmtoarele:

1. Prezentarea modului de organizare a unui program C# care conine
clase, structuri i enumeraii. Discutarea diferenelor dintre tipurile
referin (clase) i tipurile valoare (structuri);
2. Precizarea diferenelor de compilare n modurile Debug i Release;
3. Descrierea posibilitilor de decompilare a aplicaiilor .NET i de
protejare a acestora prin obscurizarea codului.




Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#


10
2. Structura general a unui program C#

O soluie C# const dintr-unul sau mai multe proiecte. Proiectele
constau dintr-unul sau mai multe fiiere. Fiierele pot conine zero sau mai
multe spaii de nume (engl. namespaces). Un namespace poate conine
tipuri precum clase, structuri, enumeraii, dar i alte namespace-uri. Mai jos
este prezentat un schelet al unui program C# alctuit din aceste elemente.

using System;

namespace MyNamespace
{
class MyClass
{
}

struct MyStruct
{
}

enum MyEnum
{
}

class MyMainClass
{
static void Main(string[] args)
{
// nceputul programului propriu-zis
}
}
}


2.1. Clase

Clasa este cel mai important tip de date n C#. n urmtorul exemplu,
se definete o clas public avnd un cmp, o metod i un constructor. De
remarcat terminologia utilizat pentru o variabil membru, cmp, deoarece
termenul proprietate reprezint un alt concept C# pe care l vom discuta n
capitolul 2.
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 1. Compilarea, decompilarea i obscurizarea programelor C#


11
n exemplul de mai jos, problema este definirea unui cmp public.
Conform teoriei programrii orientate obiect, toate cmpurile trebuie s fie
private iar accesul la ele s se fac prin metode publice.

public class Person
{
// Cmp / Field
public string name; // !!! cmp public, nerecomandat

// Constructor
public Person()
{
name = "nedefinit";
}

// Metod / Method
public void ChangeName(string newName)
{
name = newName;
}
}

class TestPerson
{
static void Main()
{
Person person1 = new Person();
Console.WriteLine(person1.name);

person1.ChangeName("Ion Popescu");
Console.WriteLine(person1.name);
}
}


2.2. Clase statice i membri statici

O clas static nu poate fi instaniat. Deoarece nu exist instane ale
clasei, apelarea unei metode dintr-o clas static se realizeaz folosind
numele clasei nsei. De exemplu, dac avem o clas static numit
UtilityClass care conine o metod public numit MethodA, aceasta este
apelat n modul urmtor:

UtilityClass.MethodA();
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#


12
O clas static poate fi utilizat ca o modalitate convenabil de a
grupa o serie de metode care opereaz asupra unor parametri de intrare i nu
au nevoie de cmpuri ntruct nu au stare intern. De exemplu, n mediul
.NET, clasa static System.Math conine metode care realizeaz operaii
matematice, fr a avea nevoie s memoreze sau s acceseze alte date n
afara argumentelor cu care sunt apelate.
Mai jos este prezentat un exemplu de clas static avnd dou
metode care convertesc temperatura din grade Celsius n grade Fahrenheit i
viceversa.

public static class TemperatureConverter
{
public static double CelsiusToFahrenheit(string temperatureCelsius)
{
// conversia argumentului din string n double
double celsius = Convert.ToDouble(temperatureCelsius);

// conversia din grade Celsius n grade Fahrenheit
double fahrenheit = (celsius * 9 / 5) + 32;

return fahrenheit;
}

public static double FahrenheitToCelsius(string temperatureFahrenheit)
{
double fahrenheit = Convert.ToDouble(temperatureFahrenheit);
double celsius = (fahrenheit 32) * 5 / 9;
return celsius;
}
}

class TestTemperatureConverter
{
static void Main()
{
Console.WriteLine("Selectati directia de conversie");
Console.WriteLine("1. Din grade Celsius in grade Fahrenheit");
Console.WriteLine("2. Din grade Fahrenheit in grade Celsius");
Console.Write(":");
string selection = Console.ReadLine();
double f, c = 0;



Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 1. Compilarea, decompilarea i obscurizarea programelor C#


13
switch (selection)
{
case "1":
Console.Write("Introduceti temperatura in grade Celsius: ");
f = TemperatureConverter.CelsiusToFahrenheit(Console.ReadLine());
// se afieaz rezultatul cu 2 zecimale
Console.WriteLine("Temperatura in grade Fahrenheit: {0:F2}", f);
break;

case "2":
Console.Write("Introduceti temperatura in grade Fahrenheit: ");
c = TemperatureConverter.FahrenheitToCelsius(Console.ReadLine());
Console.WriteLine("Temperatura in grade Celsius: {0:F2}", c);
break;

default:
Console.WriteLine("Selectati un tip de conversie");
break;
}

// ateapt apsarea tastei ENTER
Console.ReadLine();
}
}

Deseori, se utilizeaz clase nestatice cu membri statici n locul
claselor statice. n acest caz, membrii statici pot fi apelai chiar i naintea
crerii unor instane ale clasei. La fel ca mai sus, membrii statici sunt
accesai cu numele clasei, nu al unei instane. Indiferent cte instane ale
clasei sunt create, pentru un membru static exist ntotdeauna o singur
copie. Metodele statice nu pot accesa metode i cmpuri nestatice din clas.
Cmpurile statice se folosesc n general pentru a stoca valori care
trebuie cunoscute de ctre toate instanele clasei i pentru a pstra evidena
numrului de obiecte care au fost instaniate.


2.3. Cmpuri constante

Un cmp constant este static n comportament (nu poate fi
modificat) i de aceea aparine tot tipului i nu instanelor. Prin urmare va fi
accesat tot cu numele clasei, ca i cmpurile statice.


Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#


14
public class Car
{
public const int NumberOfWheels = 4;
public static void Drive() { }

// alte cmpuri i metode nestatice
}


// utilizare din exteriorul clasei
Car.Drive();
int i = Car.NumberOfWheels;


2.4. Structuri

n C#, structurile sunt versiuni simplificate ale claselor. De obicei,
ele ocup mai puin spaiu n memorie i sunt potrivite pentru tipurile de
date de dimensiuni mici, utilizate frecvent. Diferena cea mai important
ntre structuri i clase este faptul c structurile sunt tipuri valoare iar clasele
sunt tipuri referin.
Cnd se creeaz o instan de tip valoare, se aloc n memoria stiv
un singur spaiu pentru pstrarea valorii instanei respective. n acest mod
sunt tratate tipurile primitive precum int, float, bool, char etc. Compilatorul
creeaz automat un constructor implicit care iniializeaz toate cmpurile cu
valorile implicite ale tipurilor acestora, de exemplu tipurile numerice cu 0,
bool cu false, char cu '\0' iar cmpurile de tip referin (instane ale altor
clase) cu null. Pentru structuri nu se poate declara un constructor implicit
(fr parametri), ns se pot declara constructori cu parametri, care s
iniializeze membrii cu valori diferite de cele implicite. Dezalocarea
instanelor se face automat cnd acestea ies din domeniul lor de definiie.
La alocarea instanelor de tip referin, se memoreaz att referina
obiectului n stiv, ct i spaiul pentru coninutul obiectului n heap.
Managementul memoriei este fcut de ctre garbage collector.
S considerm urmtoarea situaie: structura MyPoint i clasa
MyForm.

MyPoint p1; // p1 este alocat cu valorile implicite ale membrilor
p1 = new MyPoint(); // nu are efect aici, reseteaz valorile membrilor
MyForm f1; // se aloc referina, f1 = null
f1 = new MyForm(); // se aloc obiectul, f1 primete referina acestuia
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 1. Compilarea, decompilarea i obscurizarea programelor C#


15
n primul caz, se aloc un singur spaiu n memorie pentru p1. n al
doilea caz, se aloc dou spaii: unul pentru obiectul MyForm i unul pentru
referina lui, f1. De aceea, dac vrem s declarm un vector de 1000 de
puncte, este mai avantajos s crem o structur dect o clas, deoarece astfel
vom aloca mai puin memorie.
Dac vrem s copiem obiectele:

MyPoint p2 = p1;
MyForm f2 = f1;

p2 devine o copie independent a lui p1, fiecare cu cmpurile lui separate.
n cazul lui f2, se copiaz numai referina, astfel nct f1 i f2 pointeaz
ctre acelai obiect.
Fie metoda urmtoare, apelat cu argumentele p1 i f1:
Change(p1, f1):

void Change(MyPoint p, MyForm f)
{
p.X = 10; // p este o copie, instruciunea nu are efect asupra lui p1
f.Text = "Hello"; // f i f1 pointeaz la acelai obiect, f1.Text se schimb
f = null; // f este o copie a referinei f1, instruciunea nu are efect asupra lui f1
}

Pentru o compatibilitate ct mai bun cu mediul .NET, Biblioteca
MSDN recomand utilizarea structurilor numai n urmtoarele situaii:

Tipul reprezint o valoare unitar, similar cu un tip primitiv
(int, double etc.);
Dimensiunea unei instane este mai mic de 16 octei (deoarece la
transmiterea ca parametru n metode se creeaz o nou copie pe
stiv);
Tipul este immutable (metodele nu modific valorile cmpurilor;
cnd se dorete schimbarea acestora se creeaz un nou obiect cu
noile valori);
Operaiile de boxing (mpachetare) i unboxing (despachetare),
prezentate n seciunea 2.6, sunt rare.




Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#


16
2.5. Trimiterea argumentelor prin referin

Trimiterea argumentelor prin referin se realizeaz cu ajutorul
cuvintelor cheie ref i out. Astfel, modificrile fcute asupra parametrului n
metoda apelat se vor reflecta asupra variabilei din metoda apelant. Un
argument trimis ca ref trebuie iniializat mai nti. Un argument trimis cu
out nu trebuie iniializat n metoda apelant, ns metoda apelat este
obligat s i atribuie o valoare.

class RefExample
{
static void Method(ref int i)
{
i = 44;
}
static void Main()
{
int val = 0;
Method(ref val);
// val este acum 44
}
}
class OutExample
{
static void Method(out int i)
{
i = 44;
}
static void Main()
{
int val;
Method(out val);
// val este acum 44
}
}

Revenind la exemplul cu structura MyPoint i clasa MyForm, fie
metoda urmtoare, apelat cu argumentele p1 i f1: Change(ref p1, ref f1):

void Change(ref MyPoint p, ref MyForm f)
{
p.X = 10; // se modific p1.X
f.Text = "Hello"; // se modific f1.Text
f = null; // f1 este distrus
}


2.6. Operaiile de boxing i unboxing

Aceste operaii permit ca tipurile valoare s fie tratate drept tipuri
referin, dup cum se poate vedea n figura 1.1.




Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 1. Compilarea, decompilarea i obscurizarea programelor C#


17
Boxing (mpachetare)

int i = 123; // tip valoare
object o = i; // tip referin (boxing)
Unboxing (despachetare)

int i = 123;
object o = i;
int j = (int)o; // tip valoare (unboxing)


Figura 1.1. Operaiile de boxing i unboxing

Vom utiliza aceste operaii n capitolul 3.


2.7. Enumeraii

O enumeraie este alctuit dintr-o mulime de constante.
Enumeraiile pot avea orice tip integral cu excepia lui char, tipul implicit
fiind int. Valoarea implicit a primului element este 0, iar valorile succesive
sunt incrementate cu 1. De exemplu:

enum Days { Sun, Mon, Tue, Wed, Thu, Fri, Sat };

n aceast enumeraie, Sun este 0, Mon este 1, Tue este 2 i aa mai
departe. Enumeratorii pot avea iniializatori care suprascriu valorile
implicite. De exemplu:

enum Zile { Lun = 1, Mar, Mie, Joi, Vin, Sam, Dum };

Aici secvena de elemente pornete de la 1 n loc de 0.
Urmtoarele instruciuni sunt valide:


Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#


18
int x = (int)Zile.Lun; // x = 1
Zile z1 = Zile.Mar; // z1 = Mar
Zile z2 = (Zile)3; // z2 = Mie
string s = z2.ToString(); // s = "Mie"

Modificarea valorilor unei enumeraii ntr-o nou versiune a unui
program poate cauza probleme pentru alte programe ce folosesc codul
respectiv. De multe ori valorile din enum sunt utilizate n instruciuni
switch, iar dac noi elemente sunt adugate enumeraiei, se va activa cazul
default. Dac ali dezvoltatori depind de acel cod, ei trebuie s tie cum s
trateze noile elemente adugate.


3. Compilarea, decompilarea i obscurizarea
codului

3.1. Compilarea. Limbajul Intermediar Comun

Limbajul Intermediar Comun (engl. Common Intermediate
Language, CIL), cunoscut i sub denumirea de Limbajul Intermediar
Microsoft (engl. Microsoft Intermediate Language, MSIL) este limbajul
de nivelul cel mai sczut al platformei .NET. MSIL a fost numele utilizat
pentru limbajul intermediar pn la versiunea 1.1 a platformei .NET.
ncepnd cu versiunea 2.0, limbajul a fost standardizat iar denumirea
standardului este CIL.
Compilarea i execuia unui program .NET se realizeaz n dou
etape, dup cum se prezint n figura 1.2.


Figura 1.2. Etapele compilrii i execuiei unui program .NET
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 1. Compilarea, decompilarea i obscurizarea programelor C#


19
n timpul compilrii limbajelor .NET, codul surs este transformat n
cod CIL i nu direct n cod executabil de ctre procesor. CIL reprezint un
set de instruciuni independent de sistemul de operare i de procesor, care
poate fi executat n orice mediu pe care este instalat platforma .NET, de
exemplu motorul de execuie (runtime-ul) .NET pentru Windows, sau Mono
pentru Linux.
Compilarea la timp (engl. just-in-time compilation, JIT) are loc
n momentul execuiei efective a programului i presupune transformarea
codului CIL n instruciuni executabile imediat de ctre procesor. Conversia
se realizeaz gradat n timpul execuiei programului, iar compilatorul JIT
efectueaz o serie de optimizri specifice mediului de execuie.
Avantajul principal al platformei .NET este interoperabilitatea dintre
diferite limbaje de programare. De exemplu, un proiect scris n Visual Basic
poate fi apelat fr modificri dintr-un proiect C#.


3.2. Decompilarea. Programul .NET Reflector

Deoarece codul intermediar este standardizat, este relativ simpl
transformarea invers, ntr-un limbaj de nivel nalt precum C#. Un astfel de
decompilator este .NET Reflector, pe care MSDN Magazine l-a numit unul
din utilitarele obligatorii pentru un dezvoltator .NET. Programul este folosit
deseori de ctre programatori pentru a nelege structura intern a
bibliotecilor .NET pentru care codul surs nu este disponibil. S considerm
urmtorul program simplu:

public class Program
{
static void Main(string[] args)
{
string[] s = new string[] { "Hello, ", "World!" };
for (int i = 0; i < s.Length; i++)
Console.Write(s[i]);
Console.WriteLine(Environment.NewLine + "ok"); // NewLine pentru Windows este "\r\n"
}
}

Dup compilare, assembly-ul rezultat (n acest caz fiierul exe) se
deschide n .NET Reflector. Programul permite navigarea prin
namespace-uri, clase i metode. Cu click-dreapta se deschide un meniu din
care se poate selecta opiunea de decompilare (engl. disassemble), ca n
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#


20
figura 1.3. Din combo-box-ul din bara de instrumente se alege limbajul n
care s se realizeze decompilarea.


Figura 1.3. Programul .NET Reflector

Iat rezultatele decompilrilor n mai multe limbaje:

C#




Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 1. Compilarea, decompilarea i obscurizarea programelor C#


21
Visual Basic




Managed C++




Delphi











Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#


22
CIL






Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 1. Compilarea, decompilarea i obscurizarea programelor C#


23
3.3. Compilarea n modurile Debug i Release

Dei majoritatea optimizrilor se realizeaz n momentul compilrii
JIT, chiar i compilatorul C# poate efectua analize ale codului i unele
simplificri n vederea creterii vitezei de execuie. Compilarea n mod
Debug este destinat facilitrii procesului de descoperire a erorilor i de
aceea codul generat urmeaz mai fidel structura codului surs. n modul
Debug, compilatorul JIT genereaz un cod mai uor de depanat, ns mai
lent.
n schimb, compilarea n mod Release poate introduce optimizri
suplimentare. Aceste opiuni pot fi controlate din mediul Visual Studio,
astfel: View Solution Explorer Project Properties Build. n modul
Release, opiunea Optimize code este activat.
De asemenea, n View Solution Explorer Project Properties
Build Advanced Output, se precizeaz crearea sau nu a unui fiier pdb
(program database) care conine informaii ce fac legtura ntre codul CIL
generat i codul surs iniial, utile n special n faza de Debug.
n continuare, vor fi prezentate unele diferene de compilare n mod
Debug (prima imagine, de sus), respectiv Release (a doua imagine, de jos).

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#


24
a) Declararea variabilelor n locul n care sunt utilizate.





Interesant este faptul c aceste optimizri nu apar ntotdeauna. De
exemplu, o metod simpl cum ar fi urmtoarea nu va fi optimizat, dei
principiul este acelai ca mai sus.

public void Locals()
{
int i;
for (i = 0; i < 3; i++)
DoSomething();
for (i = 2; i < 5; i++)
DoSomething();
}



Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 1. Compilarea, decompilarea i obscurizarea programelor C#


25
b) Transformarea buclelor while n bucle for









Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#


26
c) Eliminarea iniializrilor cu null






d) Eliminarea variabilelor neutilizate






Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 1. Compilarea, decompilarea i obscurizarea programelor C#


27
e) Optimizarea iniializrilor n constructor





Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#


28
f) Optimizarea blocurilor switch





Prin urmare, programatorul nu trebuie s fac optimizri, mai ales
cnd acestea scad claritatea codului. Singurele optimizri recomandate sunt
acelea care scad complexitatea unui algoritm cu cel puin o clas, de
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 1. Compilarea, decompilarea i obscurizarea programelor C#


29
exemplu de la O(n
2
) la O(log n) sau O(n). n rest, compilatorul face oricum
transformri ale codului, adaptate mediului de execuie existent. Eventualele
optimizri manuale pot conduce n cel mai ru caz la secvene nestandard
care nu sunt recunoscute de compilator i care pot scdea de fapt
performanele aplicaiei.
Codul pregtit pentru livrarea comercial trebuie ntotdeauna
compilat n modul Release.


3.4. Obscurizarea codului. Dotfuscator

Codul obscurizat (engl. obfuscated) este un cod foarte greu de citit
i de neles. Deoarece prin decompilare orice program .NET devine de fapt
open-source, obscurizarea este una din modalitile prin care se poate pstra
secretul asupra codului aplicaiilor realizate.
Visual Studio include un astfel de instrument, numit Dotfuscator
Community Edition care are o serie de limitri fa de versiunea
Professional. Printre cele mai importante sunt criptarea irurilor de
caractere, comprimarea assembly-urilor obscurizate i diferite scheme de
redenumire. Nu este un instrument infailibil, ns este util pentru aplicaiile
de importan medie.
Dotfuscator Community Edition poate fi pornit din mediul Visual
Studio din meniul: Tools Dotfuscator Community Edition.
Mai nti se ncarc assembly-ul dorit, iar din tab-ul Rename se pot
selecta namespace-urile, tipurile i metodele care se doresc redenumite,
implicit toate. Apoi se ruleaz proiectul apsnd butonul Build (figura 1.4).


Figura 1.4. Instrumentul Dotfuscator

Rezultatul va fi un nou assembly, cu numele interne schimbate.
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#


30
S considerm urmtorul exemplu. n stnga este programul iniial
iar n dreapta codul dezasamblat dup obscurizare.

public class AddingNumbers
{
public int AddTwo(int a, int b)
{
return a + b;
}

public int AddThree(int a, int b, int c)
{
return a + b + c;
}
}

class Program
{
static void Main(string[] args)
{
int x = 1, y = 2, z = 3;
AddingNumbers an =
new AddingNumbers();
int r1 = an.AddTwo(x, y);
Console.WriteLine(r1);
int r2 = an.AddThree(x, y, z);
Console.WriteLine(r2);
}
}
public class a
{
public int a(int A_0, int A_1)
{
return (A_0 + A_1);
}

public int a(int A_0, int A_1, int A_2)
{
return ((A_0 + A_1) + A_2);
}
}

class b
{
private static void a(string[] A_0)
{
int num = 1;
int num2 = 2;
int num3 = 3;
a a = new a();
Console.WriteLine(a.a(num, num2));
Console.WriteLine(
a.a(num, num2, num3));
}
}


4. Aplicaii

4.1. Realizai un program de tip consol n care s creai cte o
metod pentru fiecare din situaiile de mai jos. Compilai programul n mod
Debug cu Debug Info full, respectiv Release cu Debug Info none.

Variabile locale nefolosite:

int a = 4;
int b = 3;
double c = 4;
bool ok = false;
Console.WriteLine(ok);
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 1. Compilarea, decompilarea i obscurizarea programelor C#


31
Ramuri ale expresiilor condiionale:

int b = 3;
double c = 4;
bool ok = false;

if (b < 3)
if (c > 3)
ok = true;

Console.WriteLine(ok);

Cod imposibil de atins:

if (true)
Console.WriteLine("ok");
if (false)
Console.WriteLine("false");
else
Console.WriteLine("true");
return;
Console.WriteLine("finished");

Expresii aritmetice:

int a = 2 + 4 + 5;
double b = 9 / 5.0 + a + 9 + 5;
b++;

Instruciuni goto (nerecomandate, deoarece afecteaz calitatea
structurii codului):

int b = 10;
if (b < 20)
{
Console.WriteLine("true");
}
else
{
goto After;
}
After:
Console.WriteLine("goto");

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#


32
bool a = (b < 4);

if (a)
{
goto C;
}
Console.WriteLine(1);
C:
Console.WriteLine(2);


Apelarea metodelor din obiecte (pentru aceasta creai o clas Test cu
o metod MyMethod):

Test t = new Test();
int a = t.MyMethod();
Console.WriteLine(a);


De observat decompilarea urmtoarei secvene n mod Release: ce
elemente i pstreaz numele chiar n absena fiierului pdb? Care
sunt numele implicite date de .NET Reflector pentru diferite tipuri de
date?

int integer = 3;
double real = 3.14;
bool boolean = true;

Console.WriteLine("Integer: " + integer);
Console.WriteLine("Real: " + real);
Console.WriteLine("Boolean: " + boolean);

NumberForTestingOnly t = new NumberForTestingOnly();
Console.WriteLine("Test object: " + t.ReturnDouble(4));

public class NumberForTestingOnly
{
public int ReturnDouble(int par)
{
return par * 2;
}
}
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 1. Compilarea, decompilarea i obscurizarea programelor C#


33
Not: dei de multe ori termenii argument i parametru se
folosesc ca sinonime, exist o diferen ntre aceste noiuni. n exemplul
anterior:

ReturnDouble(int par) par este parametru;
t.ReturnDouble(4) 4 este argument.


4.2. Creai un program cu 3 clase, fiecare clas cu 4 metode i
obscurizai-l utiliznd instrumentul Dotfuscator. Pentru a vedea rezultate
interesante, cteva metode din aceeai clas trebuie s aib aceeai
semntur cu excepia numelui, iar celelalte s aib semnturi diferite.
Instaniai obiecte de aceste tipuri i apelai metodele corespunztoare.


Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#


34

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com


35

Capitolul 2

Stilul de scriere a codului. Tratarea
excepiilor. Interfaa grafic cu utilizatorul

1. Obiective
2. Stilul de scriere a codului
3. Tratarea excepiilor
4. Interfaa cu utilizatorul
5. Interfaa grafic cu utilizatorul n Microsoft Visual Studio .NET
6. Elemente de C#
7. Aplicaii

1. Obiective

Obiectivele capitolului 2 sunt urmtoarele:

Sublinierea importanei unui stil unitar de scriere a codului ntr-o
firm care dezvolt produse software;
Descrierea standardului de scriere a codului pe care l vom utiliza n
ghidul de aplicaii de ingineria programrii;
Explicarea modalitilor de tratare a excepiilor n C#;
Prezentarea unor aspecte legate de dezvoltarea de aplicaii cu
interfa grafic;
Prezentarea modului de lucru cu proprieti C#.


2. Stilul de scriere a codului

Unul din scopurile urmrite la scrierea programelor trebuie s fie
ntreinerea ulterioar a codului, adic facilitarea modificrilor i
completrilor viitoare, foarte probabil de ctre persoane diferite dect
autorul iniial. De asemenea, unele studii au artat c dup 6 luni de la
scrierea unui program, acesta i apare la fel de strin autorului ca i un
program scris de altcineva.
Unul din aspectele principale ale codului uor de ntreinut este
posibilitatea de a gsi anumite buci de cod i de a le modifica fr a afecta
celelalte seciuni. Claritatea este esenial. Altfel, n cazul programelor de
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

36
mari dimensiuni, aa cum sunt majoritatea situaiilor n cazul produselor
software comerciale, n locul lucrului efectiv pentru adugarea de
funcionaliti se va pierde timpul ncercndu-se s se gseasc poriunile
relevante de cod care trebuie modificate.
Formatarea codului poate simplifica nelegerea structurii semantice
sau poate cauza confuzie. Poate chiar ascunde defecte greu de depistat, de
exemplu:

bool error = DoSomething();
if (error)
Console.WriteLine("Eroare");
Environment.Exit(1); /// !!!

Nu conteaz ct de bine este proiectat un program; dac prezentarea
sa arat neglijent, va fi neplcut de lucrat cu el.


2.1. Acoladele

Exist dou modaliti principale de plasare a acoladelor.
Stilul Kernighan i Ritchie este bazat pe dorina de a afia ct mai
multe informaii ntr-un mod compact:

int KernighanRitchie() {
int a = 0, b = 0;
while (a != 10) {
a++;
b--;
}
return b;
}

Acest stil poate fi folosit la prezentri de cod sau n situaii n care
spaiul disponibil pentru afiarea codului este redus, de exemplu ntr-un
material tiprit.
Stilul extins sau stilul Allman este recomandat de Microsoft pentru
limbajul C#:




Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 2. Stilul de scriere a codului. Tratarea excepiilor. Interfaa grafic cu utilizatorul


37
int Extended()
{
int a = 0, b = 0;
while (a != 10)
{
a++;
b--;
}
return b;
}

Avantajul principal al acestuia este claritatea, deoarece blocurile de
cod sunt evideniate prin alinierea acoladelor. Este stilul pe care l vom
utiliza n acest ghid de aplicaii.


2.2. Standarde de programare

Muli programatori fr experien industrial, dei foarte buni,
refuz la nceput aplicarea unor standarde impuse. Dac programul este
corect, ei nu neleg de ce trebuie aliniat altfel sau de ce trebuie schimbate
numele variabilelor sau metodelor.
Este important de avut n vedere faptul c nu exist un stil perfect,
deci rzboaiele privind cea mai bun formatare nu pot fi ctigate. Toate
stilurile au argumente pro i contra. Majoritatea firmelor serioase de
software au standarde interne de scriere a programelor, care definesc
regulile pentru prezentarea codului. Aceste standarde cresc calitatea
programelor i sunt importante deoarece toate proiectele livrate n afara
organizaiei vor avea un aspect ngrijit i coerent, de parc ar fi fost scrise de
aceeai persoan. Existena mai multor stiluri distincte ntr-un proiect indic
lipsa de profesionalism.
Faptul c un programator crede c stilul su propriu este cel mai
frumos i cel mai uor de neles nu are nicio importan. Un stil care unui
programator i pare n mod evident cel mai bun poate reprezenta o problem
pentru altul. De exemplu:

using System . Windows . Forms;
namespace LabIP {
public class HelloWorld:System . Windows . Forms . Form {
public HelloWorld ( ) {
InitializeComponent ( );
}

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

38
protected override void Dispose ( bool disposing ) {
if( disposing ) {
if( components != null ) {
components . Dispose ( );
}
}
base . Dispose ( disposing );
}
static void Main ( ) {
Application . Run ( new HelloWorld ( ) );
}
private void button1_Click ( object sender , System . EventArgs e ) {
string STRING = "Hello World!";
display ( STRING );
}
private void display ( string STR ) {
MessageBox . Show ( STR , ":-)" );
}
}
}

Acest program nu a fost aliniat aleatoriu, ci folosind opiunile din
mediul Visual Studio: Tools Options Text Editor C# Formatting.
n acelai mod, stilul personal al unui programator poate prea la fel de
ciudat altuia.
Beneficiile adoptrii unui stil unitar de ctre toi membrii unei
organizaii depesc dificultile iniiale ale adaptrii la un stil nou. Chiar
dac nu este de acord cu standardul impus, un programator profesionist
trebuie s se conformeze. Dup ce va folosi un timp stilul firmei, se va
obinui cu el i i se va prea perfect natural.
n prezentul ghid de aplicaii vom utiliza un standard bazat pe
recomandrile Microsoft pentru scrierea programelor C#.
Este bine ca regiunile de program s fie delimitate cu ajutorul
cuvntului cheie region, de exemplu:

#region Fields
private DateOfBirth _dob;
private Address _address;
#endregion

Dac toate seciunile unei clase sunt delimitate pe regiuni, pagina ar
trebui s arate n felul urmtor atunci cnd toate definiiile sunt colapsate:

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 2. Stilul de scriere a codului. Tratarea excepiilor. Interfaa grafic cu utilizatorul


39



2.3. Convenii pentru nume

Cheia alegerii unor nume potrivite este nelegerea rolului
construciilor respective. De exemplu, dac nu putem gsi un nume bun
pentru o clas sau pentru o metod, ar fi util s ne ntrebm dac tim
ntr-adevr la ce folosete aceasta sau dac chiar este necesar s existe n
program. Dificultile la alegerea unui nume potrivit pot indica probleme de
proiectare.
Un nume trebuie s fie:

Descriptiv: Oamenii i pstreaz deseori percepiile iniiale asupra
unui concept. Este important deci crearea unei impresii iniiale
corecte despre datele sau funcionalitile unui program prin alegerea
unor termeni care s descrie exact semnificaia i rolul acestora.
Numele trebuie alese din perspectiva unui cititor fr cunotine
anterioare, nu din perspectiva programatorului;
Adecvat: Pentru a da nume clare, trebuie s folosim cuvinte din
limbajul natural. Programatorii au tendina s utilizeze abrevieri i
prescurtri, ns acest lucru conduce la denumiri confuze. Nu are
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

40
importan faptul c un identificator este lung ct vreme este lipsit
de ambiguitate. Denumirea st nu este o alegere potrivit pentru
conceptul numarStudenti. Regula de urmat este: trebuie preferat
claritatea fa de laconism. Excepiile sunt contoarele de bucle, de
exemplu clasicul for (int i = 0; i < length; i++). Acestea de multe ori
nu au o semnificaie de sine stttoare, sunt construcii specifice
(idiomuri) ale limbajelor evoluate din C i de obicei se noteaz cu o
singur liter: i, j, k etc.;
Coerent: Regulile de numire trebuie respectate n tot proiectul i
trebuie s se conformeze standardelor firmei. O clas precum cea de
mai jos nu prezint nicio garanie de calitate:

class badly_named : MyBaseClass
{
public void doTheFirstThing();
public void DoThe2ndThing();
public void do_the_third_thing();
}

Pentru descrierea tipurilor de nume, exist n englez o serie de
termeni care nu au un echivalent exact n limba romn:

Pascal case: Primul caracter al tuturor cuvintelor este o majuscul
iar celelalte caractere sunt minuscule, de exemplu: NumarStudenti;
Camel case: Pascal case cu excepia primului cuvnt, care ncepe cu
liter mic, de exemplu: numarStudenti.

Pentru denumirea conceptelor dintr-un program C#, vom adopta
conveniile din tabelul 2.1.

Tabelul 2.1. Convenii pentru denumirea conceptelor dintr-un program C#
Concept Convenie Exemple
Namespace-uri Pascal case namespace LaboratorIP
Clase Pascal case class HelloWorld
Interfee
Pascal case
precedat de I
interface IEntity
Metode Pascal case void SayHello()
Variabile locale Camel case int totalCount = 0;
Variabile booleene Prefixate cu is bool isModified;
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 2. Stilul de scriere a codului. Tratarea excepiilor. Interfaa grafic cu utilizatorul


41
Concept Convenie Exemple
Parametrii
metodelor
Camel case void SayHello(string name)
Cmpuri private
1

Camel case precedat
de underscore
string _address;
Proprieti
2
Pascal case Address
Constante, cmpuri
readonly publice
3

Pascal case const int MaxSpeed = 100;
Controale pentru
interfaa grafic
4

Camel case precedat
de tipul controlului
buttonOK
checkBoxTrigonometric
comboBoxFunction
Excepii
Pascal case cu
terminaia Exception
MyException
PolynomialException

1
Pn la versiunea Visual Studio 6.0, programatorii utilizau n C++ notaia
maghiar a lui Simonyi pentru variabile, care indica i tipul acestora, de exemplu
nAge pentru int. Pentru variabilele membru se folosea prefixul m_, de exemplu
m_nAge. Pentru limbajul C#, Microsoft nu mai recomand utilizarea acestor
notaii. Pentru cmpurile private exist cteva avantaje la prefixarea cu underscore:

cmpurile clasei vor avea o notaie diferit de variabilele locale;
cmpurile clasei vor avea o notaie diferit de parametrii metodelor, astfel
nct se vor evita situaiile de iniializare de genul this.x = x, unde this.x
este cmpul iar x este parametrul metodei;
n IntelliSense, la apsarea tastei _ vor aprea grupate toate cmpurile.

Avantajul utilizrii acestei convenii se manifest mai ales n situaii
precum aceea de mai jos:

private int description; // ortografie corect

public Constructor(int descripton) // ortografie incorect pentru "description"
{
this.description = description; // ortografie corect n ambele pri, cmpul rmne 0
}

2
Proprietile vor fi detaliate n seciunea 6.2.

3
n mare, tot ce e public ntr-o clas trebuie s nceap cu liter mare

4
Aceast notaie are avantajul c, dei numele sunt mai lungi, sunt lipsite de
ambiguitate. Exist i stilul prefixrii cu o abreviere de 3 litere, de exemplu btn
pentru Button, ckb pentru CheckBox etc. Pentru controale mai puin uzuale,
semnificaiile prefixelor nu mai sunt evidente: pbx, rdo, rbl etc.
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

42
3. Tratarea excepiilor

Tratarea erorilor se fcea n C prin returnarea unei valori, de obicei
int, care semnifica un cod de eroare. De exemplu, dac o funcie trebuia s
deschid un fiier, ea putea ntoarce 0 dac totul a funcionat normal,
respectiv codul de eroare 1 dac fiierul nu exista. n funcia apelant,
programatorul trebuia s trateze codul returnat:

int err = OpenFile(s);

Cu toate acestea, programatorul era liber s apeleze funcia direct,
OpenFile(s), fr a mai testa valoarea returnat. Programul putea fi testat cu
succes, deoarece fiierul exista, ns putea s nu mai funcioneze dup
livrare.
Majoritatea funciilor Windows API returneaz un cod dintr-o list
cu sute de valori posibile, ns puini programatori testeaz aceste valori
individual.
Tratarea excepiilor a aprut pentru a da posibilitatea programelor s
surprind i s trateze erorile ntr-o manier elegant i centralizat,
permind separarea codului de tratare a erorilor de codul principal al
programului, ceea ce face codul mai lizibil. Astfel, este posibil tratarea:

tuturor tipurilor de excepii;
tuturor excepiilor de un anume tip;
tuturor excepiilor de tipuri nrudite.

Odat ce o excepie este generat, ea nu poate fi ignorat de sistem.
Funcia care detecteaz eroarea poate s nu fie capabil s o trateze i atunci
se spune c arunc (throw) o excepie. Totui, nu putem fi siguri c exist
un caz de tratare pentru orice excepie. Dac exist o rutin potrivit,
excepia este tratat, dac nu, programul se termin. Rutinele de tratare a
excepiilor pot fi scrise n diverse feluri, de exemplu examineaz excepia i
apoi nchid programul sau re-arunc excepia.
Structura blocurilor try-catch pentru tratarea excepiilor este
urmtoarea:





Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 2. Stilul de scriere a codului. Tratarea excepiilor. Interfaa grafic cu utilizatorul


43
FuncieApelat
{
...
if (condiii)
throw ...
...
}

FuncieApelant
{
...
try
{
FuncieApelat();
}
catch (Exception e) // catch fr parametru dac nu intereseaz detaliile excepiei
{
// cod pentru tratarea excepiei, care prelucreaz parametrul e
}
...
}

Codul care ar putea genera o excepie se introduce n blocul try.
Excepia este aruncat (throw) din funcia care a fost apelat, direct sau
indirect. Excepiile care apar n blocul try sunt captate n mod normal de
blocul catch care urmeaz imediat dup acesta. Un bloc try poate fi urmat
de unul sau mai multe blocuri catch. Dac se execut codul dintr-un bloc try
i nu se arunc nicio excepie, toate rutinele de tratare sunt ignorate, iar
execuia programului continu cu prima instruciune de dup blocul (sau
blocurile) catch.
n C#, tipul trimis ca parametru este de obicei Exception:

try
{
FunctieApelata();
}
catch (Exception ex)
{
...
}

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

44
De cele mai multe ori, ne intereseaz proprietatea Message (de tip
string) a unui astfel de obiect, care arat cauza erorii. Textul respectiv este
precizat n funcia care arunc excepia.

private void FunctieApelata(int a)
{
if (a == 0)
throw new Exception("Argument zero");
}

private void FunctieApelanta()
{
FunctieApelata(0);
}

Dac excepia nu este tratat, va aprea un mesaj de atenionare cu
textul dorit (figura 2.1).


Figura 2.1. Mesaj de excepie

Mesajul de eroare trebuie preluat n program n blocul catch:

private void FunctieApelanta()
{
try
{
FunctieApelata(0);
}
catch (Exception ex)
{
// ex.Message este "Argument zero"
}
}

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 2. Stilul de scriere a codului. Tratarea excepiilor. Interfaa grafic cu utilizatorul


45
Programatorul i poate defini propriile tipuri de excepii, n cazul n
care are nevoie s trimit informaii suplimentare privind excepia. Acestea
trebuie ns derivate din clasa Exception:

public class MyException: Exception
{
public int _info; // informaie suplimentar

// n constructor se apeleaz i constructorul clasei de baz
public MyException(int val) : base()
{
_info = val;
}
}

Utilizarea acestui tip se face astfel:

throw new MyException(3);

Dup un try pot exista mai multe blocuri catch. Ele trebuie dispuse
n ordinea invers a derivrii tipurilor, de la particular la general:

try
{
FunctieApelata(x);
}
catch (MyException myex)
{
...
}
catch (Exception ex)
{
...
}

Alt ordine nu este permis, eroarea fiind descoperit la compilare:
A previous catch clause already catches all exceptions of this or a super
type ('System.Exception').





Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

46
3.1. Tratarea excepiilor pe firul de execuie al
aplicaiei

Uneori pentru a fi siguri c nu am lsat vreo excepie netratat,
putem trata global toate excepiile aprute pe firele de execuie ale aplicaiei,
n maniera descris n continuare:

static class Program
{
static void Main()
{
// Adugarea unui event handler pentru prinderea excepiilor
// din firul principal al interfeei cu utilizatorul
Application.ThreadException +=
new ThreadExceptionEventHandler(OnThreadException);

// Adugarea unui event handler pentru toate firele de execuie din appdomain
// cu excepia firului principal al interfeei cu utilizatorul
AppDomain.CurrentDomain.UnhandledException +=
new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MyForm()); // MyForm este fereastra principal a programului
}

// Trateaz excepiile din firul principal al interfeei cu utilizatorul
static void OnThreadException(object sender, ThreadExceptionEventArgs t)
{
// Afieaz detaliile excepiei
MessageBox.Show(t.Exception.ToString(), "OnThreadException");
}

// Trateaz excepiile din toate celelalte fire de execuie
static void CurrentDomain_UnhandledException(object sender,
UnhandledExceptionEventArgs e)
{
// Afieaz detaliile excepiei
MessageBox.Show(e.ExceptionObject.ToString(), "CurrentDomain_UnhandledException");
}
}



Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 2. Stilul de scriere a codului. Tratarea excepiilor. Interfaa grafic cu utilizatorul


47
4. Interfaa cu utilizatorul

Interfaa cu utilizatorul permite acestuia s interacioneze cu
aplicaia. Exist dou tipuri principale de interfee:

interfa cu utilizatorul de tip caracter (engl. character user
interface, CUI);
interfa cu utilizatorul de tip grafic (engl. graphical user interface,
GUI).

Un exemplu de interfa de tip caracter este interfaa la linia de
comand a sistemului de operare MS-DOS. Cnd se folosete o astfel de
interfa, n general utilizatorul trebuie s memoreze i s tasteze comenzi
text. De aceea, interfeele de acest tip pot fi mai dificil de utilizat i necesit
o oarecare pregtire a utilizatorului. O interfa grafic ncearc s
simplifice comunicarea. Graficele reprezint obiecte pe care utilizatorul le
poate manipula i asupra crora poate efectua aciuni. Deoarece utilizatorul
nu trebuie s tie un limbaj de comand, o interfa grafic bine proiectat
este mai uor de folosit dect o interfa de tip caracter.


4.1. Proiectarea comenzilor i interaciunilor

Dac ierarhia de comenzi trebuie s se integreze ntr-un sistem de
interaciuni deja existent, trebuie mai nti studiat acesta.
Se stabilete o ierarhie iniial de comenzi care poate fi prezentat
utilizatorilor n mai multe moduri: o serie de opiuni dintr-un meniu, o bar
de instrumente (toolbar) sau o serie de imagini (icons).
Apoi, aceast ierarhie se rafineaz prin ordonarea serviciilor din
fiecare ramur a ierarhiei n ordinea logic n care trebuie s se execute, cele
mai frecvente servicii aparrnd primele n list.
Limea i adncimea ierarhiei trebuie proiectate n aa fel nct s
se evite suprancarea memoriei de scurt durat a utilizatorului. De
asemenea, trebuie minimizat numrul de pai sau de aciuni (apsri ale
mouse-ului, combinaii de taste) pe care trebuie s le efectueze acesta pentru
a-i ndeplini scopul.
Interaciunile cu factorul uman pot fi proiectate pe baza urmtoarelor
criterii:

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

48
coerena: se recomand utilizarea unor termeni i aciuni cu
semnificaii unice, bine precizate i care se regsesc n mod unitar n
tot sistemul;
numrul mic de pai: trebuie s se minimizeze numrul de aciuni pe
care trebuie s le ndeplineasc utilizatorul;
evitarea aerului mort (engl. dead air): utilizatorul nu trebuie
lsat singur, fr niciun semnal, atunci cnd ateapt ca sistemul s
execute o aciune. El trebuie s tie c sistemul execut o aciune i
ct din aciunea respectiv s-a realizat;
operaiile de anulare (engl. undo): se recomand furnizarea
acestui serviciu datorit erorilor inerente ale utilizatorilor;
timpul scurt i efortul redus de nvare: de multe ori, utilizatorii nu
citesc documentaia, de aceea se recomand furnizarea n timpul
execuiei a unor soluii pentru problemele aprute;
aspectul estetic al interfeei: oamenii utilizeaz mai uor un produs
software cu un aspect plcut.

Se recomand folosirea de icoane i controale similare celor din
produsele software cu care utilizatorul este familiarizat. Dac are de-a face
cu acelai aspect exterior, acesta i va folosi cunotinele anterioare pentru
navigarea prin opiunile programului, ceea ce va reduce i mai mult timpul
de instruire.


4.2. Considerente practice

Elementele interfeei grafice trebuie s fie coerente, adic s aib
stiluri, culori i semnificaii similare n toat aplicaia. Un tabel centralizat
de cuvinte cheie poate ajuta la alegerea textelor sau etichetelor de ctre
proiectanii interfeei care lucreaz la acelai sistem. Aceast tabel conine lista
de cuvinte folosite n toat interfaa i care nseamn aceeai lucru peste tot.
O interfa clar este uor de neles. Metaforele utilizate trebuie s
fie n acord cu experiena utilizatorilor n legtur cu obiectele din lumea
real pe care le reprezint. De exemplu, icoana unui co de gunoi poate
reprezenta o funcie de gestionare a fiierelor nedorite (gen Recycle Bin):
fiierele pot fi introduse n co, unde rmn i pot fi regsite pn cnd coul
este golit.
Erorile trebuie identificate imediat folosind un mesaj inofensiv.
Utilizatorul trebuie s-i poat repara o greeal ori de cte ori este posibil
acest lucru iar documentaia programului sau manualul de utilizare trebuie
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 2. Stilul de scriere a codului. Tratarea excepiilor. Interfaa grafic cu utilizatorul


49
s l ajute n acest sens. Mesajele critice trebuie folosite numai atunci cnd
utilizatorul trebuie avertizat c unele date pot fi pierdute sau deteriorate dac
nu acioneaz imediat.
Chiar dac nu sunt probleme, furnizarea informaiilor despre starea
sistemului face interfaa mai prietenoas. Totui, aceste mesaje pot deveni
suprtoare dac sunt folosite prea des. Pot fi afiate i mesaje despre cursul
unei aciuni sau despre timpul dup care se va termina o activitate. Dac o
aciune dureaz aproximativ 6-8 secunde, se poate folosi un indicator de tip
clepsidr. Pentru activiti mai lungi de 8 secunde, se pot folosi indicatoare
de tip procentaj sau timp rmas. Utilizatorii trebuie s aib de asemenea
posibilitatea ntreruperii sau anulrii acestor aciuni de durat.
Mesajele sonore trebuie n general evitate deoarece pot fi
suprtoare, distrag atenia iar semnificaia sunetelor poate depinde de
contextul cultural al utilizatorilor.

Culoarea joac un rol important n proiectarea unei interfee
grafice. Folosirea corect a culorilor face interfaa clar i uor de navigat.
Totui, dac nu sunt folosite cu atenie, culorile pot distrage atenia
utilizatorului.
Culorile pot fi utilizate pentru a identifica prile importante ale
interfeei. Prea multe culori strlucitoare fac textul dificil de citit. Trebuie de
asemenea evitat un fundal complet alb i nu trebuie folosite mai mult de
4 culori ntr-o fereastr. Interpretarea culorilor este foarte subiectiv. Poate
depinde de asociaii culturale, psihologice i individuale. Deci, n general,
cel mai bine este s folosim culori subtile i neexagerate. Utilizatorii
presupun de multe ori c exist o legtur ntre obiectele de aceeai culoare,
aa c trebuie s fim ateni s nu folosim aceeai culoare pentru obiecte fr
legtur.
Culorile nu trebuie s fie singura surs de informaii deoarece unii
utilizatori nu pot distinge anumite culori, iar alii pot avea monitoare care nu
suport o gam larg de culori.

Ca i culorile, icoanele pot pune n valoare o interfa grafic, dac
sunt folosite corect. Icoanele bine proiectate ofer utilizatorului un mod
accesibil de comunicare cu aplicaia. Exist cteva elemente de care trebuie
s inem seama la proiectarea acestora:

un stil i o dimensiune comun pentru toate icoanele dau interfeei
un aspect coerent;
desenele ajut utilizatorul s recunoasc metaforele i s-i
aminteasc funciile;
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

50
conturarea icoanelor cu negru le face s ias n eviden din fundal;
icoanele pot fi afiate n trei mrimi: 48 x 48, 32 x 32 i 16 x 16
pixeli; acestea trebuie s fie uor de recunoscut chiar i atunci cnd
sunt afiate la dimensiunea de 16 x 16 pixeli;
dei o icoan poate fi accentuat prin culoare, ea trebuie s poat fi
recunoscut i n varianta alb-negru.

Icoanele bine proiectate i comunic funciile cu claritate i cresc
utilizabilitatea interfeei, ns o icoan neclar poate deruta utilizatorii i
poate crete numrul de erori. Putem folosi etichete text pentru a ne asigura
c semnificaia unei icoane este clar. Cteodat este cel mai bine s folosim
imagini tradiionale deoarece utilizatorul este familiarizat cu ele. O icoan
bine proiectat trebuie s poat fi distins cu uurin de celelalte icoane din
jurul su, iar imaginea trebuie s fie simpl i potrivit contextului interfeei.

Corpurile de liter (font-urile) utilizate ntr-o interfa grafic nu
trebuie amestecate. Ca i n cazul culorilor, prea multe font-uri pot distrage
atenia utilizatorului.


4.3. Profilurile utilizatorilor

Pentru a crea o interfa grafic utilizabil, trebuie s cunoatem
profilul utilizatorului, care descrie ateptrile i nevoile acestuia. Un mod
potrivit de a determina profilul utilizatorului este prin observare la locul su
de munc. Poate fi folositoare sugestia ca utilizatorul s gndeasc cu voce
tare atunci cnd lucreaz cu prototipul unei interfee.
Aproape ntotdeauna va exista un procent de utilizatori nceptori iar
interfaa trebuie s aib grij de acetia. De exemplu, putem asigura
alternative la acceleratori (combinaii de taste pentru anumite funcii) i
putem preciza shortcut-urile n opiunile meniurilor.
Profilurile utilizatorilor se ncadreaz n general n trei categorii:

Utilizatorul comod dorete s foloseasc interfaa imediat, cu foarte
puin antrenament. Acest tip de utilizator prefer utilizarea
mouse-ului, atingerea sensibil a ecranului sau stiloul electronic.
Navigarea simpl este important deoarece utilizatorul comod nu
ine minte ci complicate. Afiarea unei singure ferestre la un
moment dat simplific navigarea. Pentru a face o interfa grafic
accesibil unui utilizator de acest tip, ea trebuie s se bazeze pe
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 2. Stilul de scriere a codului. Tratarea excepiilor. Interfaa grafic cu utilizatorul


51
recunoaterea unei icoane, mai degrab dect pe amintirea a ceea ce
reprezint icoana. Acest lucru se poate realiza prin folosirea unei
multitudini de grafice i de opiuni n meniuri;
Utilizatorul rapid dorete un timp de rspuns ct mai mic, aa nct
trebuie evitate prea multe redesenri ale ferestrelor. Acest tip de
utilizator prefer n general s foloseasc tastatura i mai puin
mouse-ul. Utilizatorii de acest tip au n general timp pentru instruire
i sunt dispui s renune la faciliti n favoarea vitezei.
Acceleratorii le permit s lucreze mai repede;
Utilizatorul energic este de nivel avansat i are experien cu
interfeele grafice. Acesta nu i dorete o instruire de durat i se
ateapt s foloseasc interfaa imediat. Deoarece este sigur pe sine
i i place s exploreze, trebuie ntotdeauna asigurat o opiune de
anulare (engl. undo). Alte trsturi pe care le ateapt sunt
schimbri limitate ale modului de afiare, multitasking i
posibilitatea particularizrii i individualizrii aspectului interfeei
grafice.


5. Realizarea programelor cu interfaa grafic
cu utilizatorul n Microsoft Visual Studio .NET

Cnd este creat un nou proiect C# de tip Windows Application, n
mijlocul ecranului (figura 2.2), apare un formular (Form) fereastra
principal a programului, n care se vor aduga diverse componente de
control: butoane, text-box-uri etc.
n partea din stnga a ecranului exist o bar de instrumente (View
Toolbox sau Ctrl+Alt+X) din care se aleg cu mouse-ul componentele ce
trebuie adugate n fereastr.
Pentru adugarea unei componente, programatorul va face click cu
mouse-ul pe imaginea corespunztoare din toolbox, apoi va face click n
formular, n locul unde dorete s apar componenta respectiv. Odat
introduse n fereastr, componentele pot fi mutate, redimensionate, copiate
sau terse. n dreapta este o fereastr de proprieti (View Properties
Window sau F4). De aici, fiecrei componente folosite i se pot modifica
proprietile, adic aspectul exterior, aa cum va aprea n program, sau
caracteristicile funcionale interne. De asemenea, se pot selecta
evenimentele corespunztoare componentei care vor fi tratate n program.

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

52


Figura 2.2. Mediul de dezvoltare Microsoft Visual Studio

n continuare, vor fi prezentate cteva componente de control
folosite practic n orice program Windows. Pentru fiecare component, vor
fi amintite unele proprieti i metode uzuale. Pentru o descriere mai
amnunit, se recomand consultarea documentaiei MSDN.


Application

Clasa Application ncapsuleaz o aplicaie Windows. Clasa conine
metode i proprieti statice pentru managementul unei aplicaii, cum ar fi
metode pentru pornirea i oprirea programului, prelucrarea mesajelor
Windows i proprieti corespunztoare informaiilor despre aplicaie.
Se poate observa c n scheletul de program creat implicit de mediul
de dezvoltare, n metoda Main() este pornit programul pe baza clasei
corespunztoare ferestrei principale:

Application.Run(new MainForm());


Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 2. Stilul de scriere a codului. Tratarea excepiilor. Interfaa grafic cu utilizatorul


53
Form

Clasa System.Windows.Forms.Form corespunde unei ferestre
standard. O aplicaie poate avea mai multe ferestre una principal, cteva
secundare i cteva ferestre de dialog.
Unele proprieti:

Icon icoana care apare n bara de titlu a ferestrei;
FormBorderStyle nfiarea i comportamentul chenarului, de
exemplu, dac fereastra poate fi redimensionat;
Text titlul ferestrei, care apare n bara de titlu i n taskbar;
StartPosition locul unde apare fereastra pe ecran;
Size dimensiunea (nlimea i limea ferestrei); de obicei se
stabilete prin redimensionarea ferestrei cu mouse-ul, n procesul de
proiectare.

Cteva evenimente:

Load, Closed pentru diverse iniializri n momentul crerii
ferestrei sau prelucrri n momentul nchiderii acesteia;

n general, pentru tratarea unui eveniment n C#, este selectat mai
nti obiectul de tipul dorit (la noi fereastra), apoi n fereastra de proprieti
se alege tab-ul de evenimente i se identific evenimentul cutat.

Figura 2.3. Editarea proprietilor componentelor

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

54
Dup un dublu-click, ca n figura 2.3, se va crea automat o nou
metod vid corespunztoare evenimentului, iar utilizatorul va trebui numai
s scrie n corpul funciei comenzile dorite.


Button

Clasa System.Windows.Forms.Button corespunde unui buton.
Cteva proprieti i evenimente:

Text textul nscris pe buton;
Click funcia executat cnd butonul este apsat.


Label

Clasa System.Windows.Forms.Label nscrie un text undeva n
fereastr. Una din proprieti:

Text textul nscris.


TextBox

Clasa System.Windows.Forms.TextBox corespunde unei csue de
editare de text. Cteva proprieti i evenimente:

Text textul din csu (de tip string);
Multiline textul poate fi introdus pe o singur linie (false) sau pe
mai multe (true);
ScrollBars indic prezena unor bare de derulare (orizontale,
verticale) dac proprietatea Multiline este true;
Enabled componenta este activat sau nu (true / false);
ReadOnly textul poate fi modificat sau nu de utilizator (true /
false);
CharacterCasing textul poate aprea normal (Normal), numai cu
litere mici (Lower) sau numai cu litere mari (Upper);
TextChanged evenimentul de tratare a textului n timp real, pe
msur ce acesta este introdus.
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 2. Stilul de scriere a codului. Tratarea excepiilor. Interfaa grafic cu utilizatorul


55
ComboBox

Clasa System.Windows.Forms.ComboBox corespunde unui combo-
box, care combin un text-box cu o list. Cteva proprieti i evenimente:

Text textul din partea de editare;
Items lista de obiecte din partea de selecie, care se poate introduce
i prin intermediul ferestrei de proprieti;
SelectedIndex numrul articolului din list care este selectat (0
primul, 1 al doilea, etc., 1 dac textul din partea de editare nu este
ales din list);
TextChanged, SelectedIndexChanged evenimente de tratare a
schimbrii textului prin introducerea direct a unui nou cuvnt sau
prin alegerea unui obiect din list.


MenuStrip

Clasa System.Windows.Forms.MenuStrip corespunde meniului
principal al unei ferestre. Mod de folosire:

se introduce o component de acest tip n fereastr;
se editeaz meniul, direct n fereastr sau folosind proprietile;
pentru separatori se introduce n cmpul Caption un minus ( );
literele care se vor a fi subliniate trebuie precedate de &;
pentru implementarea metodei de tratare a unei opiuni din meniu se
va face dublu-click pe aceasta (sau pe evenimentul Click n fereastra
de proprieti).


Timer

Clasa System.Windows.Forms.Timer ncapsuleaz funciile de
temporizare din Windows. Cteva proprieti i evenimente:

Tick evenimentul care va fi tratat o dat la un interval de timp;
Interval intervalul de timp (n milisecunde) la care va fi executat
codul corespunztor evenimentului Tick;
Enabled indic dac timer-ul e activat sau nu (true / false).
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

56
string

Este o clas care permite lucrul cu iruri de caractere.
Exist operatorul +, care permite concatenarea irurilor:

string str1 = "Microsoft ";
string str2 = "Word";
str1 = str1 + str2; // sau str1 += str2; => str1 == "Microsoft Word"

Clasa conine multe proprieti i metode utile, dintre care amintim:

int Length lungimea irului;
int IndexOf(...) poziia n ir la care apare prima dat un caracter
sau un subir;
string Substring(...) returneaz un subir;
string Remove(int startIndex, int count) returneaz irul rezultat
prin tergerea a count caractere din ir, ncepnd cu poziia
startIndex;
string[] Split(...) mparte irul n mai multe subiruri delimitate de
anumite secvene de caractere.

O metod static a clasei este Format(...), care returneaz un ir de
caractere corespunztor unui anumit format. Sintaxa este asemntoare cu
cea a funciei printf din C. De exemplu:

double d = 0.5;
string str = string.Format("Patratul numarului {0} este {1}", d, d * d);

Acelai rezultat s-ar fi putut obine astfel:

str = "Patratul numarului " + d.ToString() + " este " + (d * d).ToString();

Orice obiect are metoda ToString(), care convertete valoarea sa
ntr-un ir. Pentru obiecte definite de programator, aceast metod poate fi
suprascris.
Dac n exemplul de mai sus d = 0.72654 i dorim s afim
numerele numai cu 2 zecimale, metoda Format i dovedete utilitatea
(figura 2.4).


Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 2. Stilul de scriere a codului. Tratarea excepiilor. Interfaa grafic cu utilizatorul


57
string str=string.Format("Patratul numarului {0:F2} este {1:F2}", d, d*d);
MessageBox.Show(str);


Figura 2.4. Mesaj cu numere formatate


StringBuilder

Majoritatea programatorilor utilizeaz de obicei clasa string cnd
opereaz cu iruri de caractere. n cazul concatenrii unor iruri, folosirea
clasei StringBuilder aduce o important cretere de performan. S
considerm urmtorul bloc:

string listaNumere = "";
for (int i=0; i<1000; i++)
listaNumere = listaNumere + " " + (i + 1).ToString();

n acest caz, se creeaz un nou obiect string la fiecare atribuire, adic
de 1000 de ori!
Codul echivalent folosind StringBuilder este urmtorul:

StringBuilder sbListaNumere = new StringBuilder(10000);
for (int i = 0; i < 1000; i++)
{
sbListaNumere.Append(" ");
sbListaNumere.Append((i+1).ToString());
}
string listaNumere2 = sbListaNumere.ToString();

Pentru a avea acces la clasa StringBuilder, trebuie inclus
namespace-ul System.Text la nceputul programului:

using System.Text;

Directivele using sunt asemntoare directivelor #include din
C/C++. Namespace-urile sunt colecii de clase predefinite sau definite de
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

58
programator. Dac nu se dorete utilizarea unui namespace, clasa trebuie
referit cu tot cu namespace. n cazul de fa:

System.Text.StringBuilder sbListaNumere = new System.Text.StringBuilder(10000);

Ca dezavantaje, trebuie s menionm c la iniializarea unui obiect
StringBuilder performanele scad. De asemenea, sunt foarte multe operaii
care nu se pot efectua cu StringBuilder, ci cu string. Pentru concatenarea a 2
iruri nu este nevoie de StringBuilder. Se poate recomanda utilizarea acestei
clase dac e nevoie de concatenarea a cel puin 4 iruri de caractere. De
asemenea, pentru creterea vitezei, trebuie s estimm lungimea final a
irului (parametrul constructorului). Dac folosim constructorul vid sau
lungimea estimat este mai mic dect n realitate, alocarea spaiului se face
automat iar performana scade.


6. Elemente de C#

6.1. Clase pariale

n clasele corespunztoare ferestrelor, exist metode predefinite
generate automat de mediul Visual Studio, care conin iniializarea
controalelor grafice. Aceste metode sunt de obicei de dimensiuni mai mari i
sunt separate de logica aplicaiei fiind plasate ntr-un alt fiier, numit
*.Designer.cs.
Definiia unei clase, structuri sau interfee se poate mpri n dou
sau mai multe fiiere surs. Fiecare fiier surs conine o parte din definiia
clasei i toate prile sunt combinate cnd aplicaia este compilat. Exist
cteva situaii cnd este util mprirea definiiei clasei:

Cnd se lucreaz la proiecte mari, mprirea clasei n fiiere
separate permite mai multor programatori s lucreze la ele simultan;
Cnd se lucreaz cu surse generate automat, codul poate fi adugat
clasei fr s mai fie nevoie de recrearea fiierului surs. Visual
Studio folosete aceast cale cnd creeaz ferestrele Windows, codul
wrapper pentru servicii web .a.m.d. Programatorul poate scrie
codul care folosete aceste poriuni fr s mai fie nevoie de
modificarea fiierului creat de Visual Studio.

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 2. Stilul de scriere a codului. Tratarea excepiilor. Interfaa grafic cu utilizatorul


59
Pentru a mpri definiia unei clase, se folosete cuvntul cheie
partial, dup cum este prezentat mai jos:

public partial class Student
{
public void Learn()
{
}
}

public partial class Student
{
public void TakeExam()
{
}
}

Modificatorul partial nu este valabil n declaraiile pentru funcii
delegat sau enumerri.


6.2. Proprieti. Accesori

Proprietile sunt membri care furnizeaz un mecanism flexibil de
citire, scriere, sau calculare de valori ale cmpurilor private. Ele pot fi
folosite ca i cum ar fi membri publici, dar ele sunt de fapt metode speciale,
care permit ca datele s fie accesate mai uor ns n acelai timp pstreaz
sigurana i flexibilitatea metodelor.
Proprietile combin aspecte specifice att cmpurilor ct i
metodelor. Pentru utilizatorul unui obiect, o proprietate apare ca un cmp,
deoarece accesul la proprietate necesit exact aceeai sintax. Pentru
realizatorul clasei, o proprietate este format din unul sau dou blocuri de
cod, reprezentnd un accesor get i/sau un accesor set. Blocul de cod pentru
accesorul get este executat cnd proprietatea este citit, iar blocul de cod
pentru accesorul set este executat cnd proprietii i este atribuit o valoare.
O proprietate fr accesorul set este considerat doar pentru citire
(read-only). O proprietate fr accesorul get este considerat doar pentru
scriere (write-only). O proprietate cu ambii accesori este pentru citire i
scriere (read-write).



Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

60
6.2.1. Accesorul get

Corpul accesorului get este similar cu cel al unei metode i trebuie
s returneze o valoare de tipul proprietii. Execuia accesorului get este
echivalent cu citirea valorii cmpului corespunztor. n urmtorul exemplu,
este prezentat un accesor get ce ntoarce valoarea unui cmp privat _name:

class Person
{
private string _name; // cmp

public string Name // proprietate
{
get
{
return _name;
}
}
}

Din exteriorul clasei, citirea valorii proprietii se realizeaz astfel:

Person p1 = new Person();
Console.Write(p1.Name); // se apeleaz accesorul get

Accesorul get trebuie s se termine cu instruciunea return sau
throw, iar fluxul de control nu poate depi corpul accesorului.
Cnd se ntoarce doar valoarea unui cmp privat i sunt permise
optimizrile, apelul ctre accesorul get este tratat inline de ctre compilator
n aa fel nct s nu se piard timp prin efectuarea unui apel de metod.
Totui, un accesor get virtual nu poate fi tratat inline ntruct compilatorul
nu tie n timpul compilrii ce metod va fi de fapt apelat n momentul
rulrii.
Schimbarea strii unui obiect utiliznd accesorul get nu este
recomandat. De exemplu, urmtorul accesor produce ca efect secundar
schimbarea strii obiectului de fiecare dat cnd este accesat cmpul
_number.




Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 2. Stilul de scriere a codului. Tratarea excepiilor. Interfaa grafic cu utilizatorul


61
private int _number;

public int Number
{
get
{
return _number++; // !!! nerecomandat
}
}

Accesorul get poate fi folosit fie ca s returneze valoarea unui cmp,
fie s o calculeze i apoi s o returneze. De exemplu:

class Student
{
private string _name;

public string Name
{
get
{
return _name != null ? _name : "NA";
}
}
}

n secvena de cod anterioar, dac _name este null, proprietatea va
ntoarce totui o valoare, i anume NA (engl. No Account).


6.2.2. Accesorul set

Accesorul set (numit i mutator) este similar cu o metod ce ntoarce
void. Folosete un parametru implicit numit value (valoare), al crui tip este
tipul proprietii. n exemplul urmtor, este adugat un accesor set
proprietii Name:







Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

62
class Person
{
private string _name;

public string Name
{
get
{
return _name;
}
set
{
_name = value;
}
}
}

Cnd se atribuie o valoare proprietii, este apelat accesorul set cu
un argument ce furnizeaz noua valoare. De exemplu:

Person p1 = new Person();
p1.Name = "Joe"; // se apeleaz accesorul set cu value = "Joe"


6.2.3. Aspecte mai complexe ale lucrului cu proprieti

n exemplul urmtor, clasa TimePeriod reine o perioad de timp n
secunde, dar are o proprietate numit Hours care permite unui client s
lucreze cu timpul n ore.

class TimePeriod
{
private double _seconds;

public double Hours
{
get { return _seconds / 3600; }
set { _seconds = value * 3600; }
}
}


Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 2. Stilul de scriere a codului. Tratarea excepiilor. Interfaa grafic cu utilizatorul


63
class Program
{
static void Main()
{
TimePeriod t = new TimePeriod();

// atribuirea proprietii Hours determin apelul accesorului set
t.Hours = 24;

// evaluarea proprietii Hours determin apelul accesorului get
Console.WriteLine("Timpul in ore: " + t.Hours);
}
}

n mod implicit, accesorii au acceai vizibilitate, sau nivel de acces
cu al proprietii creia i aparin. Totui, uneori li se poate restriciona
accesul. De obicei, aceasta implic restricionarea accesibilitii accesorului
set, n timp ce accesorul get rmne public. De exemplu:

public string Name
{
get
{
return _name;
}
protected set
{
_name = value;
}
}

Aici, accesorul get primete nivelul de accesibilitate al proprietii
nsi, public n acest caz, n timp ce accesorul set este restricionat n mod
explicit aplicnd modificatorul de acces protected.
Proprietile au mai multe utilizri: pot valida datele nainte de a
permite o modificare, pot returna date cnd acestea sunt de fapt provenite
din alte surse, precum o baz de date, pot produce o aciune cnd datele sunt
modificate, cum ar fi invocarea unui eveniment sau schimbarea valorii altor
cmpuri.
n exemplul urmtor, Month este o proprietate:



Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

64
public class Date
{
private int _month = 7;

public int Month
{
get
{
return _month;
}
set
{
if ((value > 0) && (value < 13))
{
_month = value;
}
}
}
}

Aici, accesorul set garanteaz c valoarea cmpului _month este
ntre 1 i 12. Locaia real a datelor proprietii este de obicei denumit
memorie auxiliar (engl. backing store). Marea majoritate a
proprietilor utilizeaz n mod normal cmpuri private ca memorie
auxiliar. Cmpul este marcat privat pentru a se asigura faptul c nu poate fi
accesat dect prin apelarea proprietii.
O proprietate poate fi declarat static folosind cuvntul cheie static.
n acest fel proprietatea devine disponibil apelanilor oricnd, chiar dac nu
exist nicio instan a clasei.
Spre deosebire de cmpuri, proprietile nu sunt clasificate ca
variabile i de aceea nu se poate transmite o proprietate ca parametru ref sau
out.

Important! Exist instrumente care genereaz automat proprieti
read-write pentru toate cmpurile. Dac ntr-o clas exist multe cmpuri,
trebuie s ne ntrebm dac toate acestea trebuie s fie accesibile din
exterior. Nu are sens ca toate cmpurile private ale unei clase s fie expuse
n afar, chiar i prin intermediul proprietilor.




Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 2. Stilul de scriere a codului. Tratarea excepiilor. Interfaa grafic cu utilizatorul


65
7. Aplicaii

7.1. Realizai interfaa grafic a unei aplicaii Windows pentru
rezolvarea de ecuaii polinomiale de gradul I i II, precum i de ecuaii
trigonometrice simple (figura 2.5).


Figura 2.5. Exemplu de rezolvare


7.2. Creai clasele pentru rezolvarea celor dou tipuri de ecuaii
(figura 2.6). Se vor arunca dou tipuri de excepii, conform structurii de mai
jos. Fiind dou tipuri diferite de ecuaii, vom avea o interfa IEquation cu
metoda Solve, din care vor fi derivate PolyEquation i TrigEquation.
n clasa principal, evenimentul de tratare a apsrii butonului
Calculeaza va testa tipul de ecuaie.
Pentru o ecuaie polinomial, va citi coeficienii ecuaiei i va
instania un obiect corespunztor:

IEquation eq = new PolyEquation(x2, x1, x0);
textBoxSolutie.Text = eq.Solve();

Pentru o ecuaie trigonometric, depinznd de tipul de funcie
trigonometric:

eq = new TrigEquation(TrigEquation.TrigonometricFunction.Sin, arg);
textBoxSolutie.Text = eq.Solve();


Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

66

Figura 2.6. Exemplu de rezolvare: clasele soluiei

Fiecrui tip de ecuaie i va corespunde propria clas de excepie:
PolyException, respectiv TrigException.
Pentru ecuaia polinomial se vor considera urmtoarele excepii:

pentru

: O infinitate de soluii;
pentru

: Nicio soluie.

Pentru ecuaia trigonometric, excepia Argument invalid va fi
aruncat cnd || , ns numai pentru funciile arcsin i arccos.
n evenimentul butonului vom avea un singur bloc try, urmat de trei
blocuri catch: pentru cele dou tipuri de excepie, precum i pentru
excepiile generice, rezultate de exemplu la ncercarea de a citi coeficienii,
dac utilizatorul introduce caractere nenumerice.

Indicaie: codul pentru rezolvarea ecuaiei polinomiale este prezentat
n continuare, unde

:


Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 2. Stilul de scriere a codului. Tratarea excepiilor. Interfaa grafic cu utilizatorul


67
if (_x2 == 0)
{
_eqType = EquationType.FirstDegree;
// soluie: -_x0 / _x1
}
else if (delta > 0)
{
double sqrtDelta = Math.Sqrt(delta);
double sol1 = (-_x1 + sqrtDelta) / (2.0 * _x2);
double sol2 = (-_x1 - sqrtDelta) / (2.0 * _x2);
// soluii: sol1, sol2
}
else if (delta == 0)
{
double sol = (-_x1) / (2.0 * _x2);
// soluie: sol
}
else
{
double rsol = -_x1 / (2.0 * _x2);
double isol = Math.Sqrt(-delta) / (2.0 * _x2);
// soluii: rsol isol
}

Atenie: scopul laboratorului este lucrul cu excepii, nu rezolvarea
propriu-zis a ecuaiilor!


7.3. Eliminai blocurile try-catch din clasa principal a aplicaiei i
efectuai tratarea excepiilor pe firul de execuie n metoda Main.


Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

68

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com

69

Capitolul 3

Reutilizarea codului cu ajutorul DLL-urilor

1. Obiective
2. Bibliotecile legate dinamic
3. Crearea DLL-urilor n C#
4. Grafic n C#
5. Aplicaii

1. Obiective

Obiectivele capitolului 3 sunt urmtoarele:

Descrierea DLL-urilor;
Legarea static a DLL-urilor .NET, cea mai simpl i folosit form;
Legarea dinamic a DLL-urilor .NET, util pentru crearea
plug-in-urilor;
Prezentarea unor aspecte privind grafica n C#.


2. Bibliotecile legate dinamic

Bibliotecile legate dinamic (engl. Dynamic Link Libraries, DLL),
reprezint implementarea Microsoft a conceptului de bibliotec partajat
(engl. shared library). n trecut, DLL-urile au dat dezvoltatorilor
posibilitatea de a crea biblioteci de funcii care puteau fi folosite de mai
multe aplicaii. nsui sistemul de operare Windows a fost proiectat pe baza
DLL-urilor. n timp ce avantajele modulelor de cod comun au extins
oportunitile dezvoltatorilor, au aprut de asemenea probleme referitoare la
actualizri i revizii. Dac un program se baza pe o anumit versiune a unui
DLL i alt program actualiza acelai DLL, de multe ori primul program
nceta s mai funcioneze corect.
Pe lng problemele legate de versiuni, dac se dorea dezinstalarea
unei aplicaii, se putea terge foarte uor un DLL care era nc folosit de un
alt program.
Soluia propus de Microsoft a fost introducerea posibilitii de a
urmri folosirea DLL-urilor cu ajutorul registrului, ncepnd cu Windows
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

70
95. Se permitea unei singure versiuni de DLL s ruleze n memorie la un
moment dat. Cnd era instalat o nou aplicaie care folosea un DLL
existent, se incrementa un contor. La dezinstalare, contorul era decrementat
i dac nicio aplicaie nu mai folosea DLL-ul, atunci acesta putea fi ters.
Apare ns o alt problem deoarece cnd un DLL este ncrcat,
Windows va folosi versiunea ce ruleaz pn cnd nicio aplicaie nu o mai
folosete. Astfel, chiar dac DLL-ul sistemului este n regul, sau o aplicaie
are o copie local pe care se lucreaz, cnd aplicaia precedent a pornit cu
o versiune incompatibil, atunci noua aplicaie nu va merge.
Aceast problem se poate manifesta n situaii precum urmtoarele:
o aplicaie nu funcioneaz atunci cnd ruleaz o alt aplicaie sau, i mai
ciudat, o aplicaie nu funcioneaz dac o alt aplicaie a rulat (dar nu mai
ruleaz neaprat n prezent). Dac aplicaia A ncarc o bibliotec
incompatibil sau corupt, atunci aplicaia B lansat folosete aceast
bibliotec. Aceast versiune va sta n memorie chiar dup ce aplicaia A nu
mai exist (att timp ct aplicaia B nc ruleaz), deci aplicaia B s-ar putea
s nceteze s funcioneze din cauza aplicaiei A, chiar dac aceasta nu mai
ruleaz. O a treia aplicaie C poate s eueze (ct vreme aplicaia B nc
ruleaz) chiar dac este pornit dup ce aplicaia A a fost nchis.
Rezultatul s-a numit infernul DLL (engl. DLL hell).
Rezolvarea infernului DLL a fost unul din scopurile platformei
.NET. Aici pot exista mai multe versiuni ale unui DLL ce ruleaz simultan,
ceea ce permite dezvoltatorilor s adauge o versiune care funcioneaz la
programul lor fr s se ngrijoreze c un alt program va fi afectat. Modul n
care .NET reuete s fac aceasta este prin renunarea la folosirea
registrului pentru a lega DLL-urile de aplicaii i prin introducerea
conceptului de assembly.


3. Crearea DLL-urilor n C#

Din fereastra corespunztoare File New Project, se alege tipul
proiectului Class Library (figura 3.1). n namespace-ul proiectului pot fi
adugate mai multe clase. n acest caz, din exterior fiecare clas va fi
accesat ca Namespace.ClassName. Dac se elimin namespace-ul, clasa va
fi accesat direct cu numele clasei: ClassName. Spre deosebire de o aplicaie
executabil, aici nu va exista o metod Main, deoarece DLL-ul este numai o
bibliotec de funcii utilizabile din alte programe executabile.

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 3. Reutilizarea codului cu ajutorul DLL-urilor


71


Figura 3.1. Crearea unui proiect de tip Class Library (DLL)






Figura 3.2. Adugarea unei referine la un DLL



Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

72
3.1. Legarea static

Dup ce s-a creat un proiect corespunztor unei aplicaii executabile,
din Project Add Reference, se selecteaz de pe harddisk n tab-page-ul
Browse fiierul DLL care trebuie adugat n proiect. n continuare, n
program vor fi utilizate ca atare toate funciile din DLL (figura 3.2).
S considerm urmtorul exemplu: avem ntr-un DLL numit
Operatii.dll o clas Putere n namespace-ul Matematica avnd o metod
double Patrat(double x) care returneaz valoarea parametrului ridicat la
ptrat. Mai nti, se va cuta i selecta fiierul Operatii.dll de pe harddisk.
Apoi, ntr-o metod din clasa programului principal, se va apela direct
metoda de ridicare la putere:

double a = Matematica.Putere.Patrat(5.5);


3.2. Legarea dinamic

Legarea static presupune c se cunoate ce DLL va trebui ncrcat
nainte de executarea programului. Exist totui situaii n care acest lucru
este imposibil: de exemplu, dac o aplicaie necesit o serie de plug-in-uri,
acestea pot fi adugate sau terse, iar aplicaia principal trebuie s
determine dup lansarea n execuie cu ce DLL-uri poate lucra. Un alt
avantaj este faptul c programatorul poate testa existena unui anumit DLL
necesar i poate afia un mesaj de eroare i eventual o modalitate de
corectare a acesteia.
C# permite ncrcarea dinamic a DLL-urilor. S considerm tot
exemplul anterior. Apelul metodei de ridicare la ptrat se face n modul
urmtor:

// se ncearc ncrcarea DLL-ului
Assembly a = Assembly.Load("Operatii");

// se identific tipul (clasa) care trebuie instaniat
// dac n clasa din DLL exist un namespace,
// se folosete numele complet al clasei din assembly, incluznd namespace-ul
Type t = a.GetType("Matematica.Putere");

// se identific metoda care ne intereseaz
MethodInfo mi = t.GetMethod("Patrat");

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 3. Reutilizarea codului cu ajutorul DLL-urilor


73
// se creeaz o instan a clasei dorite
// aici se apeleaz constructorul implicit
object o = Activator.CreateInstance(t);

// definim un vector de argumente pentru a fi trimis metodei
// metoda Ptrat are numai un argument de tip double
object[] args = new object[1];
double x = 5.5;
args[0] = x;

// apelul efectiv al metodei i memorarea rezultatului
double result = (double)mi.Invoke(o, args);

Acesta este modul general de ncrcare. Este obligatorie tratarea
excepiilor care pot aprea datorit unei eventuale absene a DLL-ului sau a
ncrcrii incorecte a unei metode. De aceea, fluxul de mai sus va trebui
mprit n mai multe blocuri care s permit tratarea excepiilor, ncrcarea
o singur dat a bibliotecii i apelarea de cte ori este nevoie a metodelor
dorite.
Dac se apeleaz dinamic o metod static, se folosete null n loc de
obiectul o.
La nceputul programului, dac avem o aplicaie Windows, n
evenimentul Load al ferestrei trebuie s existe un bloc de tipul:

private void Form1_Load(object sender, EventArgs e)
{
try
{
LoadOperatiiPutere();
}
catch (Exception exc)
{
MessageBox.Show(exc.Message, "Exceptie DLL");
Close();
}
}







Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

74
Metoda care ncarc efectiv DLL-ul este:

private void LoadOperatiiPutere()
{
Type t = null;

try
{
Assembly a = Assembly.Load("Operatii");
t = a.GetType("Matematica.Putere");
}
catch (Exception)
{
throw new Exception("Operatii.dll nu poate fi incarcat");
}

_miPatrat = t.GetMethod("Patrat");
if (_miPatrat == null)
throw new Exception("Metoda Patrat din Operatii.dll nu poate fi accesata");

_objPutere = Activator.CreateInstance(t);
}

Metoda clasei din programul executabil care realizeaz apelul efectiv
este:

private double MyOperatiiPutere(double x)
{
object[] args = new object[1];
args[0] = x;
return (double)_miPatrat.Invoke(_objPutere, args);
}

Pentru compilarea codului de mai sus este necesar includerea n
program a namespace-ului System.Reflection.


3.3. Depanarea unui DLL

Deoarece un DLL nu este direct executabil, exist dou metode
pentru dezvoltarea i depanarea unei astfel de componente.
Abordarea cea mai simpl este crearea unei aplicaii executabile, de
cele mai multe ori de tip consol n cazul n care DLL-ul va conine funcii
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 3. Reutilizarea codului cu ajutorul DLL-urilor


75
de calcul i nu grafice. n proiect va exista namespace-ul DLL-ului cu toate
clasele aferente, iar n plus o clas cu o metod Main, din care se vor putea
apela i depana metodele din DLL. La sfrit, dup ce DLL-ul este corect, se
poate exclude clasa cu Main i se poate recompila proiectul ca DLL: Project
Properties Application Output type. Alternativ, se poate crea un nou
proiect de tip Class library n care se va copia codul DLL-ului.
A doua metod este includerea a dou proiecte ntr-o soluie n
Visual Studio. Un proiect va fi DLL-ul iar cellalt proiect va fi unul
executabil. Din proiectul executabil trebuie adugat referina la DLL. n
consecin, fiierul dll rezultat din compilare va fi copiat automat n
directorul fiierului exe.


4. Grafic n C#

Pentru lucrul n mod grafic, C# pune la dispoziia programatorului o
clas numit Graphics. Pentru a transla suprafaa de desenare n cadrul
ferestrei, se poate folosi un obiect de tip PictureBox, care va fi plasat acolo
unde se dorete.

Important! Desenarea n fereastr, ntr-un PictureBox sau n orice
alt control trebuie fcut numai n evenimentul Paint al controlului
respectiv. n caz contrar, cnd fereastra este minimizat sau cnd controlul
este acoperit de alte ferestre, desenul se pierde.

Evenimentul Paint conine un parametru de tipul:

System.Windows.Forms.PaintEventArgs e

Suprafaa grafic a controlului va fi n acest caz e.Graphics, care
conine metodele de desenare. Majoritatea controalelor au implementat un
eveniment Paint. n afara acestuia, suprafaa de desenare poate fi identificat
prin metoda CreateGraphics, care returneaz un obiect de tip Graphics. n
cele ce urmeaz, vom aminti unele elemente de baz, care pot fi folosite n
program ca atare (totui, pentru aprofundarea acestor cunotine, se pot
consulta alte manuale sau documentaia MSDN). Deoarece majoritatea
metodelor sunt suprancrcate, vom da cte un exemplu simplu de utilizare
pentru fiecare situaie.


Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

76
Desenarea unei linii

e.Graphics.DrawLine(Pen pen, int x1, int y1, int x2, int y2)

Primul parametru precizeaz culoarea i stilul de desenare a liniei.
Se poate declara i folosi un nou obiect de tip Pen (Pen pen = new Pen(...)),
ns pentru linii continue i culori predefinite se poate utiliza enumerarea
Pens. De exemplu:

e.Graphics.DrawLine(Pens.Black, 10, 10, 20, 40);

Desenarea unui dreptunghi i a unei elipse

e.Graphics.DrawRectangle(Pen pen, int x, int y, int latime, int inaltime)

Deseneaz conturul unui dreptunghi, cu un anumit stil i culoare,
folosind coordonatele unui vrf i respectiv limea i nlimea sa. Pentru
umplerea unui dreptunghi cu un anumit model i culoare, se folosete
metoda:

e.Graphics.FillRectangle(Brush b, int x, int y, int latime, int inaltime)

Ca i n cazul unui Pen, se poate declara un nou obiect de tip Brush,
de exemplu:

Brush b = new SolidBrush(Color.Blue);

sau se poate folosi enumerarea Brushes, care presupune c stilul de umplere
va fi solid (compact).
Un dreptunghi alb cu contur negru se va desena astfel:

e.Graphics.FillRectangle(Brushes.White, 0, 0, 10, 20);
e.Graphics.DrawRectangle(Pens.Black, 0, 0, 10, 20);

n mod analog se folosesc metodele DrawEllipse i FillEllipse.

Afiarea unui text n mod grafic

DrawString (string s, Font font, Brush brush, int x, int y)
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 3. Reutilizarea codului cu ajutorul DLL-urilor


77
Primul parametru este textul care trebuie afiat. Al doilea parametru
reprezint corpul de liter cu care se va desena irul de caractere. De
exemplu:

Font font = new Font("Arial", 10);

Al treilea parametru este utilizat pentru trasarea efectiv a textului
(vezi paragraful despre desenarea unui dreptunghi i a unei elipse). Ultimii
doi parametri sunt coordonatele ecran.


Double-buffering automat

Deoarece funciile grafice sunt n general lente, pentru desene
suficient de complexe sau animaii, unde se presupune tergerea unor
elemente i afiarea altora, ecranul pare s clipeasc (engl. flickering). O
soluie este desenarea tuturor elementelor ntr-o zon de memorie, de
exemplu un Bitmap, i apoi afiarea direct a acestuia pe ecran. Aceast
afiare presupune de obicei doar copierea unor informaii dintr-o zon de
memorie n alta, fiind deci foarte rapid. Deoarece se folosesc dou zone de
memorie, aceast tehnic se numete double-buffering. n anumite situaii,
se pot folosi mai multe zone de memorie.
n C# se poate face automat double-buffering, prin introducerea unei
linii precum urmtoarea (de obicei, dar nu obligatoriu) n constructorul
ferestrei:

SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.DoubleBuffer |
ControlStyles.UserPaint, true);

Versiunea 2.0 a platformei .NET (cu Visual Studio 2005) a introdus
proprietatea DoubleBuffered pentru obiectele Form.


5. Aplicaii

5.1. Realizai un DLL numit Prim care s conin o clas cu o
metod care testeaz dac un numr natural, primit ca parametru, este prim.
Not: 1 nu este numr prim.


Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

78
5.2. Realizai un program executabil care testeaz conjectura lui
Goldbach: orice numr par mai mare sau egal ca 4 poate fi scris ca sum de
2 numere prime i orice numr impar mai mare sau egal ca 7 poate fi scris
ca sum de 3 numere prime (figura 3.3). Va fi folosit funcia de test pentru
numere prime din Prim.dll. Legarea se va face static.


Figura 3.3. Exemplu de rezolvare


5.3. Modificai Prim.dll prin adugarea unei metode int
NumaraPrime(int n), care calculeaz numrul numerelor prime mai mici sau
egale cu . Verificai c Suma.exe se execut corect dup modificarea
DLL-ului.


5.4. Realizai un program executabil care ncarc dinamic biblioteca
Prim.dll i apeleaz metoda NumaraPrime.


5.5. Tem pentru acas. Realizai un program executabil care s
afieze graficul funciei:

= numrul de numere prime , > 0.

precum i o aproximare a acestui numr, de forma:




Pentru calculul exact, se va utiliza metoda int NumaraPrime(int n)
din Prim.dll. Pentru aproximare, se va crea un DLL numit Aproximare, cu o
clas cu acelai nume care s conin o metod double XLogX(double x).
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 3. Reutilizarea codului cu ajutorul DLL-urilor


79
Legarea se va face dinamic. Verificai tratarea excepiilor n cazul utilizrii
unui DLL cu o semntur incorect a metodei XLogX.

Indicaii. Pentru fiecare metod din DLL-uri, este util definirea unei
metode corespunztoare n programul principal. De exemplu, pentru metoda
EstePrim din Prim.dll, se poate crea o metod de tipul:

private bool MyPrimEstePrim(int n)

care s apeleze metoda EstePrim i s returneze rezultatul. n continuare, n
program se va apela direct metoda MyPrimEstePrim. ncrcarea DLL-ului
trebuie fcut o singur dat, la pornirea programului, chiar dac apelul
metodelor se va face ori de cte ori este necesar.
Cele dou funcii nu se suprapun, doar forma lor este asemntoare.
De aceea, cele dou grafice trebuie scalate diferit pe axa Y (figura 3.4).


Figura 3.4. Exemplu de rezolvare


Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

80

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com


81

Capitolul 4

Documentarea unui proiect.
Fiiere de ajutor

1. Obiective
2. Crearea de fiiere de ajutor
3. Activarea unui fiier de ajutor prin program
4. Generarea automat a documentaiei API
5. Comentariile
6. Lucrul cu fiiere n C#: ncrcare, salvare
7. Aplicaii

1. Obiective

Obiectivele principale ale capitolului 4 sunt urmtoarele:

Crearea de fiiere de ajutor (help) n formatele HLP i CHM ;
Activarea unui fiier de ajutor dintr-un program C#;
Generarea automat a documentaiei API a unei soluii C# cu
ajutorul utilitarului NDoc.

n plus, ne propunem:

S oferim o serie de recomandri privind comentarea unui program;
S prezentm utilizarea dialogurilor de ncrcare i salvare, precum
i o modalitate simpl de a lucra cu fiiere n C#;
S utilizm o clas care poate rezolva ptrate magice de orice
dimensiune (att de dimensiune impar ct i de dimensiune par).


2. Crearea de fiiere de ajutor

2.1. Crearea de fiiere HLP

Un utilitar gratuit pentru realizarea de fiiere HLP este Microsoft
Help Workshop (figura 4.1). Acesta creeaz fiiere HLP pe baza unui
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

82
document Rich Text Format, RTF, editat dup anumite convenii,
corespunztoare opiunilor fiierelor de ajutor.
Subiectele din help sunt asociate n general cu un identificator unic.
Acesta se insereaz printr-o not de subsol (engl. footnote) cu caracterul #
naintea titlului paginii respective. Deschiderea unei anumite pagini de
ajutor, att din fiierul cuprins, ct i dintr-un program, se face pe baza
acestui identificator. Paginile sunt desprite cu separator de pagin (engl.
page break).



Figura 4.1. Microsoft Help Workshop

Fiierul de ajutor propriu-zis poate fi nsoit de un fiier cuprins,
cu formatul urmtor:

:Base Exemplu.hlp
:Title Exemplu de fisier .hlp
:Index=Exemplu.hlp
1 Capitolul 1
2 Pagina 1=Topic_id1
2 Pagina 2=Topic_id2
1 Capitolul 2
2 Pagina 3=Topic_id3

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 4. Documentarea unui proiect. Fiiere de ajutor


83
Base reprezint numele fiierului de ajutor, titlul determin textul ce
va aprea pe bara ferestrei help-ului, iar indexul precizeaz fiierul de unde
se va face indexarea (n cazul nostru, acelai fiier). n continuare, se descrie
structura help-ului ntr-o manier arborescent. Numerele din faa
denumirilor de capitole reprezint nivelul n arbore al subiectului respectiv
(figura 4.2).



Figura 4.2. Cuprinsul unui fiier HLP

Se observ c legtura la paginile corespunztoare se face pe baza
identificatorului de subiect, topic id.
Pentru ca utilizatorul s navigheze uor prin help, sunt disponibile
opiuni de indexare i cutare a cuvintelor cheie. n cazul indexului,
cuvintele cheie sunt desemnate printr-o not de subsol marcat K. Pagina de
index afieaz lista cuvintelor cheie definite pentru fiecare subiect (figura
4.3).

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

84


Figura 4.3. Indexul unui fiier HLP




Figura 4.4. Pagina de cutare ntr-un fiier HLP
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 4. Documentarea unui proiect. Fiiere de ajutor


85
n pagina de cutare Find (figura 4.4), help-ul genereaz automat o
list cu toate cuvintele gsite. Utilizatorul poate introduce un anumit cuvnt,
sau mai multe, i afl n ce pagini apare acesta. Titlurile de subiecte care
apar n lista de jos sunt determinate de o not de subsol marcat cu $ n
fiierul RTF.
Dac se dorete includerea unor imagini, acestea sunt pur i simplu
inserate n fiierul RTF i vor aprea n mod automat i n help.
O alt opiune util este includerea de texte pop-up, n situaii n care
explicarea unui termen sau a unui concept este suficient de scurt i nu
necesit utilizarea unei pagini noi (figura 4.5).



Figura 4.5. Text pop-up ntr-un fiier HLP

Acest format presupune inserarea unui text ascuns n fiierul RTF.
Dac editorul folosit este Microsoft Word, atunci trebuie s activm mai
nti opiunea de vizualizare a informaiilor ascunse, prin combinaia de
taste CTRL+* sau CTRL+SHIFT+8. Textul link va fi subliniat i imediat dup
el va fi introdus un identificator pentru fereastra mic ce va aprea.
Identificatorul va fi scris cu litere ascunse, ceea ce se poate realiza din
meniul Format Font... Hidden. S presupunem c identificatorul se
numete POPUP.
ntr-o alt pagin se va scrie textul care se dorete s apar (n cazul
nostru: Textul apare ntr-o fereastr mic). n faa sa, va fi inserat o not
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

86
de subsol marcat cu #, iar coninutul notei va fi identificatorul menionat
anterior, POPUP.
Pentru realizarea unei legturi la alt pagin, se va sublinia dublu
textul corespunztor legturii, care va fi urmat de identificatorul subiectului
paginii la care se vrea s se sar.


2.2. Crearea de fiiere CHM

Un utilitar gratuit pentru realizarea de fiiere CHM (Compiled
HTML) este HTML Help Workshop (figura 4.6).



Figura 4.6. Microsoft HTML Help Workshop

Ideea care st la baza acestui format este transformarea unui site web
sau a unui grup de pagini HTML ntr-un singur fiier, cu opiuni de navigare
i cutare.
Pentru a realiza un astfel de fiier, trebuie create mai nti paginile
HTML cu informaiile utile. n tab-page-ul Project se apas al doilea buton
din stnga, Add/Remove topic files. Este suficient includerea paginii de
index, de la care se presupune c exist legturi ctre celelalte pagini. Se
creeaz apoi cte un fiier Contents i Index.

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 4. Documentarea unui proiect. Fiiere de ajutor


87



Figura 4.7. Crearea cuprinsului unui fiier CHM




Figura 4.8. Crearea intrrilor de index ale unui fiier CHM

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

88
n tab-page-ul Contents (figura 4.7), se pot insera subiectele
corespunztoare unor anumite pagini. Pentru aceasta se folosesc butoanele
din stnga Insert a heading (un nod n arbore) i Insert a page (o frunz).
n mod analog se definesc i intrri de index, care pot fi asociate cu
una sau mai multe pagini (figura 4.8).
Dac o intrare de index are mai multe pagini asociate, la cutare
rezultatul va fi de forma celui prezentat n figura 4.9.



Figura 4.9. Rezultatele cutrii ntr-un fiier CHM

Pentru generarea automat a opiunii de cutare n lista de cuvinte a
paginilor, se apas primul buton din stnga din tab-page-ul Project, numit
Change project options, iar n pagina Compiler se bifeaz csua Compile
full-text search information.


3. Activarea unui fiier de ajutor prin program

3.1. Process.Start

Cel mai simplu mod de deschidere a unui fiier de ajutor este
printr-un apel la sistemul de operare. n C# apelul este de forma:

System.Diagnostics.Process.Start("nume-fisier");

3.2. HelpProvider

O alt modalitate este utilizarea clasei specializate HelpProvider. Se
introduce n Form un astfel de obiect i apoi din fereastra de proprieti se
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 4. Documentarea unui proiect. Fiiere de ajutor


89
seteaz numele fiierului CHM asociat n cmpul HelpNamespace. Desigur
aceast operaie i cele descrise n continuare pot fi fcute i prin program.
Apoi, pentru fiecare control din fereastr pentru care dorim s apar help-ul
atunci cnd apsm tasta F1, trebuie s modificm urmtoarele proprieti:

Show help on help provider: true;
Help navigator on help provider: locul unde vrem s se deschid
help-ul: la pagina de cuprins, la pagina de index, de cutare sau la o
pagin specificat de programator;
Help keyword on help provider: dac pentru controlul respectiv
avem o anumit pagin care trebuie deschis, Help navigator on help
provider va lua valoarea Topic iar n Help keyword on help provider
se va introduce calea ctre pagina care trebuie deschis, relativ la
fiierul CHM. De exemplu, dac fiierul este obinut prin compilarea
unui director numit web, n care se gsete un document pag1.htm,
care trebuie deschis acum, n acest cmp se va introduce:
web\pag1.htm.


3.3. Help

Pentru activarea unui fiier de ajutor CHM se poate folosi i clasa
Help. Aceasta are un numr de metode statice specifice, precum ShowHelp,
ShowHelpIndex, ShowPopup.
Pentru acelai exemplu de fiier CHM vom avea:

Help.ShowHelp(this, "Exemplu.chm")
o deschide fiierul Exemplu.chm;
Help.ShowHelp(this, "Exemplu.chm", "web/pag1.htm")
o deschide pagina solicitat din acelai fiier;
Help.ShowHelpIndex(this,"Exemplu.chm")
o deschide pagina de index a fiierului Exemplu.chm;
Help.ShowPopup(this, "Pop-up window",
new Point(Cursor.Position.X, Cursor.Position.Y))
o deschide o fereastr de pop-up cu textul dorit la coordonatele
curente ale mouse-ului.



Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

90
4. Generarea automat a documentaiei API

NDoc genereaz documentaie pentru Interfaa de Programare a
Aplicaiei (engl. Application Programming Interface, API) pe baza
assembly-urilor .NET i a fiierelor de documentaie XML generate de
compilatorul C#. NDoc poate genera documentaia n diferite formate,
precum help-ul HTML n stil MSDN, CHM, formatul Visual Studio .NET
(HTML Help 2), sau stilul de pagini web de tip MSDN online.
Documentaia XML se realizeaz automat prin includerea n codul
surs a comentariilor triple: linii care ncep cu /// i care preced un tip
definit de utilizator cum ar fi: namespace-uri, clase, interfee sau membrii
precum cmpuri, metode, proprieti sau evenimente.
Pentru a genera automat fiierul XML, trebuie setat calea ctre
acesta n Project Properties Build Output XML documentation file
(figura 4.10).



Figura 4.10. Generarea automat a unui fiier de documentaie XML



Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 4. Documentarea unui proiect. Fiiere de ajutor


91



Figura 4.11. Utilitarul NDoc


n programul NDoc, se adaug assembly-ul pentru care se va crea
documentaia i se seteaz proprietile proiectului ce anume va fi inclus
n documentaie. De exemplu, o API pentru un utilizator extern nu va
documenta metodele private, deoarece acestea oricum nu vor putea fi
accesate de utilizator. Pentru a genera o referin de uz intern, se pot include
i aceste metode prin setarea proprietii respective.
Tot aici se alege titlul documentaiei i formatul acesteia
(Documentation type). Apoi se apas butonul Build Docs din bara de
instrumente (figura 4.11).
Va rezulta documentaia n formatul ales (figura 4.12).

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

92


Figura 4.12. Documentaie API creat cu NDoc


5. Comentariile

n cele ce urmeaz, se prezint civa pai de baz pentru a
mbunti calitatea comentariilor.

Trebuie s se explice DE CE, nu CUM. Comentariile nu trebuie s
descrie cum lucreaz programul; se poate vedea aceasta citind codul, care
trebuie scris clar i inteligibil. Trebuie n schimb s ne concentrm asupra
explicrii motivelor pentru care s-a scris n acest fel sau ce ndeplinete n
final un bloc de instruciuni.
Trebuie verificat dac se scrie constant actualizarea structurii
StudentList din StRegistry sau memorarea informaiilor despre obiectele
Student pentru a fi folosite mai trziu. Cele dou formulri sunt echivalente,
dar a doua precizeaz scopul codului pe cnd prima spune doar ce face
codul. n timpul ntreinerii acelei pri din cod, motivele pentru care aceasta
exist se vor schimba mult mai rar dect modalitile concrete de
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 4. Documentarea unui proiect. Fiiere de ajutor


93
implementare. ntreinerea celui de-al doilea tip de comentarii este deci mult
mai uoar. Comentariile bune explic de ce, nu cum.
De asemenea, se pot folosi comentarii pentru a explica alegerea unei
anumite implementri. Dac exist dou strategii de implementare posibile
i se opteaz asupra uneia din ele, atunci se pot aduga comentarii pentru a
explica motivele alegerii.

Nu trebuie descris codul. Comentariile descriptive inutile sunt
evidente: ++i; // incrementeaz i. Unele pot s fie mult mai subtile:
comentarii descriptive lungi ale unui algoritm complex, urmat de
implementarea algoritmului. Nu este nevoie s se rescrie laborios codul n
limbaj natural dect dac se documenteaz un algoritm complex care ar fi
altfel impenetrabil. Nu trebuie duplicat codul n comentarii.

Nu trebuie nlocuit codul. Dac exist comentarii care specific
ceva ce s-ar putea aplica prin nsui limbajul de programare, de exemplu
aceast variabil ar trebui accesat doar de ctre clasa A, atunci acest
deziderat trebuie exprimat printr-o sintax concret. Dac ne gsim n
situaia n care scriem comentarii pentru a explica cum lucreaz un algoritm
complex, atunci trebuie s ne oprim. Este bine s documentm codul, dar ar
fi i mai bine dac am putea face codul sau algoritmul mai clar:

Dac se poate, codul trebuie mprit n cteva funcii bine denumite
pentru a reflecta logica algoritmului;
Nu trebuie scrise comentarii care s descrie folosirea unei variabile;
aceasta trebuie redenumit. Comentariile pe care vrem s le scriem
ne spun deseori care ar trebui s fie numele variabilei;
Dac se documenteaz o condiie care ar trebui s fie ntotdeauna
ndeplinit, poate ar trebui s se scrie o aseriune de testare a
unitilor (mai multe detalii se vor vedea n capitolele 13 i 14);
Nu este nevoie de optimizri premature care pot obscuriza codul.

Cnd ne aflm n situaia de a scrie comentarii dense pentru a explica
codul, trebuie sa facem un pas napoi, ntruct s-ar putea s existe o
problem mai mare care trebuie rezolvat.

Codul neateptat trebuie documentat. Dac o parte din cod este
neobinuit, neateptat sau surprinztoare, trebuie documentat cu un
comentariu. Ne va fi mult mai uor mai trziu cnd vom reveni, uitnd totul
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

94
despre problem. Dac exist soluii alternative specifice (workarounds),
acestea trebuie menionate n comentarii.

Comentariile trebuie s fie clare. Comentariile se folosesc
pentru a adnota i explica codul. Acestea nu trebuie sa fie ambigue, ci din
contra, ct mai specifice. Dac o persoan citete comentariile i rmne s
se ntrebe ce nseamn, atunci acestea au sczut calitatea programului i au
afectat nelegerea codului.

Comentariile ajut la citirea codului. Comentariile sunt de
obicei scrise deasupra codului pe care-l descriu, nu dedesubt. n acest fel,
codul surs se citete n jos, aproape ca o carte. Comentariile ajut la
pregtirea cititorului pentru ceea ce urmeaz s vin. Folosite cu spaii
verticale, comentariile ajut la mprirea codului n paragrafe. Un
comentariu introduce cteva linii, explicnd ce se intenioneaz s se obin,
Urmeaz imediat codul, apoi o linie goal, apoi urmtorul bloc. Exist o
convenie: un comentariu cu o linie goal naintea lui apare ca un nceput de
paragraf, n timp ce un comentariu intercalat ntre dou linii de cod apare
mai mult ca o propoziie n paranteze sau o not de subsol.

Comentariile din antetul fiierului. Fiecare fiier surs ar trebui
s nceap cu un bloc de comentarii ce descrie coninutul su. Acesta este
doar o scurt prezentare, o prefa, furniznd cteva informaii eseniale ce
se doresc ntotdeauna afiate de ndat ce este deschis un fiier. Dac exist
acest antet, atunci un programator care deschide fiierul va avea ncredere n
coninut; arat c fiierul a fost creat aa cum trebuie. Funcionalitatea
fiecrui fiier surs trebuie comentat.
Unele persoane susin c antetul ar trebui s furnizeze o list cu toate
funciile, clasele, variabilele globale i aa mai departe, care sunt definite n
fiier. Acesta este un dezastru pentru ntreinere; un astfel de comentariu
devine rapid nvechit. Antetul fiierului trebuie s conin informaii despre
scopul fiierului (de exemplu implementarea interfeei IDocument) i o
declaraie cu drepturile de autor care s descrie proprietarul i regulile de
copiere.
Antet-ul nu trebuie s conin informaii care ar putea deveni uor
nvechite, precum data cnd a fost ultima oar modificat fiierul. Probabil c
data nu ar fi actualizat des i ar induce n eroare. De asemenea, nu trebuie
s conin un istoric al fiierului surs care s descrie toate modificrile
fcute. Dac trebuie s derulezi peste 10 pagini din istoricul modificrilor
pentru a ajunge la prima linie de cod, atunci devine incomod lucrul cu
fiierul. Din acest motiv, unii programatori pun o astfel de list la sfritul
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 4. Documentarea unui proiect. Fiiere de ajutor


95
fiierului. Chiar i aa, acesta poate deveni foarte mare i se va ncrca mai
ncet.

Degradarea comentariilor. Orice cod nentreinut corect tinde s
se degradeze, pierznd din calitatea proiectrii iniiale. Totui, comentariile
tind s se degradeze mult mai repede dect oricare alt parte de cod. Ele i
pot pierde sincronizarea cu codul pe care l descriu i pot deveni profund
suprtoare. Comentariile incorecte sunt mai duntoare dect lipsa
comentariilor: dezinformeaz i induc n eroare cititorul.
Cea mai simpl soluie este aceasta: cnd se repar, adaug sau
modific codul, se repar, adaug sau modific orice comentarii din jurul
su. Nu se modific cteva linii i att. Trebuie s ne asigurm c orice
modificare din cod nu le va transforma n comentarii neadevrate. Corolarul
este urmtorul: trebuie s crem comentarii uor de actualizat, dac nu, ele
nu vor fi actualizate. Comentariile trebuie s fie clar legate de seciunea lor
de cod i nu trebuie plasate n locaii obscure.


6. Lucrul cu fiiere n C#: ncrcare, salvare

Clasele OpenFileDialog i SaveFileDialog afieaz dialoguri de
ncrcare/salvare a fiierelor. Aceste obiecte trebuie apelate din alte
componente, de exemplu, la apsarea unui buton sau la alegerea unei opiuni
dintr-un meniu, va aprea ferestra de dialog. n funcia apelant va trebui
introdus un bloc de tipul:

if (openFileDialog.ShowDialog() != DialogResult.OK) // nu s-a apsat OK
return;

Metoda de mai sus determin afiarea dialogului. Dac aceasta se
execut corect (utilizatorul a ales un fiier), este disponibil proprietatea
open/saveFileDialog.FileName, care conine numele fiierului dorit (cale
complet i nume).
Cteva proprieti:

open/saveFileDialog.DefaultExt extensia ataat n mod automat
fiierului;
open/saveFileDialog.Filter dialogul de selecie de fiiere include un
combo-box cu tipurile fiierelor. Cnd utilizatorul alege un tip de
fiier din list, numai fiierele de tipul selectat sunt afiate n dialog.
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

96
Filter poate fi setat n Properties sau n codul surs, n formatul:
"Text Files (*.txt)|*.txt|All Files (*.*)|*.*";
open/saveFileDialog.InitialDir directorul implicit unde se deschide
dialogul. Poate fi de exemplu MyDocuments, dac aceast
proprietate nu este specificat. Pentru directorul n care se afl
programul, se folosete . .

n continuare, se vor defini nite stream-uri pentru fiiere. De
exemplu:

StreamWriter sw = new StreamWriter(saveFileDialog.FileName);
// operaii cu sw
// de exemplu scriem n fiier un numr n cu 3 zecimale
sw.WriteLine("Numarul este {0:F3}", n);
sw.Close();

Pentru lucrul cu fiiere trebuie inclus namespace-ul System.IO.


7. Aplicaii

7.1. Realizai o interfa grafic pentru desenarea unui ptrat magic
(figura 4.13), cu ajutorul clasei MagicBuilder, prezentat n continuare.


Figura 4.13. Exemplu de rezolvare


Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 4. Documentarea unui proiect. Fiiere de ajutor


97
/**************************************************************************
* *
* File: MagicBuilder.cs *
* Copyright: (c) 2003, A. Riazi *
* Website: http://www.codeproject.com/KB/recipes/Magic_Square.asp *
* Description: Calculates magic squares of any size. *
* Translated into C# and adapted by Florin Leon *
* http://florinleon.byethost24.com/lab_ip.htm *
* *
* This code and information is provided "as is" without warranty of *
* any kind, either expressed or implied, including but not limited *
* to the implied warranties of merchantability or fitness for a *
* particular purpose. You are free to use this source code in your *
* applications as long as the original copyright notice is included. *
* *
**************************************************************************/

using System;
using System.Collections.Generic;

namespace MagicSquare
{
public class MagicBuilder
{
private int[,] _matrix;
private int _size;

public MagicBuilder(int size)
{
_size = size;
_matrix = new int[size, size];
}

public int[,] BuildMagicSquare()
{
if (_size < 1 || _matrix == null)
throw new Exception("Dimensiune incorecta");
MagicSquare(_matrix, _size);
return _matrix;
}

private void MagicSquare(int[,] matrix, int n)
{
if (n % 2 == 1)
OddMagicSquare(matrix, n);
else
{
if (n % 4 == 0)
DoublyEvenMagicSquare(matrix, n);

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

98
else
SinglyEvenMagicSquare(matrix, n);
}
}

private void OddMagicSquare(int[,] matrix, int n)
{
int nsqr = n * n;
int i = 0, j = n / 2;

for (int k = 1; k <= nsqr; ++k)
{
matrix[i, j] = k;

i--;
j++;

if (k % n == 0)
{
i += 2;
--j;
}
else
{
if (j == n)
j -= n;
else if (i < 0)
i += n;
}
}
}

private void DoublyEvenMagicSquare(int[,] matrix, int n)
{
int[,] mat1 = new int[n, n];
int[,] mat2 = new int[n, n];

int i, j;

int index = 1;
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
{
mat1[i, j] = ((i + 1) % 4) / 2;
mat2[j, i] = ((i + 1) % 4) / 2;
matrix[i, j] = index;
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 4. Documentarea unui proiect. Fiiere de ajutor


99
index++;
}

for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
{
if (mat1[i, j] == mat2[i, j])
matrix[i, j] = n * n + 1 - matrix[i, j];
}
}

private void SinglyEvenMagicSquare(int[,] matrix, int n)
{
int p = n / 2;

int[,] mat = new int[p, p];
MagicSquare(mat, p);

int i, j, k;

for (i = 0; i < p; i++)
for (j = 0; j < p; j++)
{
matrix[i, j] = mat[i, j];
matrix[i + p, j] = mat[i, j] + 3 * p * p;
matrix[i, j + p] = mat[i, j] + 2 * p * p;
matrix[i + p, j + p] = mat[i, j] + p * p;
}

if (n == 2)
return;

int[] mat1 = new int[p];
List<int> vect = new List<int>();

for (i = 0; i < p; i++)
mat1[i] = i + 1;

k = (n - 2) / 4;

for (i = 1; i <= k; i++)
vect.Add(i);

for (i = n - k + 2; i <= n; i++)
vect.Add(i);

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

100
int temp;
for (i = 1; i <= p; i++)
for (j = 1; j <= vect.Count; j++)
{
temp = matrix[i - 1, vect[j - 1] - 1];
matrix[i - 1, vect[j - 1] - 1] = matrix[i + p - 1, vect[j - 1] - 1];
matrix[i + p - 1, vect[j - 1] - 1] = temp;
}

i = k;
j = 0;
temp = matrix[i, j]; matrix[i, j] = matrix[i + p, j]; matrix[i + p, j] = temp;

j = i;
temp = matrix[i + p, j]; matrix[i + p, j] = matrix[i, j]; matrix[i, j] = temp;
}
}
}

Indicaii: Un ptrat magic este o matrice ptratic de dimensiune ,
care conine numerele ntregi din intervalul

i n care suma
elementelor pe linii, coloane i diagonale este aceeai.
Pentru salvarea graficului, trebuie s se foloseasc un obiect de tip
Bitmap, care dispune de funcii de salvare/ncrcare a imaginilor. Deoarece
obiectul Bitmap va fi folosit att pentru desenarea ntr-un PictureBox ct i
pentru salvarea imaginii ntr-un eveniment de apsare a unui buton, va
trebui s avem un cmp n clas, instaniat n constructorul ferestrei:

private Bitmap _bmp;

public void MainForm()
{
InitializeComponent();

// n constructorul ferestrei, dup metoda InitializeComponent();
_bmp = new Bitmap(pictureBox.Width, pictureBox.Height);
}

Desenarea n Bitmap trebuie pus n legtur cu suprafaa de
desenare a ferestrei din PictureBox. Atunci, n evenimentul Paint al acesteia,
vom avea o secven de cod de forma:


Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 4. Documentarea unui proiect. Fiiere de ajutor


101
Graphics g = Graphics.FromImage(_bmp);

// n continuare, desenarea se va face n g (n Bitmap)
g.Clear(Color.White);
...

// la sfrit, vom desena coninutul bitmap-ului n picture-box
e.Graphics.DrawImage(_bmp, 0, 0);

Salvarea imaginii din Bitmap se va face n evenimentul Click al unui
buton:

_bmp.Save(saveFileDialog.FileName, System.Drawing.Imaging.ImageFormat.Png);

Cu linia de cod de mai sus, imaginea va fi salvat n format png.


7.2. Creai un fiier HLP sau un fiier CHM pentru programul
Ptratul magic.

Indicaie: Cu ajutorul componentei HelpProvider se poate afia un
help bazat pe context, de exemplu pentru text-box-urile corespunztoare
dimensiunii ptratului i sumei caracteristice.


7.3. Creai o documentaie API pentru clasa MagicBuilder folosind
programul NDoc. Comentariile triple trebuie introduse cu o linie mai sus de
prima linie a clasei, cmpului sau metodei comentate.

Exemple:

/// <summary>
/// Clasa pentru construirea unui ptrat magic
/// </summary>
public class MagicBuilder
...

/// <summary>
/// Constructorul clasei pentru ptratul magic
/// </summary>
/// <param name="size">Dimensiunea ptratului</param>
public MagicBuilder(int size)
...
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

102
/// <summary>
/// Metoda care returneaz ptratul construit
/// </summary>
/// <returns>Matricea corespunztoare ptratului magic</returns>
public int[,] BuildMagicSquare()
...



7.4. Opional. Realizai un program de generare a unui antet cu
informaii pentru un fiier de cod surs C# (figurile 4.14 i 4.15).


Figura 4.14. Program generator de antete


Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 4. Documentarea unui proiect. Fiiere de ajutor


103

Figura 4.15. Antet generat pentru un fiier surs



Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

104

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com


105

Capitolul 5

Diagrame UML

1. Obiective
2. Diagrame principale ale UML
3. Altova UModel
4. Aplicaii

1. Obiective

Limbajul Unificat de Modelare (engl. Unified Modeling
Language, UML) este un limbaj pentru specificarea, vizualizarea,
construirea i documentarea elementelor sistemelor software. Este un
standard de facto pentru modelarea software. Obiectivele capitolului 5 sunt
urmtoarele:

1. Prezentarea celor mai importante tipuri de diagrame UML 2.0;
2. Introducerea programului Altova UModel pentru desenarea
diagramelor UML:
a. Utilizarea diagramei de clase pentru generarea automat de
cod C#;
b. Generarea automat a diagramei de clase pe baza codului
surs C#;
c. Desenarea unor diagrame de cazuri de utilizare, clase,
activiti i secvene.


2. Diagrame principale ale UML

2.1. Diagrama cazurilor de utilizare

O diagram de nivel nalt util n multe situaii este diagrama
cazurilor de utilizare, care descrie mulimea de interaciuni dintre utilizator
i sistem. Prin construirea unei colecii de cazuri de utilizare, putem descrie
ntregul sistem ntr-o manier clar i concis. Cazurile de utilizare sunt
denumite de obicei printr-o combinaie verb-substantiv, de exemplu:
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

106
Pltete factura, Creeaz cont etc. Notaia pentru un caz de utilizare este
prezentat n figura 5.1.


Figura 5.1. Caz de utilizare

Un caz de utilizare trebuie s aib un iniiator al aciunii, numit
actor. n cazul unui sistem bancar, retragerea banilor este fcut de clieni,
astfel nct clientul devine unul din actori (figura 5.2).


Figura 5.2. Caz de utilizare cu actor

Actorii nu sunt numai oameni, ci orice cauz extern care iniiaz un
caz de utilizare, de exemplu un alt sistem de calcul sau un concept mai
abstract, precum timpul, de exemplu n ultima zi a lunii se actualizeaz
statele de salarii. Pentru majoritatea sistemelor, un anumit actor poate
interaciona cu mai multe cazuri de utilizare, iar un anumit caz de utilizare
poate fi iniiat de actori diferii (figura 5.3).


Figura 5.3. Cazuri de utilizare cu actori multipli
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 5. Diagrame UML


107
2.2. Diagrama de clase

Modelarea conceptual (numit i modelarea domeniului) este
activitatea de identificare a conceptelor importante pentru sistem. n cazul
proiectrii orientate obiect, modelarea conceptual se realizeaz prin
diagrama claselor, ntruct clasele reprezint concepte. Diagrama claselor
furnizeaz structura codului care urmeaz s fie scris. Problema principal
este identificarea conceptelor. Regula de urmat aici este: dac clientul nu
nelege conceptul, probabil c nu este un concept.
O clas se reprezint printr-o csu mprit n trei (figura 5.4). n
partea de sus este notat numele clasei, n partea median sunt incluse
atributele (cmpurile) iar n partea de jos operaiile (metodele) sale.


Figura 5.4. O clas n notaia UML

n figura 5.5 sunt prezentate notaiile pentru vizibilitatea atributelor
i operaiilor (private, protejate, publice).


Figura 5.5. Vizibilitatea atributelor i operaiilor


2.2.1. Dependena

Relaia de dependen apare cnd o clas folosete pentru scurt timp
o alt clas, de exemplu trimiterea unui mesaj (apelarea din clasa A a unei
metode din clasa B) sau trimiterea ca parametru ntr-o metod a clasei A a
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

108
unui obiect de tip B. n C#, un exemplu este clasa Math, ale crei metode
statice sunt apelate punctual de obiectele altor clase. Se noteaz cu linie
punctat cu o sgeat (figura 5.6).


Figura 5.6. Relaia de dependen


2.2.2. Asocierea

Linia simpl n UML are rolul de asociere: o clas A are un cmp
instaniat din cealalt clas B. Numerele descriu cardinalitatea asocierii,
adic ne spun cte instane sunt permise din fiecare clas. Figura 5.7
prezint cteva cardinaliti posibile, dei din punct de vedere al notaiei nu
exist restricii asupra cardinalitilor care pot fi specificate.


Figura 5.7. Cardinaliti

O greeal pe care o putem face n faza de analiz este s trasm o
linie ntre dou clase, dar s nu notm numele asocierii. Dup ce vom trasa
toate liniile, nu vom mai ti ce nseamn fiecare.
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 5. Diagrame UML


109
n figura 5.8 este prezentat un exemplu de asociere ntre clase,
corespunztor fazei de analiz.


Figura 5.8. Asociere mai complex

Asocierile de mai sus sunt bidirecionale. ntr-o asociere
unidirecional, cele dou clase sunt nrudite, dar numai o clas tie c exist
relaia respectiv. n situaia din figura 5.9, managerul tie despre adres,
dar adresa nu tie despre manager.


Figura 5.9. Asociere unidirecional









Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

110
2.2.3. Agregarea i compunerea

n cazul agregrii, un obiect este construit din altele. De exemplu, un
calculator este o agregare ntre procesor, plac video, plac de sunet etc.
(figura 5.10).


Figura 5.10. Relaia de agregare

Compunerea este un concept similar cu agregarea, ns mai puternic,
deoarece implic faptul c ntregul nu poate exista fr pri. n exemplul de
agregare de mai sus, dac se nltur placa de sunet, calculatorul rmne
calculator. ns o carte nu poate exista fr pagini; o carte este compus din
pagini. Notaia este asemntoare, dar rombul este plin (figura 5.11).


Figura 5.11. Relaia de compunere


2.2.4. Motenirea

De multe ori, mai multe clase au atribute i operaii comune. Acestea
pot fi introduse ntr-o singur clas i motenite n celelalte, de exemplu
clasele din figura 5.12.
Dac am mai vrea s adugm o clas Pisic, ar trebui s repetm
atributele i operaiile comune. Soluia este motenirea dintr-o clas mai
general.
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 5. Diagrame UML


111

Figura 5.12. Clase cu potenial de generalizare

Notaia UML pentru motenire (generalizare) este cea din figura 5.13.


Figura 5.13. Relaia de motenire

Trebuie s subliniem faptul c atributul vrst a fost transformat din
privat n protejat, pentru a putea fi accesat n clasele derivate.







Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

112
2.2.5. Metode abstracte i virtuale

Clasele derivate pot redefini implementarea unor metode. n
exemplul urmtor, clasele Lup, Pete i AltAnimal sunt derivate din clasa
Animal, ns primele dou reimplementeaz metoda Mnnc n modul lor
specific. Notaia n acest caz este cea din figura 5.14.


Figura 5.14. Notaia pentru metode virtuale

Cuvintele introduse ntre << i >> se numesc stereotipuri.
De multe ori avem nevoie s lsm o metod neimplementat ntr-o
clas (metod abstract) i s o implementm pe un nivel mai de jos al
ierarhiei. Clasele i metodele abstracte se noteaz cu italice (figura 5.15).


Figura 5.15. Notaia pentru clase i metode abstracte





Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 5. Diagrame UML


113
2.2.6. Interfee

S presupunem c InstrumentMuzical din exemplul precedent e
acum o interfa iar clasele Pian i Vioar trebuie s implementeze metoda
Cnt. Notaia este asemntoare celei de la motenirea de clase, dar cu linie
punctat, iar interfaa poate fi declarat explicit cu un stereotip (figura 5.16).


Figura 5.16. Notaia pentru interfee


2.2.7. Trsturi statice

n notaia UML, trsturile (atributele/cmpurile i
operaiile/metodele) statice se subliniaz, ca n figura 5.17.


Figura 5.17. Notaia pentru trsturi statice







Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

114
2.3. Diagrame de activiti

Diagramele de activiti sunt folosite pentru modelarea proceselor
sau a algoritmilor din spatele unui anumit caz de utilizare. Notaia este
urmtoarea:

nod iniial: un cerc plin; este punctul de start al diagramei;
nod final: un cerc plin nconjurat de un alt cerc; o diagram poate
avea 0, 1 sau mai multe noduri finale;
aciuni: dreptunghiurile rotunjite reprezint paii activi executai n
cadrul procesului;
arce: sgeile diagramei;
punct final al fluxului: un cerc cu un X n interior; indic faptul c
procesul se oprete n acest punct;
ramificaie (engl. fork): o bar neagr cu un flux de intrare i mai
multe fluxuri de ieire; denot nceputul unor activiti desfurate n
paralel;
reunire (engl. join): o bar neagr cu mai multe fluxuri de intrare
i un flux de ieire; denot sfritul prelucrrilor paralele;
condiie: text asociat unui flux care definete o propoziie cu o
valoare de adevr i care trebuie s fie adevrat pentru continuarea
execuiei;
decizie: un romb cu un flux de intrare i mai multe fluxuri de ieire;
fluxurile de ieire includ condiii;
mbinare (engl. merge): un romb cu mai multe fluxuri de intrare i
un flux de ieire; toate fluxurile de intrare trebuie s ating acest
punct pentru ca procesul s continue;
partiie sau culoar (engl. partition / swimlane): o parte a diagramei
care indic cine ndeplinete aciunile;
not: un comentariu care poate aduce informaii suplimentare
privind scopul, utilizarea sau constrngerile unei entiti.

n figura 5.18 este prezentat o diagram de activiti cu decizii.
Candidatul trebuie s fie admis este o not asociat unei decizii.

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 5. Diagrame UML


115

Figura 5.18. Diagram de activiti cu decizii


n figura 5.19 este prezentat o alt diagram de activiti, cu partiii
i ramificaii.

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

116

Figura 5.19. Diagram de activiti cu partiii i ramificaii
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 5. Diagrame UML


117
2.4. Diagrama de secvene

Diagrama de secvene pune accentul pe aspectul temporal (ordonarea
mesajelor). Notaia grafic este un tabel care are pe axa X obiecte, iar pe axa
Y mesaje ordonate cresctor n timp. Axa Y arat pentru fiecare obiect
timpul ca o linie vertical punctat, numit linia vieii unui obiect (engl.
lifeline) i perioada n care obiectul deine controlul execuiei
(reprezentat printr-un dreptunghi) i efectueaz o aciune, direct sau prin
intermediul procedurilor subordonate.
n figura 5.20 este descris interaciunea dintre doi abonai ai unei
reele de telefonie. De remarcat c n diagrama de secvene utilizm obiecte,
nu clase. ntr-un program pot exista mai multe instane ale aceleiai clase
care au roluri diferite n sistem. Un obiect este identificat de numele su i
numele clasei pe care o instaniaz. Numele obiectului poate s lipseasc
dac nu este semnificativ pentru nelegerea comportamentului sistemului.
Liniile orizontale continue semnific mesaje iniiate de obiecte, iar liniile
orizontale punctate reprezint mesaje-rspuns.


Figura 5.20. Diagram de secvene


Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

118
3. Altova UModel

Altova UModel este un instrument vizual pentru crearea de diagrame
UML. Poate genera cod Java, C# i Visual Basic .NET pe baza diagramelor
i poate s realizeze diagrame UML ale programelor existente. Este posibil
de asemenea ajustarea codului existent prin modificarea diagramelor
corespunztoare.
Fiecare tip de diagram are o bar de instrumente corespunztoare cu
elementele UML caracteristice, care pot fi introduse n fereastra de
desenare, conectate i modificate (figura 5.21).


Figura 5.21. Diagramele UML n Altova UModel







Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 5. Diagrame UML


119
3.1. Diagrama de clase

Proprietile (cmpurile) i operaiile (metodele) unei clase pot fi
adugate mai rapid cu ajutorul tastelor F7, respectiv F8. Din bara de
instrumente sau din conectorii dreptunghiului asociat clasei se creeaz
tipurile de legturi dintre clase, de exemplu asociere, motenire etc.
Membrii unei clase pot fi redenumii direct pe diagram sau din fereastra
Model Tree.
Implicit, diagramele au vizibilitatea marcat grafic iar clasele au
prima csu colorat cu un gradient. Aspectul vizual al diagramelor poate fi
configurat folosind stilurile: View Styles. De exemplu, diagrama din
figura 5.22 sus este echivalent cu cea de jos, eliminnd gradientul i
marcnd proprietatea Show Visibility drept UML Style n loc de UModel
Style. Alte proprieti utile sunt: Show Namespace, Show Stereotypes.




Figura 5.22. Diagrame de clase cu diferite stiluri






Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

120
3.1.1. Generarea de cod

Pentru a genera cod (C#) pe baza unei diagrame de clase, trebuie mai
nti creat un pachet care va conine clasele. n Model Tree, click dreapta pe
Root, New Element Package. Pe acest pachet trebuie aplicat profilul
limbajului dorit pentru generare: click dreapta pe pachetul creat, Code
Engineering Set as C# Namespace Root.
n pachet se introduce apoi o diagram de clase i se adaug clasele.
Tipurile proprietilor se pot completa din lista de tipuri din modelul
ales, la apsarea : dup numele proprietii (figura 5.23).


Figura 5.23. Tipurile proprietilor

Analog, pentru operaii se vor aduga parametrii i tipul de return
(figura 5.24). Numele parametrilor sunt precedate de cuvintele cheie in
(parametru normal), out (parametru out), inout (parametru ref).


Figura 5.24. Parametrii i tipul de return pentru operaii
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 5. Diagrame UML


121
Pentru o clas se pot aduga automat accesori prin click dreapta,
Create getter/setter Operations... (figura 5.25).




Figura 5.25. Adugarea de accesori

Caracteristicile specifice ale unei operaii se pot introduce din
fereastra Properties, de exemplu cu stereotipurile <<constructor>>,
<<virtual>>, <<abstract>>, <<override>> etc. (figura 5.26).


Figura 5.26. Adugarea de stereotipuri

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

122
Trebuie precizat faptul c aceste stereotipuri devin disponibile doar
dup crearea unui pachet setat ca C# Namespace Root, n care au fost
adugate clasele.
Vizibilitatea membrilor se poate seta de asemenea apsnd pe
imaginea din stnga numelui sau din fereastra Properties.
Se finalizeaz diagrama de clase (figura 5.27), care se poate exporta
i ca imagine din File Save Diagram As Image...



Figura 5.27. Diagram de clase cu asociere i motenire



Figura 5.28. Adugarea unui component
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 5. Diagrame UML


123
Pentru generarea efectiv a codului, mai trebuie adugat un
component n proiect, deoarece numai un astfel de element conine n
viziunea UML codul propriu-zis pentru implementare: click dreapta pe
Root, New Element Component. Dup crearea componentului, se trag
(drag and drop) clasele din diagrama de clase n component. Automat se
creeaz nite relaii de realizare (figura 5.28).
Pentru component mai trebuie specificate n fereastra Properties
limbajul de programare dorit i calea ctre directorul unde se vor genera
fiierele surs (figura 5.29).


Figura 5.29. Proprietile componentului

Apoi se face click dreapta pe numele componentului (aici
MyComponent), Code Engineering Override Program Code from
UModel Component... (figura 5.30).


Figura 5.30. Setrile pentru sincronizare

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

124
Scheletul de program generat pentru exemplul de mai sus este
urmtorul:

public class ClassA
{
protected int _propInt;

public virtual void OperationA1(int a, out int b, ref int c)
{
}

public int OperationA2()
{
}
}

public class ClassB : ClassA
{
private int _propertyB1;
private ClassC _propertyB2;

public bool OperationB1()
{
}
}

public class ClassC
{
private double _propertyC;

public int OperationC()
{
}

public double PropertyC
{
set { }
get { }
}
}





Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 5. Diagrame UML


125
3.1.2. Crearea diagramei unui proiect existent

Importarea de cod pentru crearea diagramei de clase este destul de
simpl (figura 5.31); se alege Project Import Source Directory... pentru a
prelua fiierele surs din directorul specificat (posibil recursiv) sau Project
Import Source Project... pentru importarea unei soluii Visual Studio
(fiierul sln).


Figura 5.31. Setrile pentru generarea unei diagrame din cod

Dac se import codul generat anterior, se observ c UModel
afieaz automat relaiile de generalizare (motenire) dar nu i pe cele de
asociere (sau agregare/compunere). Acestea pot fi indicate n diagram prin
click dreapta pe un cmp i alegerea opiunii de afiare ca asociere (figura
5.32).
Relaiile de dependen nu apar automat, ns ntr-o diagram nu
trebuie s existe clase izolate. Ar nsemna c acestea nu sunt utilizate deloc
i atunci nu se justific prezena lor.

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

126

Figura 5.32. Afiarea unei proprieti ca asociere

S considerm urmtorul program:

namespace Dependency
{
public class A
{
public static int Add(int a, int b)
{
return a + b;
}
}

public class B
{
private int _x, _y;
private int _sum;


Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 5. Diagrame UML


127
public int Sum
{
get { return _sum; }
}

public B(int x, int y)
{
_x = x; _y = y;
_sum = A.Add(_x, _y);
}
}

class Program
{
static void Main(string[] args)
{
B b = new B(1, 2);
Console.WriteLine(b.Sum);
}
}
}

La importarea sa, diagrama UModel este cea din figura 5.33.


Figura 5.33. Clasele importate
n acest caz, relaiile de dependen ntre Program i B, respectiv
ntre B i A trebuie trasate manual (figura 5.34).



Figura 5.34. Adugarea relaiilor de dependen
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

128
3.1.3. Aranjarea automat a elementelor din diagrame

O funcionalitate foarte util este dispunerea automat a elementelor
n fereastr (click dreapta n fereastr, Autolayout All Force Directed sau
Hierarchical).


3.2. Celelalte diagrame

Prin click dreapta pe Root, New Diagram pot fi introduse n proiect
orice diagrame UML, iar n bara de meniuri apar elementele UML specifice
tipului respectiv de diagram.


4. Aplicaii

4.1. Generai fiiere de cod C# dintr-o diagram de clase (se poate
urmri exemplul prezentat mai sus).

4.2. Realizai diagrama de clase a unui proiect C# prin importare.

4.3. Desenai diagramele din figurile: 5.3, 5.6, 5.8, 5.10, 5.11, 5.15,
5.16, 5.17, 5.18, 5.19 i 5.20.

Indicaie: Notaiile pot fi particularizate prin modificarea
proprietilor elementelor, de exemplu modificarea tipului implicit de
asociere (figura 5.35).


Figura 5.35. Modificarea tipului de asociere
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 5. Diagrame UML


129
4.4. Tem pentru acas. Desenai diagrama de activiti i diagrama
de secvene pentru un proiect C# la alegere.
Diagrama de secvene trebuie realizat manual la un nivel mai nalt,
nu diagrama realizat automat de versiunile recente ale UModel, n care
reprezentarea este la nivel de linie de cod. Diagramele astfel rezultate sunt
prea complexe pentru a fi nelese.
Diagramele trebuie exportate i n format imagine, de preferin png.


Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

130

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com


131

Capitolul 6

Arhitectura MVC

1. Obiective
2. Introducere. Arhitectura cu trei straturi
3. Arhitectura MVC
4. Arhitectura MVP
5. Aplicaii

1. Obiective

Obiectivul principal al acestui capitol este implementarea unui
program dup ablonul arhitectural Model-Vizualizare-Prezentator (engl.
Model-View-Presenter, MVP), o variant a arhitecturii clasice Model-
Vizualizare-Controlor (engl. Model-View-Controller, MVC).
Ca obiective detaliate, vom avea:

1. Obiective de proiectare: particularizarea arhitecturii MVP pentru o
aplicaie cu interfa de tip consol, subliniind faptul c arhitectura
este independent de tipul interfeei cu utilizatorul;
2. Obiective de programare: realizarea unui meniu consol structurat pe
niveluri;
3. Obiective diverse: calcularea distanei ntre dou puncte de pe
suprafaa Pmntului definite de coordonatele lor geografice.


2. Introducere. Arhitectura cu trei straturi

Una din recomandrile de baz ale ingineriei programrii este
structurarea arhitecturii unei soluii pe niveluri, adic mprirea sistemului
n mai multe componente ordonate ierarhic, fiecare cu limitri legate de
modul de interaciune.
Din punct de vedere al terminologiei, se folosete strat (engl.
tier) pentru a indica o separare fizic a componentelor, adic assembly-uri
(dll, exe) diferite pe aceeai main sau pe maini diferite. Termenul de
nivel (engl. layer) indic o separare logic a componentelor, de exemplu
namespace-uri diferite.
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

132
O abordare simpl i des ntlnit este utilizarea unei arhitecturi cu
dou straturi (engl. two-tier architecture). n acest caz, aplicaia separ
stratul de prezentare de stratul datelor aplicaiei. Datele reprezint entitile
care definesc problema i de obicei corespund unor tabele n baze de date.
Clasele de prezentare au responsabiliti precum recepionarea intrrilor de
la utilizator (texte introduse, apsarea unor butoane, alegerea unor opiuni
din meniuri etc.), apelurile ctre stratul de date, deciziile privind informaiile
care vor fi artate utilizatorului i afiarea ieirilor (texte, grafice etc.).
Aceste responsabiliti sunt destul de numeroase i, pe msur ce sistemul
evolueaz, stratul de prezentare poate deveni suprancrcat.
O soluie natural este divizarea acestui strat prea extins n dou alte
straturi: de prezentare, pentru preluarea intrrilor i afiarea ieirilor, i
respectiv de logic a aplicaiei, pentru asigurarea comunicaiilor cu stratul
de acces la date i pentru luarea deciziilor de control. Stratul de logic
include toate prelucrrile efective care manipuleaz datele interne i pe cele
ale utilizatorului, cu ajutorul algoritmilor specifici, pentru a controla fluxul
aplicaiei.
Figura 6.1 prezint comparativ arhitecturile cu dou i trei straturi.


Figura 6.1. Arhitectura cu dou straturi (stnga).
Arhitectura cu trei straturi (dreapta)



Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 6. Arhitectura MVC


133
3. Arhitectura MVC

Arhitectura cu dou straturi, n care se consider c schimbul de
informaii are loc ntre interfaa cu utilizatorul i bazele de date (sau n
general orice modalitate de stocare a datelor, inclusiv fiiere text, xml etc.)
presupune ca din interfa s se acceseze i s se modifice direct datele.
Totui, aceast abordare are cteva probleme semnificative. n
primul rnd, interfaa cu utilizatorul se schimb de obicei mai des dect baza
de date. n al doilea rnd, majoritatea aplicaiilor conin cod funcional
(logica) ce realizeaz prelucrri mult mai complexe dect simpla transmitere
de date.
ablonul arhitectural Model-Vizualizare-Controlor izoleaz interfaa,
codul funcional i datele, astfel nct modificarea unuia din aceste trei
componente s nu le afecteze pe celelalte dou. O aplicaie bazat pe
ablonul MVC va avea trei module corespunztoare:

1. Model: conine datele, starea i logica aplicaiei. Dei nu cunoate
Controlorul i Vizualizarea, furnizeaz o interfa pentru manipularea
i preluarea strii i poate trimite notificri cu privire la schimbarea
strii. De obicei primete cereri privind starea datelor de la
Vizualizare i instruciuni de modificare a datelor sau strii de la
Controlor;
2. Vizualizare: afieaz Modelul ntr-o form potrivit pentru
utilizator. Pentru un sigur Model pot exista mai multe Vizualizri, de
exemplu o list de elemente poate fi afiat ntr-un control vizual
precum ListBox, ntr-o consol sau ntr-o pagin web;
3. Controlor: primete intrrile de la utilizator i apeleaz obiectele
Modelului pentru a prelucra noile informaii.

Exist mai multe variante ale arhitecturii MVC, ns n general fluxul
de control este urmtorul:

1. Utilizatorul interacioneaz cu interfaa aplicaiei, iar Controlorul
preia intrarea i o interpreteaz ca pe o aciune ce poate fi
recunoscut de ctre Model;
2. Controlorul trimite Modelului aciunea utilizatorului, ceea ce poate
conduce la schimbarea strii Modelului;
3. n vederea afirii rezultatului de ctre Vizualizare, Controlorul i
poate trimite acesteia o cerere de actualizare, sau Modelul i trimite o
notificare privind schimbarea strii sale;
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

134
4. Vizualizarea preia datele necesare din Model i le afieaz.

n continuare, aplicaia ateapt o nou aciune a utilizatorului iar
ciclul se reia.
Trebuie precizat c Modelul nu este doar o baz de date, ci
ncapsuleaz i logica domeniului necesar pentru manipularea datelor din
aplicaie. De multe ori se folosete i un mecanism de stocare persistent a
acestora, de exemplu ntr-o baz de date, ns arhitectura MVC nu
menioneaz explicit stratul de acces la date; acesta se consider implicit ca
parte din Model.
Figura 6.2 prezint relaiile structurale ntre cele trei module.


Figura 6.2. Relaiile structurale ntre componentele arhitecturii MVC

Pentru o aplicaie mai simpl, aceste module pot reprezenta clase.
Din punctul de vedere al implementrii, sgeile de asociere nseamn c:

Vizualizarea va avea un cmp de tip Model; de obicei va primi ca
parametru n constructor o referin la obiectul Model;
Controlorul va avea dou cmpuri de tip Vizualizare i Model; de
obicei va primi ca parametri n constructor referine la obiectele
Vizualizare i Model.

Mai ales n aplicaiile web, este clar definit separaia dintre
Vizualizare (browser-ul) i Controlor (componentele server care rspund
cererilor http).
Prin separarea celor trei funcionaliti se atinge o cuplare slab ntre
module, caracteristic dorit n toate programele deoarece modificrile
dintr-o seciune a codului nu necesit modificri i n alte seciuni.
Decuplarea scade complexitatea proiectrii i crete flexibilitatea i
potenialul de reutilizare.

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 6. Arhitectura MVC


135
Avantajele principale ale ablonului MVC sunt urmtoarele:

Modificri rapide. Clasele ablonului trebuie doar s implementeze
nite interfee prestabilite, astfel nct acestea s cunoasc metodele
pe care le pot apela n celelalte clase. Cnd se doresc modificri, nu
trebuie rescris o clas, se poate implementa una nou i se poate
utiliza direct, chiar alturi de una veche. De asemenea, Vizualizrile
i Modelele existente pot fi refolosite pentru alte aplicaii cu un
Controlor diferit.
Modele de date multiple. Modelul nu depinde de nicio alt clas
din ablon. Datele pot fi stocate n orice format: text, xml sau baze de
date Access, Oracle, SQL Server etc.;
Interfee multiple. Deoarece Vizualizarea este separat de Model,
pot exista n aplicaie mai multe tipuri de Vizualizri ale acelorai
date. Utilizatorii pot alege mai multe scheme de afiare: mai multe
skin-uri sau comunicarea n mai multe limbi. Aplicaia poate fi
extins uor pentru a include moduri de vizualizare complet diferite:
consol, interfa grafic cu utilizatorul n ferestre (desktop),
documente web sau pentru PDA-uri.


4. Arhitectura MVP

n abordarea clasic, descris de Trygve Reenskaug pe cnd lucra la
limbajul Smalltalk la Xerox PARC (1978-1979), logica este n Model, iar
Controlorul gestioneaz intrrile de la utilizator.
Pentru aplicaiile de tip consol, este relativ simplu ca intrrile s fie
preluate de Controlor iar afiarea s se fac de ctre Vizualizare, pe baza
datelor din Model. Pentru aplicaiile moderne, cu interfee grafice cu
utilizatorul (GUI) precum ferestrele Windows, clasele de vizualizare sunt
cele care primesc intrrile utilizatorului. De aceea, n astfel de situaii,
Vizualizarea i Controlorul nu mai sunt clar delimitate.
n Cocoa (unul din mediile de dezvoltare de aplicaii orientate obiect
native ale Apple pentru Mac OS X) i DDay.MVC (proiectul DDay
reprezint o colecie de biblioteci open-source pentru tehnologiile .NET),
Controlorul conine logica aplicaiei.
Pentru a rspunde noilor realiti ce privesc interaciunea
utilizatorilor cu interfeele aplicaiilor, a fost propus ablonul Model-
Vizualizare-Prezentator, MVP. Aici, stratul de prezentare const n obiecte
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

136
de Vizualizare iar logica aplicaiei const n obiecte de control
(Prezentator/Controlor). Pentru fiecare obiect de vizualizare exist un
obiect de control.
Din punct de vedere al terminologiei, se poate utiliza termenul de
Controlor pentru Prezentator n ablonul MVP, deoarece acesta poate fi
considerat o variant modern a ablonului clasic MVC.
Dei ambele abloane, MVC i MVP, se bazeaz pe principiul comun
al arhitecturii cu trei straturi, acestea au dou diferene majore:

1. n MVC, Controlorul primete i prelucreaz intrrile de la utilizator
iar n MVP, Vizualizarea primete intrrile i apoi deleag
prelucrrile ctre Controlorul corespunztor;
2. n MVC, Vizualizarea primete notificri privind schimbrile
Modelului i afieaz noile informaii pentru utilizator. n MVP,
Controlorul modific direct Vizualizarea, ceea ce face ablonul MVP
mai uor de folosit dect ablonul MVC.

Aceste diferene fac ablonul MVP mai atractiv dect ablonul MVC
pentru aplicaiile din prezent.


4.1. Variante de actualizare a Vizualizrii

Cnd Modelul este actualizat, Vizualizarea trebuie de asemenea
actualizat pentru a reflecta modificrile. Actualizarea Vizualizrii poate fi
realizat n dou variante: Vizualizarea pasiv (engl. Passive View) i
Controlorul supervizor (engl. Supervising Controller). Figura 6.3
ilustreaz modelele logice ale celor dou variante.


Figura 6.3. Vizualizarea pasiv (stnga) i Controlorul supervizor (dreapta)

n abordarea Vizualizrii pasive, Prezentatorul actualizeaz
Vizualizarea pentru a reflecta schimbrile din Model. Interaciunea cu
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 6. Arhitectura MVC


137
Modelul este gestionat exclusiv de Prezentator iar Vizualizarea nu i poate
da seama direct de schimbrile din Model. La rndul su, Vizualizarea este
actualizat exclusiv de ctre Prezentator.
Abordarea este util atunci cnd Prezentatorul trebuie s realizeze
unele prelucrri complexe asupra datelor, nainte de a afia informaiile
pentru utilizator. Acestea apar de exemplu atunci cnd strile controalelor
din interfaa grafic depind de anumite prelucrri ale datelor. S considerm
cazul n care un utilizator dorete s mprumute o carte a unui anumit autor
de la bibliotec. Dac toate crile autorului respectiv sunt deja
mprumutate, butonul mprumut poate fi dezactivat. n aceast situaie,
faptul c mprumutul este imposibil nu este reinut n Model, ci este
determinat de Prezentator, care apoi i cere Vizualizrii s dezactiveze
butonul respectiv.
n abordarea Controlorului supervizor, Vizualizarea interacioneaz
direct cu Modelul pentru a transfera date, fr intervenia Prezentatorului.
Prezentatorul actualizeaz Modelul i manipuleaz starea Vizualizrii doar
n cazurile n care exist o logic complex a interfeei cu utilizatorul.
Vizualizarea poate fi actualizat i direct, pe baza modificrilor datelor din
Model.
Astfel de transferuri simple, n care Vizualizarea comunic direct cu
Modelul, sunt n general situaiile n care se schimb unele date n Model iar
acestea sunt preluate i afiate n Vizualizare, fr prelucrri suplimentare.
De exemplu, interfaa afieaz o list de cri mprumutate de un student de
la bibliotec, list pstrat de Model ntr-o baz de date. Cnd studentul
mprumut o nou carte, baza de date se schimb iar Vizualizarea preia
direct din Model elementele listei pentru afiare.
Vizualizarea pasiv este asemntoare arhitecturii cu trei straturi
tipice, n care stratul de logic a aplicaiei se interpune ntre stratul de
prezentare i stratul de acces la date.
Decizia asupra alegerii uneia din cele dou variante depinde de
prioritile aplicaiei. Dac este mai important testabilitatea, Vizualizarea
pasiv este mai potrivit, deoarece se poate testa toat logica interfeei cu
utilizatorul prin testarea Prezentatorului. Pe de alt parte, dac simplitatea
este mai important, Controlorul supervizor este o opiune mai bun
deoarece, pentru schimbri mici n interfa, nu mai trebuie inclus cod n
Prezentator pentru actualizarea Vizualizrii. Astfel, Controlorul supervizor
necesit de obicei mai puin cod ntruct Prezentatorul nu mai efectueaz
actualizrile simple ale Vizualizrii.
abloanele MVC i MVP au scopuri similare, ns difer prin
modalitile n care i ating aceste scopuri.
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

138
5. Aplicaii

5.1. Realizai un program de tip consol cu arhitectura MVP,
Controlor supervizor pentru determinarea costurilor unei firme de transport.
Se vor putea calcula costurile de transport ntre dou orae, identificate prin
nume, latitudine i longitudine.
Aplicaia va permite dou roluri: administrator i utilizator, cu
funcii diferite (figura 6.4).


Figura 6.4. Meniul principal

Pentru rolul de utilizator comenzile disponibile sunt prezentate n
figura 6.5.


Figura 6.5. Meniul rolului de utilizator
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 6. Arhitectura MVC


139
Pentru rolul de administrator comenzile disponibile sunt prezentate
n figura 6.6.


Figura 6.6. Meniul rolului de administrator

Indicaii:

Se furnizeaz codul surs pentru Model, mpreun cu un fiier text
care conine mai multe orae;

Model.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace TransportInfo
{
public class Model : IModel
{
#region Fields

private const string CityFileName = "cities.txt";
private List<City> _cityList;
private bool _wasModified; // lista cu orae va fi salvat n final doar dac s-a modificat

#endregion


Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

140
#region Properties
public int CityCount
{
get { return _cityList.Count; }
}
#endregion

#region Constructor

public Model()
{
_cityList = new List<City>();
_wasModified = false;
}

#endregion


#region Public Methods

public int GetNumberOfCities()
{
return _cityList.Count;
}

public bool DataExists()
{
if (!File.Exists(CityFileName))
{
_wasModified = true;
return false;
}
else
return true;
}

public void InitializeData()
{
StreamReader sr = new StreamReader(CityFileName);
string line;
while ((line = sr.ReadLine()) != null)
_cityList.Add(ParseCityLine(line));
sr.Close();
}


Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 6. Arhitectura MVC


141
public bool Add(City city)
{
// dac un ora cu acelai nume exist deja, el va fi ters
bool overwrite = false;

for (int i = 0; i < _cityList.Count; i++)
{
if (_cityList[i].Name.Trim().ToUpper() == city.Name.Trim().ToUpper())
{
_cityList.RemoveAt(i--);
overwrite = true;
}
}

// adugarea noului ora
_cityList.Add(city);
_wasModified = true;
return !overwrite;
}

public bool Delete(string cityName)
{
for (int i = 0; i < _cityList.Count; i++)
{
if (_cityList[i].Name == cityName)
{
_cityList.RemoveAt(i);
_wasModified = true;
return true;
}
}

return false;
}

public bool Exists(string cityName)
{
// dac un ora exist
for (int i = 0; i < _cityList.Count; i++)
{
if (_cityList[i].Name == cityName)
return true;
}

return false;
}
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

142
public City Search(string cityName)
{
// caut un ora dup nume i returneaz obiectul corespunztor
for (int i = 0; i < _cityList.Count; i++)
{
if (_cityList[i].Name == cityName)
return _cityList[i];
}

return new City();
}

public string ListAll()
{
// creeaz un string cu numele tuturor oraelor
if (_cityList.Count == 0)
return string.Empty;

StringBuilder sb = new StringBuilder();
sb.Append(_cityList[0].Name);

for (int i = 1; i < _cityList.Count; i++)
{
sb.Append(", ");
sb.Append(_cityList[i].Name);
}

return sb.ToString();
}

/// <summary>
/// Salveaz datele doar dac lista de orae s-a modificat
/// </summary>
/// <returns>Returneaz true dac noile date au fost salvate </returns>
public bool SaveData()
{
// dac datele s-au modificat, ele sunt salvate
if (_wasModified)
{
StreamWriter sw = new StreamWriter(CityFileName);

for (int i = 0; i < _cityList.Count; i++)
{
City c = _cityList[i];
sw.WriteLine(c.Name + "\t" + c.Latitude + "\t" + c.Longitude);
}
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 6. Arhitectura MVC


143
sw.Close();
return true;
}
else
return false;
}

#endregion

#region Private Methods

private static City ParseCityLine(string line)
{
// citete informaiile unui ora de pe o linie din fiier
string[] toks = line.Split('\t');
City city = new City(toks[0], Convert.ToDouble(toks[1]), Convert.ToDouble(toks[2]));
return city;
}

#endregion
}
}


cities.txt

Iasi 47.167 27.583
Bacau 46.567 26.917
Piatra Neamt 46.933 26.383
Suceava 47.667 26.183
Botosani 47.733 26.667
Vaslui 46.633 27.733
Bucuresti 44.44 26.1
Cluj-Napoca 46.78 23.59
Timisoara 45.76 21.23
Constanta 44.18 28.63
Brasov 45.66 25.61
Chisinau 47.033 28.833
Balti 47.75 27.917
Amsterdam 52.383 4.9
Atena 37.967 23.767
Belgrad 44.817 20.45
Berlin 52.533 13.4
Bruxelles 50.85 4.35
Budapesta 47.483 19.083
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

144
Londra 51.517 -0.1
Madrid 40.417 -3.75
Moscova 55.75 37.583
Oslo 59.917 10.75
Praga 50.083 14.367
Paris 48.833 2.333
Roma 41.9 12.5
Sofia 42.75 23.333
Viena 48.2 16.367

Se furnizeaz codul surs pentru structura corespunztoare unui ora,
mpreun cu funcia de calcul al distanei;

City.cs

namespace TransportInfo
{
public struct City
{
// readonly pentru ca structura s fie immutable
// alternativa este abordarea cu cmpuri private i proprieti publice
public readonly double Latitude, Longitude;
public readonly string Name;

public City(string name, double latitude, double longitude)
{
Name = name;
Latitude = latitude;
Longitude = longitude;
}
}
}

Calculator.cs

namespace TransportInfo
{
public class BusinessCalculator
{
#region Public Static Methods
public static double Distance(City c1, City c2)
{
// calculeaz distana n kilometri ntre dou puncte de pe suprafaa Pmntului
// identificate prin latitudine i longitudine utiliznd coordonate sferice

double a1 = c1.Latitude * Math.PI / 180.0;
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 6. Arhitectura MVC


145
double b1 = c1.Longitude * Math.PI / 180.0;
double a2 = c2.Latitude * Math.PI / 180.0;
double b2 = c2.Longitude * Math.PI / 180.0;
const double EarthRadius = 6378; // raza Pmntului n km

return (int)(EarthRadius * Math.Acos(Math.Cos(a1) * Math.Cos(b1) * Math.Cos(a2)
* Math.Cos(b2) + Math.Cos(a1) * Math.Sin(b1) * Math.Cos(a2) * Math.Sin(b2) +
Math.Sin(a1) * Math.Sin(a2)));
}

public static double Cost(double distance)
{
// aici se poate introduce orice funcie de calcul al costului
double euro = 5 + distance / 30.0;
return euro * 4.3;
}
#endregion
}
}

ntruct cele trei meniuri au structuri similare, se recomand crearea
unei metode comune care s primeasc drept parametru lista de
opiuni posibile;
Se recomand ca opiunile alese de utilizator s fie tratate ca o
enumeraie.

public enum UserChoice { AdminMenu, UserMenu, PreviousMenu, Route, AddCity,
RemoveCity, Exit, List, Undefined };
public enum MenuState { Main, Administrator, User };

Metoda Main din clasa Program poate avea coninutul urmtor:

static class Program
{
static void Main()
{
Model model = new Model();
ConsoleView view = new ConsoleView(model);
Presenter presenter = new Presenter(view, model);
view.SetPresenter(presenter);
view.Start();
}
}
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

146

F
i
g
u
r
a

6
.
7
.

E
x
e
m
p
l
u

d
e

r
e
z
o
l
v
a
r
e
:

d
i
a
g
r
a
m
a

d
e

c
l
a
s
e

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 6. Arhitectura MVC


147
Un exemplu de diagram de clase pentru aplicaie este prezentat n
figura 6.7. Pentru creterea claritii, nu s-au mai reprezentat explicit
relaiile de asociere pentru cmpurile de tip IPresenter, IModel, IView i nici
numele metodelor din interfee implementate de clasele concrete.
Metoda ListAll din clasele View apeleaz direct metoda ListAll din
clasa Model. Aici apare diferena ntre abordarea Controlorului supervizor
i cea a Vizualizrii pasive. Dac s-ar fi utilizat cea de a doua abordare,
ListAll din View ar fi apelat o metod corespunztoare din Presenter, iar
aceasta ar fi apelat metoda ListAll din Model.
Proiectele soluiei i fiierele surs pot fi structurate ca n figura 6.8.


Figura 6.8. Exemplu de rezolvare: structurarea soluiei


5.2. Tem pentru acas. Pstrnd aceleai clase pentru Model i
Prezentator, realizai o Vizualizare nou, cu o interfa grafic de tip
Windows Forms, cu aceeai funcionalitate ca i aplicaia consol dezvoltat
anterior.

Indicaii: Metoda Main din clasa Program poate avea coninutul
urmtor:


Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

148
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);

Model model = new Model();
FormView view = new FormView();
Presenter presenter = new Presenter(view, model);
view.SetModel(model);
view.SetPresenter(presenter);
Application.Run(view);
}
}

Pentru a fora utilizatorul s foloseasc doar opiunea de Ieire
pentru a nchide programul, butonul de nchidere a ferestrei poate fi
dezactivat cu ajutorul secvenei urmtoare de cod:

#region Disable Close X Button
const int MF_BYPOSITION = 0x400;

[DllImport("User32")]
private static extern int RemoveMenu(IntPtr hMenu, int nPosition, int wFlags);

[DllImport("User32")]
private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);

[DllImport("User32")]
private static extern int GetMenuItemCount(IntPtr hWnd);

private void FormView_Load(object sender, EventArgs e)
{
IntPtr hMenu = GetSystemMenu(this.Handle, false);
int menuItemCount = GetMenuItemCount(hMenu);
RemoveMenu(hMenu, menuItemCount - 1, MF_BYPOSITION);
}
#endregion

Un exemplu de interfa grafic este prezentat n capturile ecran din
figurile 6.9, 6.10 i 6.11.

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 6. Arhitectura MVC


149

Figura 6.9. Exemplu de rezolvare: meniul principal




Figura 6.10. Exemplu de rezolvare: rolul de utilizator

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

150

Figura 6.11. Exemplu de rezolvare: rolul de administrator



Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com


151

Capitolul 7

ablonul de proiectare Metoda Fabric

1. Obiective
2. ablonul creaional Metoda Fabric
3. Exemplu de implementare
4. Motenirea i polimorfismul
5. Aplicaii

1. Obiective

Obiectivele capitolului 7 sunt urmtoarele:

Implementarea unui program dup ablonul de proiectare Metoda
Fabric (engl. Factory Method);
Precizarea unor noiuni privind motenirea i polimorfismul (clase
abstracte, interfee, membri virtuali), utilizate n majoritatea
abloanelor de proiectare.


2. ablonul creaional Metoda Fabric

ablonul Metoda Fabric definete o interfa pentru crearea unui
obiect, dar las subclasele s decid ce clas s instanieze.
Diagrama de clase este prezentat n figura 7.1.


Figura 7.1. Diagrama de clase a ablonului Metoda Fabric
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

152
O alt diagram n care avem doi creatori i dou produse este
prezentat n figura 7.2.


Figura 7.2. Diagrama de clase cu doi creatori i dou produse

Metoda Fabric se folosete n general atunci cnd o clas nu poate
ti sau nu dorete s specifice din ce clas va fi creat un obiect i n
consecin las clasele derivate s specifice clasa acestuia.


3. Exemplu de implementare

Codul C# corespunztor diagramei UML anterioare este prezentat
mai jos.

Clasele Produs

abstract class Product
{
}

class ConcreteProductA : Product
{
}

class ConcreteProductB : Product
{
}






Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 7. ablonul de proiectare Metoda Fabric


153
Clasele Creator

abstract class Creator
{
// Metode
abstract public Product FactoryMethod();
}


class ConcreteCreatorA : Creator
{
// Metode
override public Product FactoryMethod()
{
return new ConcreteProductA();
}
}

class ConcreteCreatorB : Creator
{
// Metode
override public Product FactoryMethod()
{
return new ConcreteProductB();
}
}

Clientul

class Client
{
public static void Main( string[] args )
{
// FactoryMethod returneaz ProductA
Creator c = new ConcreteCreatorA();
Product p = c.FactoryMethod();
Console.WriteLine("A fost creat {0}", p );

// FactoryMethod returneaz ProductB
c = new ConcreteCreatorB();
p = c.FactoryMethod();
Console.WriteLine("A fost creat {0}", p );
}
}

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

154
4. Motenirea i polimorfismul

4.1. Polimorfismul

Cu ajutorul motenirii, o clas poate fi folosit ca i cum ar
reprezenta mai multe tipuri. Ea poate fi folosit ca propriul su tip, ca un tip
de clas de baz, sau un tip de interfa pe care o implementeaz. Acest
comportament este numit polimorfism. n C#, orice tip este polimorfic. Un
tip poate fi folosit aa cum este sau ca o instan de object, pentru c orice
tip consider automat tipul object ca tip de baz.
Polimorfismul este important nu numai pentru clasele derivate, ci i
pentru clasele de baz. Cnd se folosete o clas de baz, se poate folosi de
fapt orice clas derivat. Proiectanii unei clase de baz pot anticipa
aspectele claselor care se vor modifica prin derivare. De exemplu, o clas de
baz pentru maini poate conine membri care se modific dac maina este
o dubi sau o main decapotabil. O clas de baz poate marca acei
membri ca virtuali, dnd posibilitatea claselor derivate care reprezint
maina decapotabil i dubia s suprascrie comportamentul respectiv.
Cnd o clas derivat motenete o clas de baz, ea primete toate
metodele, cmpurile, proprietile i evenimentele clasei de baz. Pentru a
modifica datele i metodele unei clase de baz exist dou posibiliti: se
poate nlocui clasa de baz cu una derivat sau se poate suprascrie un
membru virtual din clasa de baz.


4.2. Clase abstracte

Cuvntul cheie abstract ofer posibilitatea crerii claselor i
membrilor de clase doar pentru a putea fi motenii: pentru a defini trsturi
ale claselor derivate, neabstracte.

public abstract class A
{
// membrii clasei
}

O clas abstract nu poate fi instaniat. Scopul su este s ofere o
definiie comun pentru mai multe clase derivate. De exemplu, o bibliotec
de clase poate defini o clas abstract care este folosit ca parametru n mai
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 7. ablonul de proiectare Metoda Fabric


155
multe funcii din bibliotec i necesit ca dezvoltatorii care o folosesc s
asigure o implementare proprie prin crearea unei clase derivate.
Clasele abstracte pot de asemenea s defineasc metode abstracte,
prin adugarea cuvntului cheie abstract n faa tipului returnat de metod.
De exemplu:

public abstract class A
{
public abstract void Method(int i);
}

Metodele abstracte nu au implementare i deci definiia metodei este
urmat de ; n locul unui bloc normal de cod. Clasele derivate
neabstracte trebuie s implementeze toate metodele abstracte.


4.3. Interfee

Interfeele sunt definite cu ajutorul cuvntului cheie interface. De
exemplu:

interface IComparable
{
int CompareTo(object obj);
}

Interfeele descriu un grup de funcionaliti asemntoare care pot
s aparin oricrei clase sau structuri. Interfeele pot conine metode,
proprieti, evenimente sau indeci, ns nu pot conine cmpuri.
Membrii unei interfee sunt implicit publici.
Clasele i structurile pot moteni interfee ntr-un mod asemntor
claselor care motenesc clase sau structuri, cu dou excepii:

O clas sau structur poate moteni mai multe interfee;
Cnd o clas sau structur motenete o interfa, motenete doar
numele metodelor i semnturile acestora, deoarece interfeele nu
conin implementri.

n exemplul urmtor, clasa Minivan este derivat din clasa Car i
implementeaz interfaa IComparable.

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

156
public class Minivan : Car, IComparable
{
public int CompareTo(object obj)
{
// implementarea metodei CompareTo
return 0; // dac obiectele sunt egale
}
}

Pentru a implementa un membru al unei interfee, membrul respectiv
trebuie s fie public, nestatic i s aib acelai nume i semntur cu
membrul interfeei.
Interfeele pot moteni alte interfee. Este posibil ca o clas s
moteneasc o interfa de mai multe ori, printr-o clas sau interfa
motenit. n acest caz, clasa poate implementa interfaa doar o dat.
O interfa are urmtoarele caracteristici:

Este similar unei clase de baz abstracte: orice tip neabstract care
motenete o interfa trebuie s i implementeze toi membrii;
O interfa nu poate fi instaniat direct;
Interfeele pot conine metode, proprieti, evenimente i indeci;
Interfeele nu conin implementri ale metodelor;
Clasele i structurile pot moteni mai multe interfee;
O interfa poate ea nsi s moteneasc mai multe interfee.


4.4. Membri virtuali

Pentru ca o clas derivat s reimplementeze un membru al unei
clase de baz, clasa de baz trebuie s defineasc membrul ca virtual iar
clasa derivat s foloseasc cuvntul cheie override pentru a nlocui
implementarea membrului. De exemplu:

public class BaseClass
{
public virtual void Method()
{
...
}



Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 7. ablonul de proiectare Metoda Fabric


157
public virtual int Property
{
get { ... }
}
}

public class DerivedClass : BaseClass
{
public override void Method()
{
...
}

public override int Property
{
get { ... }
}
}

Cmpurile nu pot fi virtuale, doar metodele, proprietile i indecii.
Cnd o clas derivat suprascrie un membru virtual, acel membru este apelat
chiar i atunci cnd o instan a acelei clase este accesat ca o instan a
clasei de baz. De exemplu:

DerivedClass B = new DerivedClass();
B.Method (); // Apeleaz metoda nou

BaseClass A = (BaseClass)B;
A.Method (); // Apeleaz tot metoda nou

Un membru virtual rmne astfel n toat ierarhia de clase, indiferent
de numrul de niveluri dintre clasa de baz i cea curent. Dac n clasa A
este declarat un membru virtual i clasa B este derivat din clasa A iar clasa
C este derivat din clasa B, atunci clasa C motenete membrul virtual i
poate s l suprascrie, chiar dac n clasa B el a fost deja suprascris. De
exemplu:

public class A
{
public virtual void Method()
{
...
}
}
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

158
public class B : A
{
public override void Method()
{
...
}
}

public class C : B
{
public override void Method()
{
...
}
}


4.5. Clase sigilate i membri sigilai

Sigilarea mpiedic motenirea claselor sau suprascrierea membrilor
virtuali.
O clas pot fi declarat ca sigilat, punnd cuvntul cheie sealed
naintea cuvntului class la definirea acesteia:

public sealed class A
{
// membrii clasei
}

O clas sigilat nu poate fi folosit drept clas de baz. Din aceast
cauz, ea nu poate fi nici abstract. Clasele sigilate sunt folosite, n
principiu, pentru a preveni derivarea. Neputnd fi folosite ca i clase de
baz, unele optimizri n timp real pot face apelul membrilor acestora mai
rapid.
Un membru, o metod, o proprietate sau un eveniment al unei clase
derivate care suprascrie un membru virtual al clasei de baz poate declara
acel membru ca sigilat. Astfel se elimin aspectul virtual al membrului
pentru orice clas viitoare derivat. De exemplu:




Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 7. ablonul de proiectare Metoda Fabric


159
public class B
{
public virtual void Method()
{
...
}
}

public class C : B
{
public sealed override void Method()
{
...
}
}

n exemplul anterior, metoda Method nu mai este virtual pentru
nicio clas derivat din C. Dar este nc virtual pentru instanele clasei C.


4.6. nlocuirea unui membru cu ajutorul cuvntului
cheie new

nlocuirea unui membru din clasa de baz cu unul nou, derivat,
necesit folosirea cuvntului cheie new. Dac o clas de baz definete o
metod, un cmp sau o proprietate, cuvntul cheie new se utilizeaz pentru
a crea o nou definiie n clasa derivat. Cuvntul cheie new trebuie pus
naintea tipului returnat al membrului clasei. De exemplu:

public class BaseClass
{
public void Method()
{
...
}

public int Property
{
get { ... }
}
}


Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

160
public class DerivedClass : BaseClass
{
public new void Method()
{
...
}

public new int Property
{
get { ... }
}
}

Cnd se folosete cuvntul cheie new, noul membru este apelat n
locul celui vechi, nlocuit. Membrii respectivi ai clasei de baz sunt numii
membri ascuni. Ei mai pot fi apelai doar dac o instan a clasei derivate
este convertit prin cast la o instan a clasei de baz. De exemplu:

DerivedClass B = new DerivedClass();
B.Method (); // Apeleaz metoda nou

BaseClass A = (BaseClass)B;
A.Method (); // Apeleaz metoda veche


4.7. Accesarea clasei de baz cu ajutorul cuvntului
cheie base

O clas derivat care a nlocuit sau suprascris o metod sau
proprietate poate nc accesa metoda sau proprietatea din clasa de baz
folosind cuvntul cheie base. De exemplu:

public class A
{
public virtual void Method()
{
...
}
}




Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 7. ablonul de proiectare Metoda Fabric


161
public class B : A
{
public override void Method()
{
...
}
}

public class C : B
{
public override void Method()
{
// apeleaz Method din B pentru a utiliza comportamentul lui B
base.Method();

// comportamentul specific lui C urmeaz n continuare
...
}
}

Se recomand ca un membru virtual s utilizeze cuvntul cheie base
pentru a apela implementarea membrului din clasa de baz n implementarea
proprie. Prin aceasta este lsat clasa derivat s se axeze pe implementarea
propriilor funcionaliti. Dac nu este apelat implementarea din clasa de
baz, atunci clasa derivat va trebui s se ocupe de implementarea unor
funcionaliti similare cu acelea ale clasei de baz.
Cuvntul cheie base este folosit:

Pentru a apela o metod din clasa de baz care a fost suprascris de o
alt metod;
Pentru a specifica clasa de baz al crei constructor s fie apelat la
instanierea clasei derivate.

Din metodele statice nu este permis accesul la clasa de baz prin
cuvntul cheie base.


5. Aplicaii

5.1. Realizai o aplicaie care deschide i afieaz fiiere text i
grafice (figura 7.3). Testul se va efectua dup extensia fiierului (txt, rtf,
bmp, jpg). Se va utiliza ablonul de proiectare Metoda fabric.
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

162



Figura 7.3. Exemplu de rezolvare: interfaa cu utilizatorul



Figura 7.4. Exemplu de rezolvare: fiierele de test
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 7. ablonul de proiectare Metoda Fabric


163
Aplicaia deschide fiiere index cu extensiile txd, pentru fiiere
text, respectiv grd, pentru fiiere grafice. Aceste fiiere index conin cile
ctre mai multe fiiere cu extensiile txt sau rtf, respectiv bmp sau jpg.
Un exemplu privind structura de directoare i fiiere, precum i
coninutul fiierelor index este prezentat n figura 7.4.
Diagrama de clase este prezentat n figura 7.5.


Figura 7.5. Exemplu de rezolvare: diagrama de clase

Indicaii. Pentru citirea fiierelor text se poate utiliza clasa
StreamReader din System.IO. Pentru fiierele text i rtf se poate utiliza clasa
RichTextBox din System.Windows.Forms cu metoda LoadFile. Pentru
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

164
fiierele grafice se poate utiliza clasa Bitmap unde numele fiierului este
primit n constructor sau proprietatea ImageLocation din clasa PictureBox.
Pentru deschiderea unui fiier se utilizeaz un control
OpenFileDialog. Pentru a se deschide doar tipurile de fiiere cu extensiile txd
sau grd, se seteaz proprietatea Filter cu valoarea "Text documents
(*.txd)|*.txd|Graphic documents (*.grd)|*.grd".
n evenimentul corespunztor butonului Open, se poate prelucra un
fiier doar dac utilizatorul a ales un fiier i a dat OK n fereastra de
deschidere de fiiere.

if (openFileDialog.ShowDialog() != DialogResult.OK)
return;

Apoi se testeaz valoarea proprietii FilterIndex din obiectul
openFileDialog, care indic tipul de fiier deschis (index text sau index
grafic). Indexul pleac de la 1, nu de la 0. n continuare, se instaniaz un
obiect TextDocument sau un GraphicDocument. Afiarea paginilor n
obiectul tabControl se poate face n modul urmtor:

Document doc;

... // crearea obiectului document (creatorul concret)

tabControl.Controls.Clear();
foreach (Page p in doc.Pages)
{
TabPage tp = new TabPage(p.Name);
p.Content.Dock = DockStyle.Fill;
tp.Controls.Add(p.Content);
tabControl.TabPages.Add(tp);
}

Secvena de cod de mai sus se recomand a fi inclus ntr-un bloc de
tratare a excepiilor, deoarece pot aprea probleme referitoare la deschiderea
unui fiier care s nu conin ci valide sau fiierele indicate de aceste ci s
nu aib coninutul ateptat.
n produsele concrete se creeaz controalele corespunztoare iar
numele paginilor afiate n tabControl se determin din numele fiierului
ncrcat:

_name = Path.GetFileNameWithoutExtension(fileName);
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 7. ablonul de proiectare Metoda Fabric


165
n constructorul creatorului abstract (Document) se citete fiierul
index linie cu linie i se creeaz paginile corespunztoare:

StreamReader sr = new StreamReader(indexFileName);
string line;
while ((line = sr.ReadLine()) != null)
{
if (line != string.Empty)
_pages.Add(CreatePage(line));
}
sr.Close();

ns deoarece metoda CreatePage este abstract, deciziile privind
tipul efectiv al paginii vor fi luate de clasele derivate din Document.


5.2. Tem pentru acas. Adugai n proiect un nou tip de pagin
care s afieze un document Microsoft Word i/sau un document PDF.


Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

166

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com


167

Capitolul 8

abloanele de proiectare
Singleton i Prototip

1. Obiective
2. ablonul creaional Singleton
3. ablonul creaional Prototip
4. Aplicaii

1. Obiective

Obiectivele capitolului 8 sunt urmtoarele:

Implementarea unui program dup ablonul de proiectare Singleton;
Implementarea unui program dup ablonul de proiectare Prototip
(engl. Prototype).


2. ablonul creaional Singleton

Scopul ablonului Singleton este s garanteze faptul c o clas poate
avea doar o singur instan i s asigure un punct global de acces la ea.
n unele situaii, este important ca o clas s aib o singur instan,
de exemplu atunci cnd avem dispozitive hardware sau accesorii ataate
unui calculator i dorim s prevenim accesul concurent la acestea. Alte
situaii sunt cele n care se dorete lucrul cu registrul Windows (unic) sau
atunci cnd se lucreaz cu un bazin (engl. pool) de fire de execuie. n
general, ablonul este util cnd o resurs unic trebuie s aib un
corespondent unic care o acceseaz din program.
Este nevoie deci de o modalitate de a mpiedica instanierile multiple
ale unei clase i de a asigura o metod unic global pentru accesarea
instanei. Avantajul fa de utilizarea unor clase statice sau cu proprieti
statice este faptul c Singleton-ul poate fi derivat i astfel clienii i pot
extinde funcionalitatea fr a fi nevoii s modifice clasa existent.
Diagrama de clase este prezentat n figura 8.1.
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

168

Figura 8.1. Diagrama de clase a ablonului Singleton

Clientul poate accesa poate accesa instana unic a clasei Singleton
utiliznd metoda static Instance.


2.1. Exemplu de implementare

Codul C# corespunztor diagramei UML anterioare este prezentat
mai jos.

Clasa Singleton

class Singleton
{
private static Singleton _instance;

private int _data; // datele propriu-zise ale clasei

public int Data
{
get { return _data; }
set { _data = value; }
}

private Singleton() // protected dac avem nevoie de clase derivate
{
}

public static Singleton Instance()
{
// Iniializare ntrziat ("lazy initialization")
if( _instance == null )
_instance = new Singleton();

return _instance;
}
}
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 8. abloanele de proiectare Singleton i Prototip


169
Clientul

public class Client
{
public static void Main()
{
// constructorul este privat, nu se poate folosi "new"
Singleton s1 = Singleton.Instance();
s1.Data = 5;

Singleton s2 = Singleton.Instance();
Console.WriteLine("Rezultat: {0}", s2.Data); // "Rezultat: 5"

Console.ReadLine();
}
}

Trebuie precizat c n situaiile n care mai multe fire de execuie pot
accesa simultan seciunea de iniializare, trebuie incluse mecanisme
suplimentare de sincronizare.


3. ablonul creaional Prototip

Scopul ablonului Prototip este s specifice tipurile de obiecte care
pot fi create folosind o instan prototip i s creeze noi obiecte prin
copierea acestui prototip.
Exist situaii n care instanierea unui obiect n mod normal,
folosind iniializarea strii interne n constructor, este costisitoare din punct
de vedere al timpului sau resurselor de calcul. De aceea, dac este nevoie de
mai multe astfel de obiecte n sistem, se poate utiliza un obiect prototip
pentru a crea noi obiecte, prin copierea, n loc de calcularea de fiecare dat a
valorilor datelor interne. Ideea de baz este utilizarea unei instane tipice
pentru a crea o alt instan nrudit.
ablonul folosete o metod caracteristic numit Clone pentru
crearea cpiilor unui obiect. Nu se specific ns dac clonarea este
superficial (engl. shallow) sau profund (engl. deep), aceasta depinde
de tipul datelor copiate. Clonarea superficial este mai simpl i se folosete
de obicei cnd cmpurile sunt de tip valoare (tipuri primitive, structuri).
Pentru tipuri referin, acest tip de clonare copiaz doar referinele i de
aceea, n aceste cazuri se poate prefera copierea profund, care copiaz
recursiv toate valorile.
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

170
De exemplu, dac obiectul are dou cmpuri primitive, int i double,
este suficient clonarea superficial. Dac se mai adaug un cmp vector,
int[], clonarea superficial ar copia doar referina: obiectul prototip i copia
ar referenia de fapt acelai vector. Clonarea profund creeaz n acest caz
doi vectori distinci pentru cele dou obiecte.
Una din principalele probleme ale ablonului este legat de tipul
clonrii, deoarece varianta recomandat depinde de situaie.
Diagrama de clase este cea din figura 8.2.


Figura 8.2. Diagrama de clase a ablonului Prototip


3.1. Exemplu de implementare

Codul C# corespunztor diagramei UML anterioare este prezentat
mai jos.


Prototipul abstract

abstract class Prototype
{
private string _data;

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 8. abloanele de proiectare Singleton i Prototip


171
public Prototype(string data)
{
_data = data;
}

public string Data
{
get
{
return _data;
}
}

abstract public Prototype Clone();
}


Prototipurile concrete

class ConcretePrototype1 : Prototype
{
public ConcretePrototype1(string data) : base(data)
{
}

override public Prototype Clone()
{
// copie superficial
return (Prototype)this.MemberwiseClone();
}
}


class ConcretePrototype2 : Prototype
{
public ConcretePrototype2(string data) : base(data)
{
}

override public Prototype Clone()
{
// copie superficial
return (Prototype)this.MemberwiseClone();
}
}

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

172
Clientul

class Client
{
public static void Main(string[] args)
{
// se creeaz dou prototipuri i se cloneaz fiecare

ConcretePrototype1 prototype1 = new ConcretePrototype1("Proto1");
ConcretePrototype1 clone1 = (ConcretePrototype1)p1.Clone();
Console.WriteLine("Cloned: {0}", c1.Data);

ConcretePrototype2 prototype2 = new ConcretePrototype2("Proto2");
ConcretePrototype2 clone2 = (ConcretePrototype2)p2.Clone();
Console.WriteLine("Cloned: {0}", c2.Data);

Console.ReadLine();
}
}


4. Aplicaii

4.1. S se simuleze lucrul cu o imprimant (figura 8.3). Fiecrui
document i este asociat o mrime. Imprimanta are o coad de documente
ce urmeaz a fi tiprite. Cnd se trimite un document la imprimare, dac
aceast coad este vid, fiierul ncepe s fie tiprit. Timpul necesar tipririi
este proporional cu mrimea sa. Cnd coada imprimantei nu este vid,
documentul este doar introdus n coad. La terminarea tipririi unui
document, se preia urmtorul din coad (dac exist). Implementarea se va
realiza utiliznd ablonul Singleton.
Diagrama de clase a aplicaiei este prezentat n figura 8.4.

Indicaie: pentru simularea tipririi se recomand folosirea unui
control Timer, descris n capitolul 2, seciunea 5. Evenimentul Tick este
tratat o dat la un interval de timp, specificat n milisecunde de proprietatea
Interval. De exemplu, dac Interval = 500, codul evenimentului Tick va fi
executat n mod repetat, de dou ori pe secund. Proprietatea Enabled arat
dac timer-ul e activat sau nu (true/false).

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 8. abloanele de proiectare Singleton i Prototip


173

Figura 8.3. Exemplu de rezolvare: interfaa cu utilizatorul



Figura 8.4. Exemplu de rezolvare: diagrama de clase


Proprietatea Queue din clasa Printer returneaz coninutul cozii de
activiti ale imprimantei, pentru a fi afiat ca atare de client (MainForm).
n acest fel, clientul nu mai trebuie s depind de clasa DocInfo, care
reprezint obiectele cu care lucreaz intern doar clasa Printer.

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

174
4.2. S presupunem c avem un joc n care utilizatorul mpuc
montri pe ecran (figura 8.5). Exist mai multe tipuri de montri, fiecare cu
propriile caracteristici: imagine, culoare, numr de viei etc. Pe lng
acestea, fiecare monstru are implementat un modul de inteligen artificial,
a crui iniializare necesit multe resurse.


Figura 8.5. Exemplu de rezolvare: interfaa cu utilizatorul

Scheletul programului este dat, la fel i o clas pentru un monstru
implementat n MonsterSprite.dll, cu structura din diagrama din figura 8.6
i al crei cod surs este prezentat n continuare.


Figura 8.6. Diagrama claselor din DLL
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 8. abloanele de proiectare Singleton i Prototip


175
MonsterSprite.cs

using System;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
using System.Runtime.Serialization;

namespace Monster
{
[Serializable]
public class MonsterSprite
{
protected Bitmap _image;
protected Color _color;
protected int _lives;
protected int _maxLives;
protected string _ai = "I am stupid";

public MonsterSprite(Monster settings)
{
_image = new Bitmap(settings.Image);
_maxLives = Convert.ToInt32(settings.Lives);
_lives = _maxLives;
_color = GetColor(settings.Color);

InitAI();
}

/// <summary>
/// Interpreteaz numele unei culori i returneaz un obiect Color
/// </summary>
/// <param name="colorName"></param>
/// <returns></returns>
protected Color GetColor(string colorName)
{
Color c;
switch (colorName)
{
case "red": c = Color.Red; break;
case "blue": c = Color.Blue; break;
case "green": c = Color.Green; break;
case "yellow": c = Color.Yellow; break;
case "orange": c = Color.Orange; break;
case "black": c = Color.Black; break;

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

176
default: c = Color.Gray; break;
}
return c;
}

private void InitAI()
{
_ai = "I am smart";
MessageBox.Show("Se initializeaza modulul de inteligenta artificiala...");
Thread.Sleep(2000);
}

/// <summary>
/// Deseneaz un personaj
/// </summary>
/// <param name="g"></param>
/// <param name="x"></param>
/// <param name="y"></param>
public void Draw(Graphics g, int x, int y)
{
g.DrawImage(_image, x, y);
double more = (double)_lives / (double)_maxLives;
g.FillRectangle(new SolidBrush(Color.DarkGray), (float)x, (float)(y + 200),
(float)200, (float)4);
g.FillRectangle(new SolidBrush(_color), (float)x, (float)(y + 200),
(float)(more * 200), (float)4);
}

/// <summary>
/// Returneaz true dac este mort
/// </summary>
/// <returns></returns>
public bool Shoot()
{
_lives--;
if (_lives == 0)
return true;
else
return false;
}
}
}




Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 8. abloanele de proiectare Singleton i Prototip


177
Utils.cs

namespace Monster
{
public class AllMonsters
{
public Monster[] Monsters;
}

public class Monster
{
public string Image;
public string Color;
public string Lives;
}
}

Scopul aplicaiei este s evitai iniializarea de fiecare dat a
modulului costisitor de IA (metoda InitAI), nlocuind instanierea unui obiect
MonsterSprite cu clonarea sa i modificarea caracteristicilor variabile. n
acest caz, va exista un PrototypeManager care va asigura crearea
montrilor, nlocuind o instruciune de tipul:

_mainMonster = new MonsterSprite(_listMonsters[_monsterType]);

cu:

_mainMonster = _prototypeManager.GetMonster(_monsterType);

DLL-ul coninnd clasa MonsterSprite se va folosi ca atare, fr
modificri.

Indicaie: pentru a face rapid o copie profund a unui obiect, se
poate utiliza serializarea ntr-o metod de tipul:

public static object Clone(object obj)
{
object objClone = null;
MemoryStream memory = new MemoryStream();
BinaryFormatter binForm = new BinaryFormatter();
binForm.Serialize(memory, obj);
memory.Position = 0;
objClone = binForm.Deserialize(memory);
return objClone;
}

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

178
n vederea utilizrii acestei modaliti de copiere, trebuie incluse n
proiect namespace-urile System.Runtime.Serialization i System.IO, iar
clasa trebuie decorat cu atributul [Serializable]. Aceast metod general
trebuie particularizat la situaia concret a aplicaiei.
n continuare, se prezint scheletul programului, care trebuie
optimizat dup cerinele precizate mai sus.

MainForm.cs

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Serialization;
using System.IO;

namespace Monster
{
public partial class MainForm : Form
{
List<Monster> _listMonsters;
MonsterSprite _mainMonster;
Random _rand = new Random();
int _monsterType = 0;
int _x, _y;
long _elapsed;
const int MonsterSize = 200;
const int MaxLevels = 4;
bool _gameOver = false;

public MainForm()
{
InitializeComponent();
}

private void loadSettingsToolStripMenuItem_Click(object sender, EventArgs e)
{
// ncarc
try
{
XmlSerializer serializer = new XmlSerializer(typeof(AllMonsters));
FileStream fs = new FileStream("settings.xml", FileMode.Open);
XmlReader reader = new XmlTextReader(fs);
AllMonsters ab = (AllMonsters)serializer.Deserialize(reader);
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 8. abloanele de proiectare Singleton i Prototip


179
reader.Close(); fs.Close();
serializer = null;

_listMonsters = new List<Monster>();

for (int i = 0; i < ab.Monsters.Length; i++)
_listMonsters.Add(ab.Monsters[i]);
}
catch
{
MessageBox.Show("Nu s-a putut incarca settings.xml");
return;
}

if (_listMonsters == null || _listMonsters.Count == 0)
{
MessageBox.Show("Fisier de configurare invalid: settings.xml");
_listMonsters = null;
return;
}
}

private void startNewGameToolStripMenuItem_Click(object sender, EventArgs e)
{
// start
if (_listMonsters == null || _listMonsters.Count == 0)
loadSettingsToolStripMenuItem.PerformClick();
if (_listMonsters == null)
return;

_monsterType = 0;
_gameOver = false;

try
{
_mainMonster = new MonsterSprite(_listMonsters[_monsterType]);
}
catch (Exception exc)
{
MessageBox.Show(exc.Message);
_mainMonster = null;
return;
}


Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

180
_elapsed = DateTime.Now.Ticks;
timer.Start();

Redraw();
}

private void Redraw()
{
try
{
_x = _rand.Next(pictureBox.Width - MonsterSize + 20);
_y = _rand.Next(pictureBox.Height - MonsterSize - 10);
pictureBox.Refresh();
}
catch
{
MessageBox.Show("Fereastra este prea mica");
_mainMonster = null;
return;
}
}

private void exitToolStripMenuItem_Click(object sender, EventArgs e)
{
Close();
}

private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
{
// despre program

const string copyright =
"Sablonul de proiectare Prototip\r\n" +
"Ingineria programarii\r\n" +
"(c) 2008-2012 Florin Leon\r\n" +
" http://florinleon.byethost24.com/lab_ip.htm ";

MessageBox.Show(copyright, "Despre Monstri");
}

private void pictureBox_Paint(object sender, PaintEventArgs e)
{

if (_mainMonster == null)
{
timer.Stop();
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 8. abloanele de proiectare Singleton i Prototip


181
e.Graphics.Clear(Color.White);
if (_gameOver)
{
e.Graphics.DrawString("Jocul s-a terminat!", new Font("Arial", 48),
Brushes.Red, 10, 10);
long dt = DateTime.Now.Ticks - _elapsed;
double ms = dt / 10000000.0;
e.Graphics.DrawString(ms.ToString("F3") + " s", new Font("Arial", 48),
Brushes.Red, 10, 80);
}
return;
}

_mainMonster.Draw(e.Graphics, _x, _y);
}

private void ShootMonster()
{
if (_mainMonster.Shoot())
{
_monsterType++;
if (_monsterType < MaxLevels)
{
try
{
_mainMonster = new MonsterSprite(_listMonsters[_monsterType]);
}
catch (Exception exc)
{
MessageBox.Show(exc.Message);
_mainMonster = null;
return;
}

Redraw();
}
else
{
_mainMonster = null;
_gameOver = true;
pictureBox.Refresh();
}
}
else
Redraw();
}
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

182
private void pictureBox_MouseDown(object sender, MouseEventArgs e)
{
if (_mainMonster != null)
{
if (e.X > _x && e.X < _x + MonsterSize && e.Y > _y && e.Y < _y + MonsterSize)
ShootMonster();
}
}

private void timer_Tick(object sender, EventArgs e)
{
Graphics g = pictureBox.CreateGraphics();
long dt = DateTime.Now.Ticks - _elapsed;
double ms = dt / 10000000.0;
g.FillRectangle(Brushes.White, 1, 1, 100, 20);
g.DrawString(ms.ToString("F3") + " s", new Font("Arial", 10), Brushes.Black, 1, 1);
}

private void Form1_Load(object sender, EventArgs e)
{
this.WindowState = FormWindowState.Maximized;
}
}
}

Un exemplu de fiier cu setri este dat mai jos.

settings.xml

<?xml version="1.0" encoding="us-ascii"?>
<AllMonsters>
<Monsters>
<Monster>
<Image>monster1.jpg</Image>
<Color>blue</Color>
<Lives>3</Lives>
</Monster>
<Monster>
<Image>monster2.jpg</Image>
<Color>green</Color>
<Lives>3</Lives>
</Monster>



Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 8. abloanele de proiectare Singleton i Prototip


183
<Monster>
<Image>monster3.jpg</Image>
<Color>black</Color>
<Lives>4</Lives>
</Monster>
<Monster>
<Image>monster4.jpg</Image>
<Color>red</Color>
<Lives>5</Lives>
</Monster>
</Monsters>
</AllMonsters>


Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

184

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com


185

Capitolul 9

ablonul de proiectare Faad

1. Obiectiv
2. Scop i motivaie
3. Aplicabilitate
4. Analiza ablonului
5. Exemplu de implementare
6. Aplicaie

1. Obiectiv

Obiectivul capitolului 9 este implementarea unui program dup
ablonul de proiectare structural Faad (engl. Faade).


2. Scop i motivaie

ablonul Faad asigur o interfa unitar pentru o mulime de
interfee ale unui subsistem. Faada definete o interfa de nivel nalt care
face subsistemul mai uor de utilizat.
Structurarea unui sistem n subsisteme reduce complexitatea. Unul
din scopurile unei proiectri corecte este acela de a minimiza comunicaiile
i dependenele dintre subsisteme. Un mod de a obine aceasta este
introducerea faadei, obiect care furnizeaz o singur interfa simplificat
pentru funcionalitile mai generale ale subsistemului.
De exemplu, putem considera un mediu de programare care d
aplicaiilor acces ctre un subsistem de compilare ce conine clase precum
Scanner, Parser, ProgramNode, BytecodeStream i ProgramNodeBuilder
(figura 9.1). Unele aplicaii specializate ar putea avea nevoie s acceseze
aceste clase direct, dar majoritatea aplicaiilor care folosesc compilatorul nu
sunt interesate de detalii precum parsarea sau generarea de cod, ci doresc
doar s compileze un program. Interfeele puternice dar de nivel sczut din
subsistemul compilator le complic sarcina.
Pentru a asigura o interfa de nivel nalt care s separe clienii de
aceste clase, subsistemul compilator include de asemenea o clas Compiler.
Aceast clas definete o interfa unitar pentru funcionalitatea
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

186
compilatorului i se comport ca o faad, oferind clientului o interfa
simplificat pentru subsistemul compilator.



Figura 9.1. Exemplu de sistem complex apelabil prin intermediul unei Faade


3. Aplicabilitate

Faadele se folosesc atunci cnd se dorete furnizarea unei interfee
simple pentru un sistem complex. Pe msur ce evolueaz, sistemele devin
de obicei din ce n ce mai complexe. Atunci cnd sunt folosite, majoritatea
modelelor sunt completate cu numeroase clase suplimentare, ceea ce face
sistemul mai uor de personalizat, dar de asemenea devine tot mai greu de
utilizat pentru clienii care nu au nevoie s l personalizeze. O faad poate
furniza o interfa implicit simpl a subsistemului, suficient de bun pentru
majoritatea clienilor. Doar clienii care au nevoie de mai mult flexibilitate
trebuie s utilizeze direct clasele subsistemului din spatele faadei.
De asemenea, un astfel de subsistem conine de multe ori
interdependene complexe. Folosirea sa ca atare ar crete cuplarea dintre
codul clientului i elementele subsistemului. Faada decupleaz subsistemul
de clieni, deoarece n acest caz clienii depind numai de faad.
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 9. ablonul de proiectare Faad


187
Utilizarea ablonului poate ajuta i structurarea pe niveluri a
subsistemelor, folosind cte o faad pentru a defini cte un punct de intrare
pentru fiecare nivel al subsistemului. Dac nivelurile subsistemului
comunic doar prin faade, cuplarea dintre ele va scdea de asemenea.


4. Analiza ablonului

Structura ablonului Faad este prezentat n figura 9.2.



Figura 9.2. Structura ablonului Faad

Considernd din nou elementele subsistemului compilator, pentru
exemplificare, participanii ablonului sunt:

Faada (Compiler)
o tie ce funcionaliti implementeaz clasele subsistemului;
o Trimite cererile clientului ctre obiectele subsistemului;
Clasele subsistemului (Scanner, Parser, ProgrameNode etc.)
o Implementeaz funcionalitatea subsistemului;
o Primesc apeluri de la obiectul Faad;
o Nu au cunotin despre Faad; apelurile sunt
unidirecionale: doar dinspre Faad ctre subsistem.

Clienii comunic cu subsistemul trimind cereri faadei, care le
trimite mai departe ctre obiectele subsistemului ce ndeplinesc efectiv
sarcinile. Faada trebuie s gestioneze interfaa cu clientul i s cunoasc
interfeele subsistemului.
Clienii care utilizeaz faada nu au nevoie s acceseze obiectele
subsistemului, ns acestea nu sunt ascunse. Rmne la latitudinea clientului
dac dorete s utilizeze interfaa simplificat a faadei sau s apeleze direct
funcionalitile de nivel sczut ale obiectelor subsistemului.
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

188
5. Exemplu de implementare

Codul C# corespunztor structurii ablonului Faad este prezentat
mai jos.

Subsistemele

class SubsystemOne
{
public void MethodOne()
{
Console.WriteLine("Metoda subsistemului 1 ");
}
}

class SubsystemTwo
{
public void MethodTwo()
{
Console.WriteLine("Metoda subsistemului 2");
}
}

class SubsystemThree
{
public void MethodThree()
{
Console.WriteLine("Metoda subsistemului 3");
}
}

class SubsystemFour
{
public void MethodFour()
{
Console.WriteLine("Metoda subsistemului 4");
}
}






Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 9. ablonul de proiectare Faad


189
Faada

class Facade
{
SubSystemOne _one;
SubSystemTwo _two;
SubSystemThree _three;
SubSystemFour _four;

public Facade()
{
_one = new SubSystemOne();
_two = new SubSystemTwo();
_three = new SubSystemThree();
_four = new SubSystemFour();
}

public void MethodA()
{
Console.WriteLine("Metoda A a Fatadei");
_one.MethodOne();
_two.MethodTwo();
_four.MethodFour();
}

public void MethodB()
{
Console.WriteLine("Metoda B a Fatadei");
_two.MethodTwo();
_three.MethodThree();
}
}

Clientul

public class Client
{
public static void Main(string[] args)
{
Facade f = new Facade();
f.MethodA();
f.MethodB();
Console.ReadLine();
}
}
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

190
6. Aplicaie

6.1. S se realizeze simularea unei comenzi de cumprare online a
unor produse. Exist clase pentru activiti precum nregistrarea cererii,
facturare, expediere, statistici privind cumprtorii. Clasa Facade se
constituie ntr-un punct de intrare unic pentru toate aceste activiti.

Indicaii. Diagrama de clase a aplicaiei este prezentat n figura 9.3.
Pentru iniializarea controlului checkedListBox din fereastra
principal se pot utiliza n constructor numele produselor furnizate de clasa
InfoProduse. Deoarece dorim s decuplm clientul (MainForm) de clasele
sistemului, numele sunt primite tot prin intermediul Faadei:

public MainForm()
{
InitializeComponent();
string[] produse = Facade.Produse();
for (int i = 0; i < produse.Length; i++)
checkedListBoxProduse.Items.Add(produse[i], false);
}

n evenimentul de apsare a butonului se valideaz (opional)
CNP-ul prin intermediul metodei statice a Faadei, apoi se instaniaz o
Faad cu datele citite din text-box-urile ferestrei principale i se proceseaz
comanda. O comand nu trebuie facturat i expediat dac nu s-a comandat
niciun produs.
Pentru statistici, se prelucreaz codul numeric personal:
SAALLZZJJNNNC, unde prima cifr reprezint sexul (impar = M, par = F),
urmtoarele 6 cifre reprezint data naterii (an, lun, zi), urmtoarele 2 cifre
reprezint codul judeului, urmtoarele 3 indic numrul de ordine din
registrul strii civile iar ultima e cifra de control. Persoanele nscute ntre
1900-1999 au prima cifr 1 sau 2, iar cele nscute dup 2000 au prima cifr
5 sau 6.
Validarea CNP-ului se poate face ntr-o metod de tipul:

private bool CNPValid()
{
string cnp = textBoxCNP.Text;

if (cnp.Length != 13)
return false;
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 9. ablonul de proiectare Faad


191

F
i
g
u
r
a

9
.
3
.

E
x
e
m
p
l
u

d
e

r
e
z
o
l
v
a
r
e
:

d
i
a
g
r
a
m
a

d
e

c
l
a
s
e

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

192
int suma = Convert.ToInt32(cnp[0].ToString()) * 2 +
Convert.ToInt32(cnp[1].ToString()) * 7 +
Convert.ToInt32(cnp[2].ToString()) * 9 +
Convert.ToInt32(cnp[3].ToString()) * 1 +
Convert.ToInt32(cnp[4].ToString()) * 4 +
Convert.ToInt32(cnp[5].ToString()) * 6 +
Convert.ToInt32(cnp[6].ToString()) * 3 +
Convert.ToInt32(cnp[7].ToString()) * 5 +
Convert.ToInt32(cnp[8].ToString()) * 8 +
Convert.ToInt32(cnp[9].ToString()) * 2 +
Convert.ToInt32(cnp[10].ToString()) * 7 +
Convert.ToInt32(cnp[11].ToString()) * 9;

int rest = suma % 11;

if ((rest < 10) && (rest.ToString() == cnp[12].ToString()) ||
(rest == 10) && (cnp[12] == '1'))
return true;

return false;
}

Interfaa cu utilizatorul poate arta ca n figura 9.4.



Figura 9.4. Exemplu de rezolvare: diagrama de clase

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com


193

Capitolul 10

ablonul de proiectare Proxy

1. Obiectiv
2. Scop i motivaie
3. Aplicabilitate
4. Analiza ablonului
5. Exemplu de implementare
6. Aplicaii

1. Obiectiv

Obiectivul capitolului 10 este implementarea unui program dup
ablonul de proiectare structural Proxy (o traducere posibil ar fi
Intermediar sau Delegare). Vom considera varianta proxy-ului de
protecie pentru stabilirea drepturilor de acces la nite documente protejate.
Tema pentru acas completeaz ablonul cu varianta proxy-ului la distan,
pentru accesarea distribuit a documentelor.


2. Scop i motivaie

ablonul Proxy asigur un nlocuitor pentru alt obiect pentru a
controla accesul la acesta.
Unul din motivele pentru controlarea accesului la un obiect este
ntrzierea crerii i iniializrii lui pn n momentul n care acesta trebuie
utilizat. De exemplu, s considerm un program de editare de documente
care poate conine obiecte grafice. Crearea unor obiecte-imagine raster de
mari dimensiuni poate fi foarte costisitoare din punct de vedere al timpului
necesar citirii fiierelor de pe harddisk, mai ales dac presupunem c sunt
stocate n format bmp. Deschiderea unui document trebuie s fie ns o
operaie rapid, deci crearea tuturor acestor obiecte costisitoare odat cu
deschiderea documentului trebuie evitat. Acest lucru nici nu este necesar,
deoarece nu toate imaginile vor fi vizibile n acelai timp.
O soluie este crearea la cerere a fiecrui obiect costisitor, n cazul
nostru acest lucru avnd loc n momentul n care o imagine devine vizibil.
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

194
Se pune problema ce vom plasa n document n locul imaginii reale
i cum putem ascunde faptul c imaginea este creat la cerere, astfel nct s
nu complicm implementarea editorului iar optimizarea s nu afecteze codul
de formatare i redare a imaginilor.
Se poate utiliza un alt obiect, un proxy de imagine, care s acioneze
ca nlocuitor al imaginii reale. Obiectul proxy acioneaz la fel ca imaginea
i o instaniaz cnd este nevoie, adic doar atunci cnd programul de
editare i cere s o afieze. Cererile ulterioare sunt transmise direct ctre
imaginea real i deci proxy-ul trebuie s aib o referin ctre aceasta
(figura 10.1).


Figura 10.1. Diagrama de clase a unui proxy de imagine

Referina la obiectul _image din ImageProxy va fi nul pn n
momentul n care editorul apeleaz metoda Draw i obiectul proxy
instaniaz imaginea real. Operaia Draw asigur faptul c imaginea este
instaniat nainte de a fi apelat obiectul Image.
Pn atunci, dac mai exist o metod GetSize care returneaz
dimensiunile imaginii, obiectul ImageProxy poate returna o valoare proprie
implicit. Dup instanierea imaginii raster, obiectul ImageProxy va returna
dimensiunile reale ale imaginii apelnd metoda GetSize din Image.


3. Aplicabilitate

ablonul Proxy poate fi aplicat oriunde este nevoie de o referin
mai sofisticat la un obiect. Sunt prezentate n continuare cteva situaii n
care se poate aplica acest ablon:
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 10. ablonul de proiectare Proxy


195
Proxy-ul la distan (engl. remote proxy) reprezint un obiect
local care intermediaz accesul la un obiect de pe o alt main. Este
util n general pentru aplicaiile distribuite;
Proxy-ul virtual (engl. virtual proxy) creeaz la cerere obiecte
costisitoare. Un exemplu este clasa ImageProxy din seciunea
anterioar. Imaginea real poate fi ns i o imagine descrcat de pe
internet; n acest caz proxy-ul poate afia o imagine temporar pn
cnd este descrcat imaginea real. ablonul nu se refer doar la
imagini, ci la orice obiect a crui creare necesit timp sau resurse
importante;
Proxy-ul de protecie (engl. protection proxy) controleaz
accesul la obiectul real. Este util atunci cnd obiectul reprezentat
presupune drepturi diferite de acces;
Referina inteligent (engl. smart reference) este un nlocuitor
pentru o referin, care efectueaz aciuni suplimentare n momentul
accesrii unui obiect. De exemplu, se poate folosi pentru pstrarea
cpiilor unor obiecte mari care pot sau nu s se modifice. Dac se
dorete crearea unei alte instane de acest tip, proxy-ul poate decide
s nu fac efectiv copia, folosind n continuare primul obiect. Dac
clientul ncearc s fac modificri n al doilea obiect, proxy-ul face
abia atunci copia i modificrile. De asemenea, se poate stabili astfel
numrul de referine ctre obiectul real, astfel nct acesta s poat fi
automat eliberat atunci cnd nu mai exist referine.


4. Analiza ablonului

Diagrama generic de clase a ablonului Proxy este prezentat n
figura 10.2.


Figura 10.2. Diagrama de clase a ablonului Proxy
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

196
Trebuie precizat c att clasa Proxy ct i clasa RealSubject au o
interfa identic, definit de clasa Subject, astfel nct un obiect proxy s
poat fi nlocuit de obiectul real. n funcie de tipul su, obiectul Proxy
trimite apelurile ctre obiectul RealSubject.


5. Exemplu de implementare

Codul C# corespunztor structurii ablonului Proxy este prezentat
mai jos.

Subiectul abstract

abstract class Subject
{
// Metode
abstract public void Request();
}

Subiectul real

class RealSubject : Subject
{
// Metode
override public void Request()
{
Console.WriteLine("Apelul din subiectul real");
}
}

Proxy

class Proxy : Subject
{
RealSubject _realSubject;

override public void Request()
{
// Se folosete iniializarea ntrziat
if (_realSubject == null)
_realSubject = new RealSubject();

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 10. ablonul de proiectare Proxy


197
_realSubject.Request();
}
}

Clientul

public class Client
{
public static void Main(string[] args)
{
// Se creeaz un proxy i se apeleaz metoda dorit
Proxy p = new Proxy();
p.Request();
}
}


6. Aplicaii

6.1. Realizai un program pentru accesul la o serie de documente
potrivit nivelului de acces al utilizatorului. Un schelet al aplicaiei pentru
construirea interfaei grafice cu utilizatorul (prezentat n figura 10.3) i
fiierele de configurare sunt incluse dup descrierea cerinelor i indicaiilor.



Figura 10.3. Exemplu de rezolvare: interfaa cu utilizatorul
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

198
Structur propus de fiiere este prezentat n figura 10.4.


Figura 10.4. Structura de fiiere a aplicaiei

Nivelurile de acces se dau n fiierul niveluri.txt:

Public
Privat
Confidential
Secret

Lista de utilizatori se gsete n fiierul utilizatori.txt, care este de
forma specificat n tabelul 10.1.

Tabelul 10.1. Exemplu de list de utilizatori
Numele
utilizatorului
Hash-ul parolei
Nivelul
de acces
admin 0DPiKuNIrrVmD8IUCuw1hQxNqZc= -1
pu 8DqjUKTMEIhL2P06I5dcoOT+yDA= 0
pr VJjZuW7Sgy4EqQxKwqtx+Gmyv9w= 1
se AHYsz6cDOT4Nr/gTpuzBn3zQJCE= 3
co h92iBBZknypqGwPU4T1IqAsaNX8= 2
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 10. ablonul de proiectare Proxy


199
Pe prima coloan este numele utilizatorului. Pe coloana a doua este
hash-ul parolei, pentru evitarea stocrii n clar a acesteia. La autentificare, se
va calcula hash-ul parolei i se va compara cu hash-ul din fiier. Pe a treia
coloan se noteaz nivelul de acces. Administratorul este un tip special de
utilizator. Acesta nu poate consulta documente, dar poate aduga utilizatori.
Iniial, numele administratorului este admin i parola este tot admin. n
situaia de mai sus, parolele utilizatorilor sunt egale cu numele lor. n
program, la autentificarea unui utilizator se verific existena utilizatorului i
corectitudinea parolei.
Documentele din directorul Documente au asociate i ele drepturi de
acces, setate n fiierul drepturi.txt:

public1.rtf public2.rtf
privat1.rtf privat2.rtf
confidential.rtf
topsecret.rtf

Pe prima linie sunt documentele corespunztoare primului nivelul de
acces (Public), pe linia a doua documentele pentru nivelul Privat .a.m.d.
Cnd un utilizator se autentific, el primete lista documentelor de pe
nivelul su de acces dar i documentele de pe nivelurile inferioare. Se
presupune c serverul de documente ar fi pe alt main. La selectarea unui
document, acesta este criptat i trimis clientului care l decripteaz i l
afieaz. Accesul la documente se va face printr-un proxy de protecie.
Acesta la rndul su acceseaz managerul real de documente. Clasele
ProxyDocumentManager i RealDocumentManager vor implementa ambele
interfaa IDocumentManager.
Diagrama de clase a aplicaiei este prezentat n figura 10.5.

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

200

Figura 10.5. Exemplu de rezolvare: diagrama de clase

ProxyDocumentManager se ocup de autentificare i gestionarea
drepturilor de acces. Metodele GetDocumentList i GetDocument apeleaz
metodele corespunztoare din RealDocumentManager. RealDocumentManager
cripteaz documentul i l trimite ctre ProxyDocumentManager. Aceast
operaie este important mai ales atunci cnd ProxyDocumentManager i
RealDocumentManager se afl pe maini diferite (situaia de la tem).
Atunci cnd ProxyDocumentManager primete documentul, i
afieaz coninutul criptat n EncryptedDocForm. Este o operaie opional,
util doar pentru a vedea mai clar aspectul unui fiier binar transformat ca
string n baza 64, prin apelul metodei ToBase64String. Pentru a nu
incomoda, aceast fereastr secundar poate fi implicit minimizat:

_encryptedDocForm = new EncryptedDocForm(encryptedFile);
_encryptedDocForm.WindowState = FormWindowState.Minimized;
_encryptedDocForm.Show();

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 10. ablonul de proiectare Proxy


201
n vederea afirii documentului decriptat ntr-un control de tip
RichTextBox de ctre MainForm, se utilizeaz proprietatea Rtf a controlului,
de exemplu: richTextBox.Rtf = decryptedRtfDoc.
Pentru a v putea concentra exclusiv asupra aplicrii ablonului, n
continuare se dau cteva clase ce urmeaz a fi completate sau utilizate n
program.

MainForm.cs

namespace ProtectionProxy
{
public partial class MainForm : Form
{
private ProxyDocumentManager _proxyDocumentManager;

public MainForm()
{
InitializeComponent();
groupBoxAdmin.Enabled = false;
_proxyDocumentManager = new ProxyDocumentManager();
}
}
}

DocumentManager.cs

namespace ProtectionProxy
{
interface IDocumentManager
{
List<string> GetDocumentList();
string GetDocument(string documentName, string encryptionPassword);
}
}

ProxyDocumentManager.cs

namespace ProtectionProxy
{
public class ProxyDocumentManager : IDocumentManager
{
private RealDocumentManager _realDocumentManager;
private List<User> _users;

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

202
private List<string> _levels;
private const string Path = "Secure\\";

public struct User
{
public readonly string Name;
public readonly string PassHash;
public readonly int AccessLevel;

public User(string name, string passHash, int accessLevel)
{
Name = name;
PassHash = passHash;
AccessLevel = accessLevel;
}
}

public ProxyDocumentManager()
{
_levels = new List<string>();
StreamReader sr = new StreamReader(Path + "niveluri.txt");
string[] lvls = sr.ReadToEnd().Split(" \t\r\n".ToCharArray(),
StringSplitOptions.RemoveEmptyEntries);
sr.Close();

for (int i = 0; i < lvls.Length; i++)
_levels.Add(lvls[i]);

_users = new List<User>();
sr = new StreamReader(Path + "utilizatori.txt");
string line;
while ((line = sr.ReadLine()) != null)
{
string[] toks = line.Split('\t');
User user = new User(toks[0], toks[1], Convert.ToInt32(toks[2]));
_users.Add(user);
}
sr.Close();
}

#region IDocumentManager Members

public List<string> GetDocumentList()
{
throw new Exception("The method or operation is not implemented.");
}
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 10. ablonul de proiectare Proxy


203
public string GetDocument(string documentName, string encryptionPassword)
{
throw new Exception("The method or operation is not implemented.");
}

#endregion
}
}

RealDocumentManager.cs

namespace ProtectionProxy
{
class RealDocumentManager : IDocumentManager
{
private static List<List<string>> _documents;
private const string Path = "Secure\\", DocPath = "Secure\\Documente\\";

static RealDocumentManager()
{
int numberOfLevels = 0;
StreamReader sr = new StreamReader(Path + "drepturi.txt");
string[] lines = sr.ReadToEnd().Split("\r\n".ToCharArray(),
StringSplitOptions.RemoveEmptyEntries);
sr.Close();
numberOfLevels = lines.Length;

_documents = new List<List<string>>(numberOfLevels);
for (int i = 0; i < numberOfLevels; i++)
_documents.Add(new List<string>());

sr = new StreamReader(Path + "drepturi.txt");
for (int i = 0; i < numberOfLevels; i++)
{
string[] files = sr.ReadLine().Split();
for (int j = i; j < numberOfLevels; j++)
{
for (int k = 0; k < files.Length; k++)
_documents[j].Add(files[k]);
}
}
sr.Close();
}


Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

204
#region IDocumentManager Members
public List<string> GetDocumentList()
{
throw new Exception("The method or operation is not implemented.");
}

public string GetDocument(string documentName, string encryptionPassword)
{
throw new Exception("The method or operation is not implemented.");
}

#endregion
}
}

Observaii: parola pentru criptarea unui documentului transmis se
poate considera cunoscut de ctre ProxyDocumentManager i
RealDocumentManager, astfel nct s nu mai apar ca parametru n metoda
GetDocument (encryptionPassword). Stabilirea n mod dinamic a unei
parole comune ntre dou entiti care comunic printr-un canal public este
o problem n sine i nu poate fi tratat aici. De asemenea, parola folosit
pentru criptarea documentelor este diferit de parola utilizatorului i nici nu
trebuie s fie cunoscut de ctre acesta.
Constructorul static al clasei RealDocumentManager asigur faptul
c listele cu drepturile de acces vor fi iniializate o singur dat nainte de
utilizarea efectiv a clasei de ctre ProxyDocumentManager. Constructorul
static este apelat automat nainte de a fi creat prima instan a clasei sau
nainte de referenierea membrilor statici.

Cryptography.cs

/**************************************************************************
* Website: http://www.obviex.com/samples/Encryption.aspx *
* Adaptation and added functionality by Florin Leon *
* http://florinleon.byethost24.com/lab_ip.htm *
* Description: Contains functions for encryption, decryption, *
* and hashing. *
**************************************************************************/

using System;
using System.Security.Cryptography;
using System.IO;
using System.Text;

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 10. ablonul de proiectare Proxy


205
namespace ProtectionProxy
{
public class Cryptography
{
/// <summary>
/// Encrypts specified plaintext using Rijndael symmetric key algorithm
/// and returns a base64-encoded result.
/// </summary>
/// <param name="plainText">
/// Plaintext value to be encrypted.
/// </param>
/// <param name="passPhrase">
/// Passphrase from which a pseudo-random password will be derived. The
/// derived password will be used to generate the encryption key.
/// Passphrase can be any string. In this example we assume that this
/// passphrase is an ASCII string.
/// </param>
/// <param name="saltValue">
/// Salt value used along with passphrase to generate password. Salt can
/// be any string. In this example we assume that salt is an ASCII string.
/// </param>
/// <param name="hashAlgorithm">
/// Hash algorithm used to generate password. Allowed values are: "MD5" and
/// "SHA1". SHA1 hashes are a bit slower, but more secure than MD5 hashes.
/// </param>
/// <param name="passwordIterations">
/// Number of iterations used to generate password. One or two iterations
/// should be enough.
/// </param>
/// <param name="initVector">
/// Initialization vector (or IV). This value is required to encrypt the
/// first block of plaintext data. For RijndaelManaged class IV must be
/// exactly 16 ASCII characters long.
/// </param>
/// <param name="keySize">
/// Size of encryption key in bits. Allowed values are: 128, 192, and 256.
/// Longer keys are more secure than shorter keys.
/// </param>
/// <returns>
/// Encrypted value formatted as a base64-encoded string.
/// </returns>
public static string Encrypt(string text, string pass)
{
string plainText = text;
string passPhrase = pass;
string saltValue = "s@1tValue"; // can be any string
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

206
string hashAlgorithm = "SHA1";// can be "MD5"
int passwordIterations = 2; // can be any number
string initVector = "@1B2c3D4e5F6g7H8"; // must be 16 bytes
int keySize = 256; // can be 192 or 128

// Convert strings into byte arrays.
// Let us assume that strings only contain ASCII codes.
// If strings include Unicode characters, use Unicode, UTF7, or UTF8
// encoding.
byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue);

// Convert our plaintext into a byte array.
// Let us assume that plaintext contains UTF8-encoded characters.
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);

// First, we must create a password, from which the key will be derived.
// This password will be generated from the specified passphrase and
// salt value. The password will be created using the specified hash
// algorithm. Password creation can be done in several iterations.
PasswordDeriveBytes password = new PasswordDeriveBytes(
passPhrase,
saltValueBytes,
hashAlgorithm,
passwordIterations);

// Use the password to generate pseudo-random bytes for the encryption
// key. Specify the size of the key in bytes (instead of bits).
byte[] keyBytes = password.GetBytes(keySize / 8);

// Create uninitialized Rijndael encryption object.
RijndaelManaged symmetricKey = new RijndaelManaged();

// It is reasonable to set encryption mode to Cipher Block Chaining
// (CBC). Use default options for other symmetric key parameters.
symmetricKey.Mode = CipherMode.CBC;

// Generate encryptor from the existing key bytes and initialization
// vector. Key size will be defined based on the number of the key
// bytes.
ICryptoTransform encryptor = symmetricKey.CreateEncryptor(
keyBytes,
initVectorBytes);

// Define memory stream which will be used to hold encrypted data.
MemoryStream memoryStream = new MemoryStream();
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 10. ablonul de proiectare Proxy


207
// Define cryptographic stream (always use Write mode for encryption).
CryptoStream cryptoStream = new CryptoStream(memoryStream,
encryptor,
CryptoStreamMode.Write);
// Start encrypting.
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);

// Finish encrypting.
cryptoStream.FlushFinalBlock();

// Convert our encrypted data from a memory stream into a byte array.
byte[] cipherTextBytes = memoryStream.ToArray();

// Close both streams.
memoryStream.Close();
cryptoStream.Close();

// Convert encrypted data into a base64-encoded string.
string cipherText = Convert.ToBase64String(cipherTextBytes);

// Return encrypted string.
return cipherText;
}

/// <summary>
/// Decrypts specified ciphertext using Rijndael symmetric key algorithm.
/// </summary>
/// <param name="cipherText">
/// Base64-formatted ciphertext value.
/// </param>
/// <param name="passPhrase">
/// Passphrase from which a pseudo-random password will be derived. The
/// derived password will be used to generate the encryption key.
/// Passphrase can be any string. In this example we assume that this
/// passphrase is an ASCII string.
/// </param>
/// <param name="saltValue">
/// Salt value used along with passphrase to generate password. Salt can
/// be any string. In this example we assume that salt is an ASCII string.
/// </param>
/// <param name="hashAlgorithm">
/// Hash algorithm used to generate password. Allowed values are: "MD5" and
/// "SHA1". SHA1 hashes are a bit slower, but more secure than MD5 hashes.
/// </param>
/// <param name="passwordIterations">
/// Number of iterations used to generate password. One or two iterations
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

208
/// should be enough.
/// </param>
/// <param name="initVector">
/// Initialization vector (or IV). This value is required to encrypt the
/// first block of plaintext data. For RijndaelManaged class IV must be
/// exactly 16 ASCII characters long.
/// </param>
/// <param name="keySize">
/// Size of encryption key in bits. Allowed values are: 128, 192, and 256.
/// Longer keys are more secure than shorter keys.
/// </param>
/// <returns>
/// Decrypted string value.
/// </returns>
/// <remarks>
/// Most of the logic in this function is similar to the Encrypt
/// logic. In order for decryption to work, all parameters of this function
/// - except cipherText value - must match the corresponding parameters of
/// the Encrypt function which was called to generate the
/// ciphertext.
/// </remarks>
public static string Decrypt(string text, string pass)
{
string cipherText = text;
string passPhrase = pass;
string saltValue = "s@1tValue"; // can be any string
string hashAlgorithm = "SHA1";// can be "MD5"
int passwordIterations = 2; // can be any number
string initVector = "@1B2c3D4e5F6g7H8"; // must be 16 bytes
int keySize = 256; // can be 192 or 128
// Convert strings defining encryption key characteristics into byte
// arrays. Let us assume that strings only contain ASCII codes.
// If strings include Unicode characters, use Unicode, UTF7, or UTF8
// encoding.
byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue);

// Convert our ciphertext into a byte array.
byte[] cipherTextBytes = Convert.FromBase64String(cipherText);

// First, we must create a password, from which the key will be
// derived. This password will be generated from the specified
// passphrase and salt value. The password will be created using
// the specified hash algorithm. Password creation can be done in
// several iterations.

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 10. ablonul de proiectare Proxy


209
PasswordDeriveBytes password = new PasswordDeriveBytes(
passPhrase,
saltValueBytes,
hashAlgorithm,
passwordIterations);

// Use the password to generate pseudo-random bytes for the encryption
// key. Specify the size of the key in bytes (instead of bits).
byte[] keyBytes = password.GetBytes(keySize / 8);

// Create uninitialized Rijndael encryption object.
RijndaelManaged symmetricKey = new RijndaelManaged();

// It is reasonable to set encryption mode to Cipher Block Chaining
// (CBC). Use default options for other symmetric key parameters.
symmetricKey.Mode = CipherMode.CBC;

// Generate decryptor from the existing key bytes and initialization
// vector. Key size will be defined based on the number of the key
// bytes.
ICryptoTransform decryptor = symmetricKey.CreateDecryptor(
keyBytes,
initVectorBytes);

// Define memory stream which will be used to hold encrypted data.
MemoryStream memoryStream = new MemoryStream(cipherTextBytes);

// Define cryptographic stream (always use Read mode for encryption).
CryptoStream cryptoStream = new CryptoStream(memoryStream,
decryptor,
CryptoStreamMode.Read);

// Since at this point we don't know what the size of decrypted data
// will be, allocate the buffer long enough to hold ciphertext;
// plaintext is never longer than ciphertext.
byte[] plainTextBytes = new byte[cipherTextBytes.Length];

// Start decrypting.
int decryptedByteCount = cryptoStream.Read(plainTextBytes,
0,
plainTextBytes.Length);

// Close both streams.
memoryStream.Close();
cryptoStream.Close();

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

210
// Convert decrypted data into a string.
// Let us assume that the original plaintext string was UTF8-encoded.
string plainText = Encoding.UTF8.GetString(plainTextBytes,
0,
decryptedByteCount);

// Return decrypted string.
return plainText;
}

/// <summary>
/// Returns the hash of a string
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static string HashString(string str)
{
HashAlgorithm sha = new SHA1CryptoServiceProvider();
byte[] buf = new byte[str.Length];
for (int i = 0; i < str.Length; i++)
buf[i] = (byte)str[i];
byte[] result = sha.ComputeHash(buf);
return Convert.ToBase64String(result);
}
}
}


6.2. Tem pentru acas. Extindei programul astfel nct
documentele i managerul de documente s poat fi pe un alt calculator iar
proxy-ul s nglobeze i funcionaliti de delegare la distan. Opional,
pentru eficientizarea comunicaiilor, se poate avea n vedere arhivarea
documentului trimis nainte de criptare.

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com


211

Capitolul 11

ablonul de proiectare Comand

1. Obiective
2. Scop i motivaie
3. Aplicabilitate
4. Analiza ablonului
5. Exemplu de implementare
6. Aplicaie

1. Obiective

Obiectivul principal al capitolului 11 este implementarea unui
program dup ablonul de proiectare comportamental Comand (engl.
Command). Se va prezenta i o metod de generare i adugare dinamic
a unor controale n fereastra unui program.


2. Scop i motivaie

ablonul Comand ncapsuleaz o funcie ntr-un obiect, astfel nct
este posibil trimiterea unor funcii ca parametri, formarea de cozi de
apeluri, nregistrarea listei de apeluri (engl. logging) i asigurarea
suportului pentru operaiile de anulare (engl. undo).
S presupunem o aplicaie cu o bar de instrumente care poate fi
personalizat. Cu fiecare buton al barei, utilizatorul i poate asocia funcia
dorit. Deci, din punct de vedere al proiectantului, nu se poate cunoate
apriori nici operaia propriu-zis care va fi efectuat de un buton i nici
obiectul concret care va realiza operaia respectiv. De asemenea, pentru a
avea o arhitectur elegant, toate butoanele trebuie tratate n mod unitar.
Soluia propus de ablonul Comand este ncapsularea unui astfel
de apel ntr-un obiect, care poate fi stocat sau trimis ca parametru altor
obiecte. Dup cum se poate vedea n figura 11.1, clasa abstract Command
include o operaie Execute, implementat de ctre clasele concrete derivate,
care conin ca i cmp destinatarul apelului (obiectul care va realiza efectiv
operaia) i care i vor transfera acestuia apelul de execuie a operaiei.
Pentru simplitate, s-au omis semnturile metodelor. Trebuie subliniat faptul
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

212
c aceste clase de comand sunt clase normale, care pot include i alte
cmpuri i metode pe lng metoda Execute specific ablonului.



Figura 11.1. Exemplu de sistem bazat pe ablonul Comand

n acest exemplu, destinatarii sunt clasele Document i Image.
Comanda PasteCommand are un cmp de tipul Document iar clasa
FlipCommand are un cmp de tipul Image. La apelul metodelor Execute,
obiectele de comand apeleaz metodele corespunztoare din obiectele
destinatar, dup unele eventuale prelucrri suplimentare.
Clasele de comand sunt derivate dintr-o clas de baz comun i
deci pot fi tratate unitar, chiar dac operaiile lor Execute au implementri
diferite.
ablonul permite de asemenea definirea unor comenzi macro, adic
a unei mulimi de operaii. O astfel de clas, prezentat n figura 11.2, poate
avea un vector de comenzi simple, pe care le apeleaz succesiv.



Figura 11.2. Comand macro
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 11. ablonul de proiectare Comand


213
Clasa MacroCommand este derivat la rndul su din aceeai clas
abstract Command, deci poate fi tratat ca orice alt comand. Ea nu are
ns un destinatar explicit, deoarece comenzile din serie au propriul
destinatar.
n msura n care sistemul dispune de mai multe comenzi, dac
gestionarea acestora ar aparine exclusiv clientului, acest fapt ar conduce la
creterea cuplrii ntre aceste clase. De aceea, ablonul introduce o clas
suplimentar, Invoker, care este responsabil de setarea dinamic a
comenzilor i de apelarea acestora. n exemplul anterior, bara de
instrumente este un Invoker, care gestioneaz comenzile asociate cu
butoanele sale, iar aplicaia (clasa corespunztoare ferestrei principale, de
exemplu) este clientul. Odat ce o comand a fost introdus n Invoker, ea
poate fi executat (o dat sau de mai multe ori), poate fi eliminat sau
nlocuit n mod dinamic.
Una din trsturile foarte importante care pot fi implementate uor
cu ajutorul ablonului Comand este asigurarea operaiilor de anulare (engl.
undo) i refacere (engl. redo) a ultimelor aciuni.
n general, chiar dac aplicaia are mai multe comenzi, exist cte o
singur opiune de anulare, respectiv refacere. De aceea, sistemul trebuie s
cunoasc succesiunea operaiilor efectuate i modul n care starea sistemului
este modificat de fiecare comand. Astfel, clasele de comand vor avea
dou metode suplimentare, Undo i Redo i vor trebui s rein starea
sistemului nainte de aplicarea comenzii i dup aplicarea sa (figura 11.3).


Figura 11.3. Comand cu operaii de anulare i refacere

Clasa Invoker poate reine ntr-o stiv succesiunea de comenzi
efectuate iar dac se dorete de exemplu anularea ultimelor n aciuni, se va
apela metoda Undo din cele n elemente scoase din stiv.
Putem spune c ablonul decupleaz obiectul care invoc o operaie
de cel care tie cum s o efectueze, ceea ce ofer un grad ridicat de
flexibilitate n proiectarea unei aplicaii. n cazul interfeei grafice cu
utilizatorul, o aplicaie poate furniza pentru o funcie att o interfa cu
meniuri, ct i una cu butoane i n acest caz meniurile i butoanele vor fi
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

214
asociate cu aceleai instane ale claselor concrete de comand. Comenzile
pot fi nlocuite n mod dinamic, lucru util pentru implementarea meniurilor
sensibile la context. De asemenea, prin compunerea comenzilor ntr-unele
de mai mari dimensiuni, se poate facilita generarea script-urilor de
comand.


3. Aplicabilitate

ablonul Comand poate fi utilizat n primul rnd atunci cnd
trebuie s se trimit o aciune ca parametru unui obiect, aa cum este cazul
n situaia cu bara de instrumente prezentat anterior. Trimiterea poate fi
fcut i prin intermediul unei funcii de apelare invers (engl. callback).
De exemplu, codul de tratare a evenimentelor n platforma .NET este
ncapsulat n funcii delegat i utilizat sub forma:

button.Click += new System.EventHandler(button_Click)

Comenzile reprezint un echivalent orientat obiect pentru funciile
de apelare invers.
S presupunem c ntr-un sistem de echilibrarea ncrcrii,
activitile de calcul (task-urile) trebuie transferate pe diferite maini.
Fiecare activitate de calcul este diferit. Pentru a trata n mod unitar toate
aceste activiti, ele pot fi ncapsulate n obiecte de comand. La fel, dac
activitile sunt preluate pentru rulare de fire de execuie dintr-un bazin
(engl. thread pool), utilizarea comenzilor simplific foarte mult procesul,
deoarece un fir de execuie nu trebuie s tie dect c o activitate are o
metod Execute care trebuie apelat.
Dup cum am menionat, o comand poate avea posibilitatea anulrii
sau refacerii aciunii. Dac sistemul trebuie s permit anularea i refacerea
unei ntregi succesiuni de comenzi, acest fapt poate fi uor implementat prin
introducerea n Invoker a unor liste (sau stive) de comenzi pentru anulare,
respectiv refacere. n momentul cnd se anuleaz o operaie, comanda
respectiv se scoate din lista comenzilor de anulare i se introduce n lista
comenzilor de refacere. Se procedeaz analog n cazul apelrii unei operaii
de refacere. Prin traversarea acestor liste se pot asigura oricte niveluri de
anulare i refacere.
Pentru sisteme care gestioneaz date foarte complexe, salvarea strii
n cazul blocrii se poate face tot cu ajutorul comenzilor. n aceast situaie
nu este fezabil salvarea datelor dup fiecare operaie efectuat. Aplicaia
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 11. ablonul de proiectare Comand


215
poate s pstreze o nregistrare (engl. log) cu seria de comenzi efectuate
de la pornirea sa. Dac la un moment dat sistemul se blocheaz, starea sa
poate fi refcut din cea iniial, aplicnd n ordine comenzile salvate pe
harddisk. n interfaa obiectelor de comand pot fi adugate operaii de
ncrcare i salvare. Salvarea comenzilor poate fi att o list cu
identificatorii i parametrii acestora, ct i serializarea efectiv a obiectelor
de comand aplicate.


4. Analiza ablonului

Diagrama generic de clase a ablonului Comand este prezentat n
figura 11.4.


Figura 11.4. Diagrama de clase a ablonului Comand

Clasa abstract (sau interfaa) Command declar metode precum
Execute, eventual Undo i Redo. Clasele concrete ConcreteCommand
implementeaz operaia Execute prin invocarea operaiei sau operaiilor
corespunztoare din obiectul Receiver. Clasa Receiver tie cum s efectueze
operaiile asociate cu executarea unei comenzi. Orice clas poate servi drept
destinatar. Clasa Invoker cere comenzii s execute aciunea. Clientul creeaz
un obiect ConcreteCommand i i stabilete destinatarul.
Modul n care acioneaz participanii este detaliat n diagrama de
secvene din figura 11.5.



Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

216

Figure 11.5. Diagrama de secvene a ablonului Comand

Clientul creeaz obiectul ConcreteCommand i i precizeaz
destinatarul. Obiectul Invoker stocheaz obiectul ConcreteCommand. Cnd
este nevoie, obiectul Invoker apeleaz operaia Execute din obiectul
Command. n cazul n care comenzile pot fi anulate, obiectul
ConcreteCommand i stocheaz starea pentru anularea comenzii nainte de
a aplica operaia Execute. Obiectul ConcreteCommand apeleaz operaiile
din obiectul Receiver pentru a ndeplini aciunea propriu-zis.
Consecina principal a ablonului este decuplarea obiectului care
invoc o operaie de obiectul care tie cum s o efectueze. Astfel, noi
comenzi pot fi adugate foarte uor deoarece nu sunt necesare modificri ale
claselor existente.


5. Exemplu de implementare

Codul C# corespunztor structurii ablonului Comand este
prezentat n cele ce urmeaz.

Comanda abstract

abstract class Command
{
protected Receiver _receiver;

public Command(Receiver receiver)
{
_receiver = receiver;
}
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 11. ablonul de proiectare Comand


217
abstract public void Execute();
}

Comanda concret

class ConcreteCommand : Command
{
public ConcreteCommand(Receiver receiver) : base(receiver)
{
}

public override void Execute()
{
_receiver.Action();
}
}

Destinatarul

class Receiver
{
public void Action()
{
Console.WriteLine("Apelul metodei din destinatar");
}
}

Invocatorul

class Invoker
{
private Command _command;

public void SetCommand(Command command)
{
_command = command;
}

public void ExecuteCommand()
{
_command.Execute();
}
}

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

218
Clientul

public class Client
{
public static void Main(string[] args)
{
// Se creeaz destinatarul, comanda i invocatorul
Receiver r = new Receiver();
Command c = new ConcreteCommand(r);
Invoker i = new Invoker();

// Se seteaz i se execut comanda
i.SetCommand(c);
i.ExecuteCommand();
}
}


6. Aplicaii

6.1. Realizai un program care simuleaz o foaie de calcul (gen
Microsoft Excel). Un schelet al aplicaiei pentru construirea interfeei grafice
cu utilizatorul (prezentat n figura 11.6) este inclus dup observaii i
recomandri.


Figura 11.6. Exemplu de rezolvare: interfaa cu utilizatorul



Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 11. ablonul de proiectare Comand


219
Observaii:

Controlul de tip grid este realizat dinamic cu text-box-uri. Alternativ,
se poate lucra cu un control DataGridView;
Componentele controlului sunt de fapt de tip ExtendedTextBox,
clas derivat din TextBox, care include o metod de formatare
special a numerelor din foaia de calcul: cu dou zecimale i aliniate
la dreapta. Atunci cnd se editeaz textul unui ExtendedTextBox, n
momentul n care se apas ENTER sau se prsete controlul
respectiv, deci cnd se trimite comanda, Text-ul este deja modificat.
Pentru a pstra ntr-un mod mai convenabil starea anterioar, se
poate folosi proprietatea PreviousText. Cum ar putea fi proiectat
comanda de modificare a textului unei celule pentru a nu fi nevoii s
folosii aceast proprietate?
Rmne la latitudinea proiectantului s stabileasc gradul de
complexitate al comenzilor dac o comand acioneaz asupra unui
TextBoxGrid sau asupra unui ExtendedTextBox. De obicei, se
recomand utilizarea unor comenzi ct mai simple.

Recomandri:

Se poate lucra cu trei clase de comenzi, pentru schimbarea textului,
schimbarea formatului i schimbarea culorii unui ExtendedTextBox;
Comanda va primi n constructor o referin la ExtendedTextBox-ul
asupra cruia se fac modificrile (acesta este Receiver-ul).

Pentru a v putea concentra exclusiv asupra aplicrii ablonului, n
continuare se dau cteva clase ce urmeaz a fi completate sau utilizate n
program.

MainForm.cs

namespace Spreadsheet
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();


Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

220
_grid = new TextBoxGrid(Controls, 25, 120,
new KeyEventHandler(textBox_KeyDown),
new EventHandler(textBox_Leave));

_invoker = new Invoker(_grid);
}

TextBoxGrid _grid;
Invoker _invoker;
int _selected;

private void textBox_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
// cnd se apas ENTER ntr-o celul

ExtendedTextBox tb = (ExtendedTextBox)sender;
string name = tb.Name;
_selected = Convert.ToInt32(name.Substring(2));
this.ActiveControl = _grid.GetSuccessor(_selected);
}
}

private void textBox_Leave(object sender, EventArgs e)
{
// cnd o celul nu mai este controlul selectat activ din fereastr

Control ac = this.ActiveControl;
ExtendedTextBox tb = (ExtendedTextBox)sender;
string name = tb.Name;
_selected = Convert.ToInt32(name.Substring(2));

tb.FormatText();

// de completat - tratarea schimbrii textului

this.ActiveControl = ac;
UpdateUndoRedoCombos();
}

private void buttonColor_Click(object sender, EventArgs e)
{
if (colorDialog1.ShowDialog() != DialogResult.OK)
return;

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 11. ablonul de proiectare Comand


221
Color c = colorDialog1.Color;
buttonColor.ForeColor = c;
//buttonColor.BackColor = Color.FromArgb(255 - c.R, 255 - c.G, 255 - c.B);

// de completat
UpdateUndoRedoCombos();
}

private void buttonNormal_Click(object sender, EventArgs e)
{
// de completat
UpdateUndoRedoCombos();
}

private void buttonBold_Click(object sender, EventArgs e)
{
// de completat
UpdateUndoRedoCombos();
}

private void buttonItalic_Click(object sender, EventArgs e)
{
// de completat
UpdateUndoRedoCombos();
}

private void UpdateUndoRedoCombos()
{
comboBoxUndo.Items.Clear();
string[] str = _invoker.UndoNames.ToArray();
for (int i = 0; i < str.Length; i++)
comboBoxUndo.Items.Add(str[i]);
if (comboBoxUndo.Items.Count > 0)
{
comboBoxUndo.SelectedIndex = 0;
buttonUndo.Enabled = true;
}
else
buttonUndo.Enabled = false;

comboBoxRedo.Items.Clear();
str = _invoker.RedoNames.ToArray();
for (int i = 0; i < str.Length; i++)
comboBoxRedo.Items.Add(str[i]);


Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

222
if (comboBoxRedo.Items.Count > 0)
{
comboBoxRedo.SelectedIndex = 0;
buttonRedo.Enabled = true;
}
else
buttonRedo.Enabled = false;
}

private void buttonUndo_Click(object sender, EventArgs e)
{
_invoker.Undo();
UpdateUndoRedoCombos();
}

private void buttonRedo_Click(object sender, EventArgs e)
{
_invoker.Redo();
UpdateUndoRedoCombos();
}

private void buttonExit_Click(object sender, EventArgs e)
{
Close();
}
}
}

ExtendedTextBox.cs

namespace Spreadsheet
{
class ExtendedTextBox : TextBox
{
private string _previousText;

public string PreviousText
{
get { return _previousText; }
set { _previousText = value; }
}




Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 11. ablonul de proiectare Comand


223
public ExtendedTextBox()
: base()
{
_previousText = "";
}

public void FormatText()
{
double d;
if (double.TryParse(Text, out d))
{
Text = d.ToString("F2");
TextAlign = HorizontalAlignment.Right;
}
else
TextAlign = HorizontalAlignment.Left;
}
}
}

TextBoxGrid.cs

namespace Spreadsheet
{
class TextBoxGrid
{
private ExtendedTextBox[] _textBoxes;
public const int Size = 5;

public TextBoxGrid(Control.ControlCollection controlCollection, int left, int top,
KeyEventHandler keyDownEvent, EventHandler leaveEvent)
{
_textBoxes = new ExtendedTextBox[Size * Size];
for (int i = 0; i < Size * Size; i++)
{
int x = i % Size;
int y = i / Size;

_textBoxes[i] = new ExtendedTextBox();
_textBoxes[i].Width = 100;
_textBoxes[i].Height = 20;
_textBoxes[i].Left = left + x * 100;
_textBoxes[i].Top = top + y * 20;
_textBoxes[i].Text = "";
_textBoxes[i].Name = "Tb" + i;
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

224
_textBoxes[i].KeyDown += keyDownEvent;
_textBoxes[i].Leave += leaveEvent;

controlCollection.Add(_textBoxes[i]);
}

for (int i = 0; i < Size * Size; i++)
_textBoxes[i].PreviousText = _textBoxes[i].Text;

Label[] labelsX = new Label[Size];
for (int i = 0; i < Size; i++)
{
labelsX[i] = new Label();
labelsX[i].Text = ((char)(i + 'A')).ToString();
labelsX[i].Left = left + i * 100 + 48;
labelsX[i].Top = top - 15;
controlCollection.Add(labelsX[i]);
}

Label[] labelsY = new Label[Size];
for (int i = 0; i < Size; i++)
{
labelsY[i] = new Label();
labelsY[i].Text = (i + 1).ToString();
labelsY[i].Left = left - 15;
labelsY[i].Height = 20;
labelsY[i].Top = top + i * 20 + 4;
controlCollection.Add(labelsY[i]);
}
}

public void Clear()
{
for (int i = 0; i < Size * Size; i++)
{
_textBoxes[i].Clear();
_textBoxes[i].Font = new Font(_textBoxes[i].Font, FontStyle.Regular);
_textBoxes[i].ForeColor = Color.Black;
_textBoxes[i].PreviousText = _textBoxes[i].Text;
}
}

public ExtendedTextBox GetSuccessor(int cellNumber)
{
cellNumber = (cellNumber + 1) % (Size*Size);
return _textBoxes[cellNumber];
}
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 11. ablonul de proiectare Comand


225
public string GetCoords(int cellNumber)
{
char tbx = (char)((cellNumber % Size) + 'A');
int tby = cellNumber / Size + 1;
return tbx.ToString() + tby;
}

public ExtendedTextBox GetCell(int cellNumber)
{
return _textBoxes[cellNumber];
}
}
}

ICommand.cs

namespace Spreadsheet
{
interface ICommand
{
bool Execute();
void Undo();
void Redo();
}
}

Invoker.cs

namespace Spreadsheet
{
class Invoker
{
private TextBoxGrid _grid;
private Stack<ICommand> _commands;
private Stack<ICommand> _redoCommands;
private Stack<string> _undoNames, _redoNames;

public Stack<string> RedoNames
{
get { return _redoNames; }
}



Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

226
public Stack<string> UndoNames
{
get { return _undoNames; }
}

public Invoker(TextBoxGrid grid)
{
_grid = grid;
_commands = new Stack<ICommand>();
_redoCommands = new Stack<ICommand>();
_undoNames = new Stack<string>();
_redoNames = new Stack<string>();
}

public void SetAndExecute(ICommand command, string description)
{
// de completat
}

public void Undo() // (int level)
{
// este foarte simpl anularea mai multor niveluri de aciuni:
// a ultimelor "level" comenzi

// de completat
}

public void Redo() // (int level)
{
// de completat
}
}
}

ChangeColorCommand.cs

namespace Spreadsheet
{
class ChangeColorCommand : ICommand
{
ExtendedTextBox _textBox;
// alte cmpuri



Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 11. ablonul de proiectare Comand


227
public ChangeColorCommand(ExtendedTextBox textBox, Color color)
{
//...
}

public bool Execute()
{
//...
// returneaz true dac se modific ceva n _textBox
// returneaz false dac nu se modific nimic
return false;
}

public void Undo()
{
//...
}

public void Redo()
{
//...
}
}
}

ChangeFormatCommand.cs

namespace Spreadsheet
{
class ChangeFormatCommand : ICommand
{
ExtendedTextBox _textBox;
// alte cmpuri

public ChangeFormatCommand(ExtendedTextBox textBox, FontStyle format)
{
//...
}

public bool Execute()
{
//...
// exemplu de schimbare a corpului de liter:
// _textBox.Font = new Font(_textBox.Font, _newStyle);
// returneaz true dac se modific ceva n _textBox
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

228
// returneaz false dac nu se modific nimic
return false;
}

public void Undo()
{
//...
}

public void Redo()
{
//...
}
}
}

ChangeTextCommand.cs

namespace Spreadsheet
{
class ChangeTextCommand : ICommand
{
ExtendedTextBox _textBox;
// alte cmpuri

public ChangeTextCommand(ExtendedTextBox textBox)
{
//...
}

public bool Execute()
{
// textul nou deja exist n _textBox.Text

//...
// returneaz true dac se modific ceva n _textBox
// returneaz false dac nu se modific nimic
return false;
}

public void Undo()
{
//...
}

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 11. ablonul de proiectare Comand


229
public void Redo()
{
//...
}
}
}


6.2. Tem pentru acas. Extindei programul astfel nct s permit
operaii simple cu numerele din celule (figura 11.7).


Figura 11.7. Exemplu de rezolvare: adugarea unor operaii matematice simple

La apsarea tastei ENTER n celula D1, coninutul su va deveni
5.00. Operaii permise vor fi: Add (adunare), Sub (scdere), Mul
(nmulire), Div (mprire), cu exact 2 parametri. Se va afia un mesaj de
eroare dac celulele trimise ca argumente nu conin numere valide. Cnd
cursorul revine n celula D1, deci cnd rencepe editarea celulei, va aprea
din nou formula. Rezultatul operaiei apare numai cnd celula nu este
selectat. Se vor pstra operaiile de anulare (undo) i refacere (redo).

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

230

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com


231

Capitolul 12

Evaluarea vitezei de execuie a unui program

1. Obiective
2. Metoda DateTime
3. Pointeri n C#
4. Metoda PerformanceCounter
5. Metoda Stopwatch
6. Compilarea JIT
7. Aplicaii

1. Obiective

Cnd dorim s evalum performanele unei aplicaii software, de
cele mai multe ori ncercm s-i determinm viteza de execuie. Exist
diverse strategii pentru determinarea acesteia, fie direct, prin msurarea ct
mai precis a intervalului de timp dintre pornirea programului (sau a unei
funcii care ne intereseaz) i oprirea sa, fie indirect, prin evaluarea
numrului de instruciuni i a naturii acestora, abordare ntlnit mai ales n
studiile teoretice de determinare a complexitii.
n acest capitol, vom descrie trei metode de msurare direct a
vitezei de execuie a unui program.


2. Metoda DateTime

Prima metod utilizeaz clasa DateTime. Proprietatea
DateTime.Now.Ticks numr intervalele de (teoretic!) 100 de nanosecunde
scurse de la ora 0 a datei de 1 ianuarie, anul 1. Pentru msurarea timpului
dintre dou momente, se preia aceast valoare la cele dou momente i se
face diferena. De exemplu, la pornirea unei funcii, respectiv dup
terminarea execuiei sale:

long startTicks = DateTime.Now.Ticks;
ApelFunctie();
double dif = (DateTime.Now.Ticks - startTicks) / 10000.0;
// dif este calculat n milisecunde

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

232
Avantajul acestei metode este simplitatea sa din punctul de vedere al
programatorului. Practic, metoda se poate folosi pentru intervale de timp
mai mari, de peste 1 ms.


3. Pointeri n C#

De multe ori, funciile scrise n C sau C++ primesc pointeri ca
parametri. Dei n C# nu este uzual lucrul cu pointeri, acest limbaj (spre
deosebire de Java) l permite n cadrul unor construcii speciale. De
exemplu, ntr-un DLL poate exista o funcie cu urmtorul prototip:

int NumarDivizori (int *n);

Importarea acestei funcii se va face astfel:

[DllImport("Divizibilitate", EntryPoint="NumarDivizori")]
private static unsafe extern int DllNumarDivizori(int* n);

public static unsafe int NumarDivizori(int n)
{
int arg = n, rez = 0;

// adresa argumentului este "fixat" n memorie, deoarece managementul automat
// al memoriei presupune "mutarea" diferitelor zone de memorie n vederea optimizrii
fixed (int *pArg = &arg)
{
// apelul se face cu adresa argumentului arg
rez = DllNumarDivizori(pArg);
}

return rez;
}

Pentru compilarea codului unsafe, trebuie prevzut aceast opiune
n proprietile proiectului din Solution Explorer.

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 12. Evaluarea vitezei de execuie a unui program


233

Figura 12.1. Opiunea pentru compilarea codului unsafe

S considerm acum cazul n care funcia C returneaz un pointer.
De exemplu, o funcie pentru concatenarea a dou iruri de caractere:

extern "C" __declspec(dllexport) char* MyAppend(char* first, char* second)
{
char *result = new char[strlen(first) + strlen(second)];
strcpy(result, first);
strcat(result, second);
return result;
}

Importarea acestei funcii se va face n felul urmtor:

[DllImport("StringDll", EntryPoint = "MyAppend")]
public static extern unsafe IntPtr StringAppend(
[MarshalAs(UnmanagedType.LPStr)]
string arg1,
[MarshalAs(UnmanagedType.LPStr)]
string arg2
);

Directiva MarshalAs stabilete modul de interpretare a argumentelor
i a tipurilor de return la interfaa dintre memoria gestionat de mediul .NET
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

234
(managed) i cea negestionat (unmanaged). Interpretarea se face n
momentul execuiei programului. n exemplul de mai sus, funcia C
primete un pointer la ir de caractere, care este convertit automat din tipul
C# string la apel. Funcia ntoarce de asemenea un pointer: IntPtr. Pentru
convertirea rezultatului napoi la string n C#, se pot folosi instruciuni de
tipul:

IntPtr target = StringAppend(str1, str2);
string s = Marshal.PtrToStringAnsi(target);

Pentru a putea importa o funcie cu DllImport, trebuie inclus
namespace-ul System.Runtime.InteropServices.


4. Metoda PerformanceCounter

Pentru intervale mai precise, se poate folosi o alt metod care
presupune apelarea direct a funciilor Windows de lucru cu numrtorul
calculatorului:

[DllImport("kernel32", EntryPoint = "QueryPerformanceFrequency")]
private static unsafe extern bool QueryPerformanceFrequency(Int64* f);

[DllImport("kernel32", EntryPoint = "QueryPerformanceCounter")]
private static unsafe extern bool QueryPerformanceCounter(Int64* c);

static Int64 _t1, _t2, _htrFrecv;
static bool _htrInit;

static PerformanceCounterSpeed()
{
// iniializarea numrtorului - o singur dat nainte de utilizarea clasei
InitCounter();
}

private static unsafe bool InitCounter()
{
_t1 = 0; _t2 = 0; _htrFrecv = 0; _htrInit = false;
fixed (Int64* frecv = &_htrFrecv)
{
_htrInit = QueryPerformanceFrequency(frecv);
}
return _htrInit;
}
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 12. Evaluarea vitezei de execuie a unui program


235
public unsafe void BeginTest()
{
fixed (Int64* t1 = &_t1)
{
QueryPerformanceCounter(t1);
}
}

/// <summary>
/// Returneaz diferena n milisecunde
/// </summary>
/// <returns></returns>
public unsafe double EndTest()
{
fixed (Int64* t2 = &_t2)
{
QueryPerformanceCounter(t2);
}
Int64 difCounts = _t2 - _t1;
double difSeconds = (double)difCounts / (double)_htrFrecv;
return difSeconds * 1000.0;
}


4.1. Metode de accelerare

O metod mai simpl de a apela funciile de mai sus din kernel32
este folosind tipul long n loc de Int64*.
Programul poate fi accelerat prin eliminarea verificrilor de
securitate la apelul funciilor unmanaged, cu ajutorul atributului
SuppressUnmanagedCodeSecurity:

[System.Security.SuppressUnmanagedCodeSecurity()]
private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);

Cnd din cod managed se apeleaz funcii unmanaged, se realizeaz
verificarea permisiunilor de securitate pentru a stabili dac apelantul are
drepturile necesare pentru a face apelul. Prin aplicarea explicit a acestui
atribut, se elimin aceste verificri, ceea ce crete viteza de execuie.
De asemenea, un program compilat n mod Release este n general
mai rapid dect acelai cod compilat n mod Debug.


Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

236
5. Metoda Stopwatch

O metod care combin simplitatea apelurilor oferit de clasa
DateTime cu precizia funciilor PerformanceCounter este utilizarea clasei
Stopwatch din namespace-ul System.Diagnostics.
Msurarea timpului de execuie se realizeaz astfel:

long startTicks = Stopwatch.GetTimestamp();
ApelFunctie();
double dif = (Stopwatch.GetTimestamp() - _startTicks) * 1000.0 / Stopwatch.Frequency;
// dif este calculat n milisecunde

Indiferent de metoda de msurare aleas, se recomand efectuarea
mai multor experimente pentru aceeai funcie i apoi calcularea statistic a
valorii medii i deviaiei standard.


6. Compilarea JIT

n mod tradiional, exist dou modaliti principale de execuie a
codului surs pe un procesor: interpretarea i compilarea. Codul interpretat
este transformat n cod main n mod continuu la fiecare executare. Codul
compilat static este transformat n cod main o singur dat, naintea
execuiei.
Interpretarea necesit mai puine resurse, ns timpul de execuie este
mai mare din cauza stratului software suplimentar care prelucreaz
instruciunile. Un limbaj interpretat permite unele lucruri imposibile ntr-un
limbaj compilat, de exemplu adugarea sau modificarea unor funcii chiar n
timpul execuiei. De obicei dezvoltarea aplicaiilor ntr-un limbaj interpretat
este mai simpl deoarece nu este necesar compilarea ntregului program
cnd se dorete testarea numai a unor seciuni mici de cod.
Ca exemple de limbaje interpretate putem aminti versiunile iniiale
de Perl, Ruby sau Matlab. Compilatoare exist pentru majoritatea limbajelor
de programare importante, precum C, C++, Pascal etc.
Dup cum am amintit i n capitolul 1, seciunea 3.1, compilarea
la timp (engl. just-in-time compilation, JIT) reprezint o abordare
hibrid, n care transformarea n cod main are loc continuu, ca n cazul
interpretoarelor, ns codul transformat este stocat (engl. cached) pentru a
nu afecta viteza de execuie a programului. Unitatea de compilare este
metoda. Unitile sunt compilate n cod nativ doar nainte de prima utilizare.
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 12. Evaluarea vitezei de execuie a unui program


237
Pe platforma .NET, toate limbajele folosesc Common Language
Runtime, CLR, maina virtual responsabil pentru gestionarea execuiei
programelor. CLR compileaz codul intermediar CIL n instruciuni main
executate de procesorul calculatorului. CLR mai asigur servicii
suplimentare cum ar fi managementul memoriei, sigurana tipurilor (engl.
type safety) i tratarea excepiilor. Indiferent de limbajul de programare,
toate programele scrise pentru platforma .NET sunt executate de ctre CLR.
ntruct optimizrile de baz sunt realizate n timpul compilrii
codului surs, compilarea din CIL n cod main este mult mai rapid.
Compilatorul JIT produce cod nativ puternic optimizat pe baza datelor
despre mediul de execuie, proces numit profiling. Acesta reprezint
capacitatea de a msura viteza de execuie a prilor unei aplicaii sau a
ntregii aplicaii, astfel nct s fie descoperite zonele care provoac
ntrzieri. De exemplu, se poate descoperi care metode sunt utilizate
frecvent i acestea pot fi transformate n cod inline. Dei chiar i aceste
optimizri consum un timp suplimentar, viteza de execuie crete la
apelurile ulterioare.
Compilatorul JIT cauzeaz o mic ntrziere la prima execuie a unei
aplicaii, din cauza timpului necesar pentru ncrcarea i compilarea codului
intermediar. n general, cu ct mai multe optimizri realizeaz JIT, cu att
mai bun este codul generat, ns crete i ntrzierea iniial. Un compilator
JIT trebuie s realizeze deci un compromis ntre calitatea codului generat i
timpul necesar pentru compilare.
Utilitarul Native Image Generator, Ngen, poate fi o soluie pentru
reducerea ntrzierii iniiale. Ngen precompileaz codul intermediar n cod
main nativ i de aceea nu mai este necesar compilarea n momentul
execuiei. Platforma .NET 2.0 precompileaz toate bibliotecile DLL dup
instalare. Precompilarea asigur o modalitate de a mbunti timpul de
pornire a aplicaiilor, ns calitatea codului compilat poate fi inferioar
compilrii JIT, aa cum i codul compilat static, fr optimizri ghidate de
profil, este inferioar codului compilat la timp.
Precompilarea unui assembly se poate realiza cu o comand de tipul:

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\ngen.exe install nume-assembly

Calea ctre utilitar poate fi diferit, n funcie de versiunea
platformei .NET utilizate. Imaginea precompilat a unui assembly poate fi
ndeprtat din cache folosindu-se opiunea uninstall.
Figura 12.2 prezint comportamentul aceluiai program (un exemplu
de rezolvare pentru aplicaia 7.1), care msoar viteza de execuie a unor
funcii. n stnga, pentru versiunea compilat JIT, se observ c execuia
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

238
iniial a funciilor dureaz mai mult dect apelurile ulterioare. n dreapta,
pentru versiunea precompilat cu Ngen, se observ c toate apelurile au un
timp relativ egal de execuie.



Figura 12.2. Viteza de execuie a unor funcii n variantele:
a) compilate JIT; b) precompilate

n cazul general ns, nu se poate garanta c un cod precompilat cu
Ngen va avea performane superioare fa de versiunea compilat la timp.
Exist i metode mai complicate de a precompila assembly-urile prin
program, ns acestea nu fac obiectul prezentului capitol.


7. Aplicaii

7.1. Evaluai viteza de execuie a urmtorilor algoritmi de sortare,
pentru vectori de numere reale de diferite dimensiuni: Quick sort, Shell sort
i Bubble sort.
Se va crea cte o clas pentru fiecare din cele trei metode, care s
implementeze o interfa comun:


Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 12. Evaluarea vitezei de execuie a unui program


239
void BeginTest();
double EndTest(); // returneaz diferena

Un exemplu de rezolvare, cu dou variante de execuie, este
prezentat n figura 12.3.



Figura 12.3. Exemplu de rezolvare: interfaa cu utilizatorul

n continuare, se prezint un schelet al clasei care implementeaz
algoritmii de sortare considerai.

namespace Speed
{
public class Sorting
{
public static void QuickSort(double[] vector)
{
DoQuickSort(vector, 0, vector.Length - 1);
}

private static void DoQuickSort(double[] vector, int low, int high)
{
if (high > low)
{
int k = Partition(vector, low, high); // procedura de partiionare
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

240
DoQuickSort(vector, low, k - 1);
DoQuickSort(vector, k + 1, high);
}
}

private static int Partition(double[] vector, int low, int high)
{
int l = low;
int h = high;
double x = vector[l];
double temp;

while (l < h)
{
while ((vector[l] <= x) && (l < high)) l++;
while ((vector[h] > x) && (h >= low)) h--;

if (l < h)
{
temp = vector[l];
vector[l] = vector[h];
vector[h] = temp;
}
}

temp = vector[h];
vector[h] = vector[low];
vector[low] = temp;

return h;
}

public static void ShellSort(double[] vector)
{
for (int dist = vector.Length / 2; dist > 0; dist /= 2)
for (int i = dist; i < vector.Length; i++)
for (int j = i - dist; j >= 0 && vector[j] > vector[j + dist]; j -= dist)
{
double aux = vector[j];
vector[j] = vector[j + dist];
vector[j + dist] = aux;
}
}


Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 12. Evaluarea vitezei de execuie a unui program


241
public static void BubbleSort(double[] vector)
{
// de completat cu varianta neoptimizat O(n
2
)
}
}
}

Observaii:

Pentru a le putea compara performanele, trebuie s ne asigurm c
toi algoritmii sunt aplicai aceluiai vector. n cazul vectorilor
generai aleatoriu, utili pentru studierea complexitii medii, exist
dou variante:
o S se memoreze un vector, care s fie copiat de fiecare dat
nainte de aplicarea unui algoritm;
o S se genereze pentru fiecare algoritm acelai vector de
numere aleatorii. n C#, generarea unui numr aleatoriu se
face cu ajutorul unui obiect de tip Random. Acesta este de
fapt un generator de numere pseudoaleatorii, n care numrul
urmtor este generat pe baza numrului anterior, aplicnd un
algoritm specific. Dac se pleac de fiecare dat de la acelai
numr, se va genera de fiecare dat acelai ir. n acest scop
se poate trimite ca parametru n constructor un numr seed,
care ajut la iniializarea generatorului. Dac acest parametru
lipsete (constructorul vid), se utilizeaz implicit timpul
curent, care este de fiecare dat diferit i deci i irul de
numere generat va fi de asemenea diferit. Aceast metod
este mai eficient deoarece elimin consumul suplimentar de
memorie necesar pentru pstrarea vectorului;
Pentru timpi de execuie mici, este normal ca metoda DateTime s
returneze valoarea 0;
Nu este obligatorie afiarea grafic a comparaiei ntre timpii de
execuie ai algoritmilor;
O metod util de sortare n C# este Array.Sort, care garanteaz
complexitatea .


7.2. Tem pentru acas. Extindei programul prin adugarea unui alt
algoritm de sortare (la alegere) i afiai grafic comparativ timpii de execuie
ai algoritmilor.

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

242






Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com


243

Capitolul 13

Testarea unitilor cu NUnit

1. Obiectiv
2. Testarea unitilor
3. Utilizarea platformei NUnit
4. Aplicaii

1. Obiectiv

n capitolul 13, vom descrie o metod de testare a unitilor folosind
platforma dedicat NUnit.


2. Testarea unitilor

Testarea unitilor este o metod de a verifica funcionalitatea
corect a unitilor individuale de cod surs. O unitate este cea mai mic
parte testabil dintr-o aplicaie. Scopul testrii unitilor este de a izola
fiecare parte a unui program i de a arta c prile individuale sunt corecte.
Testarea unei uniti furnizeaz un contract scris i strict pe care codul
respectiv trebuie s l satisfac. Astfel, testarea unitilor ajut la
descoperirea din timp a problemelor n ciclul de dezvoltare.
Testarea unitilor permite programatorului s refactorizeze codul
mai trziu, i asigur n continuare funcionalitatea corect. De exemplu,
testarea de regresiune presupune ca atunci cnd un defect este descoperit i
corectat, se nregistreaz i un test care expune defectul, astfel nct acesta
s poat fi retestat dup schimbrile ulterioare ale programului. n mod
normal sunt scrise teste pentru toate metodele astfel nct atunci cnd o
modificare provoac un defect, acesta s poat fi uor identificat i reparat.
Testarea unitilor ajut la eliminarea incertitudinii privind codul i poate fi
folosit ntr-o abordare de testare bottom-up. Prin testarea mai nti a
prilor unui program i apoi a sumei prilor, testarea de integrare devine
mult mai uoar.
Testarea unitilor asigur un fel de documentaie vie a sistemului.
Dezvoltatorii care vor s afle funcionalitile oferite de o unitate i cum este
ea folosit i pot studia testele pentru a avea o nelegere de baz asupra
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

244
API-ului su. Cazurile de test pot indica folosirea potrivit sau nepotrivit a
unitii. Documentaia narativ clasic este mai predispus la apariia
diferenelor fa de implementare i deci poate deveni mai uor depit.
Testarea este o activitate distinct de depanare (engl. debugging),
dei graniele celor dou nu sunt stricte. Testarea este procesul metodic de a
demonstra existena defectelor din program. Depanarea este activitatea de
descoperire a cauzelor defectelor. Testarea conduce la depanare, care
conduce la reparare, care conduce la re-testare pentru a demonstra c
repararea a fost corect.


3. Utilizarea platformei NUnit

NUnit este o platform open source pentru testarea unitilor pentru
aplicaii .NET. Are acelai scop ca i JUnit pentru aplicaii Java. Pentru a
descrie modul de lucru cu NUnit, s considerm o clas pentru efectuarea
unor operaii artimetice elementare:

public class MathOps
{
public static double Add(double x, double y)
{
return x + y;
}

public static double Sub(double x, double y)
{
return x - y - 1; // rezultat incorect
}

public static double Mul(double x, double y)
{
return x * y + 0.5; // rezultat incorect
}

public static double Div(double x, double y)
{
if (x == 0 && y == 0)
throw new Exception("Undefined operation.");
// if (y == 0)
// throw new Exception("Division by zero."); // lipsete excepia
return x / y;
}
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 13. Testarea unitilor cu NUnit


245
public static double Pow(double x, double y)
{
throw new Exception("The method or operation is not implemented.");
}
}

Pentru a utiliza platforma NUnit, trebuie adugat mai nti o
referin la assembly-ul nunit.framework.dll aflat n directorul
NUnit 2.4.8\bin\. Pentru versiunile ulterioare este de presupus c numele
acestuia se va modifica n mod corespunztor.
Pentru fiecare clas testat, se recomand crearea unei alte clase de
test. n aceste fiiere trebuie inclus namespace-ului NUnit.Framework.
Pentru a indica faptul c o clas este destinat testrii cu NUnit, se
folosete atributul [TestFixture].

Important! Clasele marcate [TestFixture] trebuie s fie publice.

[TestFixture]
public class OperatiiTest
{
...
}

n aceast clas vom include metodele de testare. Aceste metode
trebuie s fie obligatoriu fr parametri i s aib tipul de return void. O
astfel de metod este marcat cu atributul [Test]. De exemplu:

[Test]
public void Addition()
{
Assert.AreEqual(3, MathOps.Add(1, 2));
}

Cea mai des utilizat modalitate de testare este cu clasa Assert. n
metoda AreEqual primul parametru reprezint valoarea ateptat iar al doilea
rezultatul operaiei testate.
n legtur cu operaiile Assert trebuie fcute cteva precizri:

Aseriunile nu nlocuiesc excepiile. Excepiile se refer la
necesitile codului, aseriunile se refer la presupunerile codului;
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

246
O aseriune ne poate spune nu numai ce s-a ntmplat i unde (ca o
excepie), ci i de ce;
Aseriunile pot fi considerate i o form de documentaie,
comunicnd celorlali dezvoltatori ce presupuneri s-au fcut n
implementare, presupuneri de care depinde corecta funcionare a
programului.

Cnd o aseriune este adevrat, nseamn c totul se desfoar aa
cum era prevzut. Cnd este fals, nseamn c a aprut o eroare neateptat
n cod. De exemplu, dac un programator presupune c ntr-un fiier nu vor
exista niciodat mai mult de 50000 de linii, se poate pune o aseriune cu
privire la numrul de linii din fiierul citit. Dac programul ntlnete un
fiier mai mare, presupunerea a fost greit i programatorul trebuie
avertizat.
Aceste metode sunt utile deci pentru depistarea erorilor semantice,
aa cum compilatorul semnaleaz erorile sintactice. Aseriunile trebuie s
indice erorile programatorului, nu ale utilizatorului.

[Test]
public void Subtraction()
{
Assert.AreEqual(-1, MathOps.Sub(1, 2));
}

[Test]
public void Multiplication()
{
Assert.AreEqual(12, MathOps.Mul(3, 4));
}

[Test]
public void Division()
{
Assert.AreEqual(2.0 / 3.0, MathOps.Div(2, 3));
}

n cazul operaiei de mprire, pot fi aruncate excepii dac
argumentele sunt invalide. n cazul testrii, dac argumentele sunt invalide,
ne ateptm ca apelul s determine aruncarea unei excepii. Programul testat
are un defect dac nu se arunc excepia. n NUnit, aceast situaie este
tratat cu ajutorul atributului [ExpectedException()], care primete ca
parametru tipul de excepie ateptat. n cazul nostru, avem doar excepii de
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 13. Testarea unitilor cu NUnit


247
tipul de baz Exception. Dac am crea clase particulare de excepie pentru
fiecare situaie, am putea testa c i tipul de excepie aruncat este cel
corect.

[Test]
[ExpectedException(typeof(Exception))]
public void DivisionExc1()
{
MathOps.Div(0, 0);
}

[Test]
[ExpectedException(typeof(Exception))]
public void DivisionExc2()
{
MathOps.Div(5, 0);
}

Cnd unele metode din programul testat nu sunt nc implementate,
ceea ce ar determina oricum picarea testului, se poate marca o metod de
test cu atributul [Ignore], care primete ca parametru un mesaj de
atenionare. n cazul nostru, operaia Pow nu este nc implementat. Testul
poate fi ns scris de la nceput i cnd operaia va fi implementat se va
elimina doar atributul de ignorare din metoda de test.

[Test]
[Ignore("Operatia nu este inca implementata")]
public void Power()
{
Assert.AreEqual(8, MathOps.Pow(2, 3));
}

n continuare, se compileaz programul i se deschide interfaa
vizual a platformei NUnit: aplicaia nunit.exe din acelai director
NUnit 2.4.8\bin\. Se creeaz eventual un nou proiect i se adaug
assembly-ul care trebuie testat din meniul Project Add Assembly... (de
exemplu Operatii.exe). Apoi se apas butonul Run (figura 13.1).

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

248

Figura 13.1. Platforma NUnit: interfaa grafic

Pentru fiecare metod care se testeaz se pot obine informaii
suplimentare cu click-dreapta, Properties. Pe lng detalii legate de
comportamentul ateptat, sunt incluse i evaluri ale timpului de execuie al
metodelor testate.
n continuare, se face depanarea programului, se recompileaz i se
ruleaz din nou testele n interfaa NUnit. La apsarea butonului Run,
assembly-ul este rencrcat, deci testele se vor face pe noua variant a
programului.
Clasa de test poate conine cmpuri proprii. Dac este nevoie de
iniializarea lor nainte de rularea celorlalte metode de test, iniializarea se
realizeaz ntr-o metod marcat cu atributul [SetUp]. De exemplu:

[TestFixture]
public class AccountTest
{
Account _source;
Account _destination;

[SetUp]
public void Init()
{
_source = new Account();
_source.Deposit(200.00f);
_destination = new Account();
_destination.Deposit(150.00f);
}

[Test]
public void TransferFunds()
{
_source.TransferFunds(_destination, 100.00f);
Assert.AreEqual(250.00f, _destination.Balance);
Assert.AreEqual(100.00f, _source.Balance);
}
}
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 13. Testarea unitilor cu NUnit


249
NUnit permite ca o metod s fie rulat dup terminarea tuturor
testelor prin marcarea ei cu atributul [TearDown]. Acest metod se poate
folosi de exemplu pentru dezalocarea unor resurse utilizate la teste.
O clas de test poate avea doar o singur metod SetUp i doar o
singur metod TearDown. Dac sunt definite mai multe, programul va
compila, dar testele nu vor rula. Metoda TearDown nu va rula dac metoda
SetUp eueaz sau arunc o excepie.
n concluzie, testele NUnit pot fi create fr a modifica programul
testat i pot fi eliminate n varianta pregtit pentru lansare. Clasa Assert
este utilizat de obicei pentru compararea rezultatelor ateptate cu cele reale.
Metoda care testeaz egalitatea este cea mai folosit. De fiecare dat cnd
proiectul se modific, testele unitilor trebuie rulate din nou pentru a
verifica dac funcionalitatea existent nu a fost afectat.


4. Aplicaii

4.1. Implementai programul cu operaii aritmetice prezentat mai sus.
Creai cazurile de test descrise i rulai-le n interfaa NUnit.

4.2. Realizai un program care calculeaz numrul de zile diferen
ntre un moment referin ales arbitrar (1 ianuarie 2000) i o dat introdus
de utilizator. Diferena de zile ntre oricare dou date poate fi calculat prin
adunarea sau scderea rezultatelor obinute prin dou apeluri succesive ale
acestei funcii. Nu se vor folosi clasele specializate din C# gen DateTime.

Date de intrare: o dat calendaristic n formatul zi / lun / an.
Date de ieire: diferena de zile (pozitiv sau negativ).

Se vor considera cazurile de test din tabelul 13.1.

Tabelul 13.1. Cazuri de test
Data Rezultat corect
4.07.2003 1280
29.02.2100 dat invalid
10.05.2000 130
5.01.2000 4
15.10.3404 513088
2.01.2009 3289
30.04.1972 -10107
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

250
Data Rezultat corect
15.12.1999 -17
1.01.1976 -8766
5.11.1997 -787
20.03.79 -701552
32.12.1988 dat invalid

Diagramele UML ale celor dou clase sunt prezentate n figura 13.2.


Figura 13.2. Diagrama UML a clasei Zile i cea a clasei de test

Indicaii: Problema principal la calcularea diferenei de zile este
determinarea numrului de ani biseci. Regula pentru a determina dac un an
este bisect este urmtoarea: anul este divizibil cu 4, dar nu este divizibil cu
100 sau este divizibil cu 400. De exemplu, anul 1900 nu a fost bisect iar
2000 a fost an bisect pentru c este divizibil cu 400. Se poate utiliza
secvena urmtoare de cod:

int[] nrzile = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

if (_an % 4 == 0 && _an % 100 != 0 || _an % 400 == 0)
nrzile[1] = 29;

Proprietatea Diferenta este readonly (are numai accesorul get).
Metoda Calculeaza arunc o excepie dac data este invalid.


Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 13. Testarea unitilor cu NUnit


251
O alternativ la aceast proiectare a clasei Zile este declararea unei
metode statice de tipul:

public static int CalculeazaDiferenta(int zi, int luna, int an)

n acest fel, s-ar evita posibila aruncare a unei excepii la instanierea
unui obiect Zile, situaie care nu este foarte elegant.

Realizai mai nti cazurile de test i apoi implementai metodele
clasei Zile, verificnd la fiecare modificare rezultatele n interfaa vizual
NUnit.

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

252

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com

253

Capitolul 14

Rapoarte de testare

1. Obiective
2. Testarea unei ierarhii de clase
3. Aplicaie

1. Obiective

Scopul capitolului 14 este prezentarea unei modaliti de utilizare a
platformei NUnit pentru testarea unei ierarhii de clase fr duplicarea
codului de test i realizarea unui raport de testare complet pentru o problem
(aparent) simpl de clasificare a triunghiurilor.


2. Testarea unei ierarhii de clase

S considerm un program care indic tipul unui triunghi pe baza
lungimilor laturilor sale: scalen (oarecare), isoscel (dou laturi egale),
echilateral (toate trei laturi egale). Programul mai trebuie s verifice dac
triunghiul determinat de cele trei valori este un triunghi valid. Avem patru
variante de clase: Triangle1, Triangle2, Triangle3 i Triangle4 (figura 14.1),
toate cu aceeai structur, fiind diferite doar implementrile metodelor.


Figura 14.1. Ierarhia claselor care trebuie testate
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

254
Vor fi necesare mai multe teste pentru fiecare tip de triunghi, cu
exact acelai cod, adic aceleai valori ale laturilor i rezultate ateptate. De
aceea, pentru a nu repeta de patru ori acelai cod de test, putem scrie nite
teste generice pentru interfaa ITriangle.
n plus, putem optimiza modul de verificare a rezultatelor, deoarece
sunt patru metode care trebuie testate: IsScalene, IsIsosceles, IsEquilateral i
IsInvalid. Astfel, putem crea o metod care s apeleze toate cele patru
metode i s returneze un ir de caractere care s codeze rezultatele tuturor
acestor metode:

private string EvaluateTriangle()
{
if (_triangle.IsInvalid())
return "0";

string s = "";

if (_triangle.IsScalene())
s += "1";
else
s += "0";

if (_triangle.IsIsosceles())
s += "1";
else
s += "0";

if (_triangle.IsEquilateral())
s += "1";
else
s += "0";

return s;
}

Pentru un triunghi invalid, metoda va returna "0", pentru un triunghi
oarecare (scalen), metoda va returna "100", pentru un triunghi isoscel va
returna "010" iar pentru un triunghi echilateral "001". Din cauza faptului c
metodele testate au erori, pot aprea rezultate incorecte, precum "101".
Clasa de testare generic a interfeei ITriangle va avea urmtoarea
form:


Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 14. Rapoarte de testare


255
// [TestFixture]
public class TriangleTest
{
protected ITriangle _triangle;

[Test]
public void ValidScalene()
{
// 1. Scalen valid
_triangle.SetSides(10, 8, 5);
Assert.AreEqual("100", EvaluateTriangle(), "10-8-5");
}

// ... celelalte teste
}

Se remarc faptul c aceast clas nu are atributul [TestFixture],
deoarece testele vor fi realizate doar pentru tipurile concrete.
n acest scop, vom deriva patru clase din clasa TriangleTest, cte una
pentru fiecare tip de triunghi. n metoda marcat cu atributul [SetUp] vom
iniializa cmpul _triangle. n continuare, platforma NUnit va rula testele
din clasa Triangle1Test, motenite din clasa de baz TriangleTest, avnd
cmpul _triangle de tipul triunghiului concret Triangle1.

[TestFixture]
public class Triangle1Test : TriangleTest
{
[SetUp]
public void Init()
{
_triangle = new Triangle1();
}
}

n mod similar se procedeaz i pentru celelalte tipuri concrete.
Rezultatele testrii vor aprea ca n figura 14.2.
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

256

Figura 14.2. Rezultatele testrii cu NUnit


3. Aplicaie

3.1. Se dorete testarea cutie neagr (engl. black box) a claselor
de triunghiuri descrise anterior. Folosii platforma NUnit pentru a testa toate
cazurile de eroare care pot aprea. Vom considera c dac triunghiul este
valid, o singur metod trebuie s fie activ la un moment dat. De exemplu,
considerm c un triunghi echilateral nu este n acelai timp i isoscel.
Implementrile claselor din ierarhia de triunghiuri sunt prezentate n
continuare.

namespace TestTriangles
{
public interface ITriangle
{
bool IsInvalid();
bool IsScalene();
bool IsIsosceles();
bool IsEquilateral();
void SetSides(int a, int b, int c);
}
}

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 14. Rapoarte de testare


257
namespace TestTriangles
{
public class Triangle1 : ITriangle
{
int _a;
int _b;
int _c;
bool _flag;

public void SetSides(int a, int b, int c)
{
_a = a;
_b = b;
_c = c;
int semiperim = (a + b + c) / 2;
_flag = a == 0 || b == 0 || c == 0 || a < 0 || b < 0 || c < 0 || semiperim <= a ||
semiperim <= b || semiperim <= c;
}

public bool IsInvalid()
{
return _flag;
}

public bool IsScalene()
{
return _a != _b && _a != _c && _b != _c;
}

public bool IsIsosceles()
{
return _a == _b || _a == _c || _b == _c;
}

public bool IsEquilateral()
{
return _a == _b && _b == _c && !IsIsosceles();
}
}
}

namespace TestTriangles
{
public class Triangle2 : ITriangle
{
int _a;
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

258
int _b;
int _c;
bool _flag;

public void SetSides(int a, int b, int c)
{
_a = a;
_b = b;
_c = c;
int semiperim = (a + b + c) / 2;
_flag = a == 0 || b == 0 || c == 0;
}

public bool IsInvalid()
{
return _flag;
}

public bool IsScalene()
{
return _a != _b && _a != _c && _b != _c;
}

public bool IsIsosceles()
{
return _a == _b || _a == _c || _b == _c;
}

public bool IsEquilateral()
{
return _a == _b && _b == _c;
}
}
}

namespace TestTriangles
{
public class Triangle3 : ITriangle
{
int _a;
int _b;
int _c;
bool _flag;


Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 14. Rapoarte de testare


259
public void SetSides(int a, int b, int c)
{
_a = a;
_b = b;
_c = c;
int semiperim = (a + b + c) / 2;
_flag = a < 0 || b < 0 || c < 0;
}

public bool IsInvalid()
{
return _flag;
}

public bool IsScalene()
{
return _a != _b && _a != _c && _b != _c;
}

public bool IsIsosceles()
{
return _a == _b || _a == _c || _b == _c;
}

public bool IsEquilateral()
{
return _a == _b && _b == _c;
}
}
}

namespace TestTriangles
{
public class Triangle4 : ITriangle
{
int _a;
int _b;
int _c;
bool _flag;

public void SetSides(int a, int b, int c)
{
_a = a;
_b = b;
_c = c;
int semiperim = (a + b + c) / 2;
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

260
_flag = a == 0 || b == 0 || c == 0 || a < 0 || b < 0 || c < 0;
}

public bool IsInvalid()
{
return _flag;
}

public bool IsScalene()
{
return _a != _b && _a != _c && _b != _c;
}

public bool IsIsosceles()
{
return _a == _b || _a == _c || _b == _c;
}

public bool IsEquilateral()
{
return _a == _b && _b == _c;
}
}
}

Creai un raport de testare pentru fiecare clas. Raportul va avea
structura din tabelul 14.1.

Tabelul 14.1. Raport de testare

Nr. test Valori laturi Rspuns corect Rspuns program Observaii
1 3 5 5 Isoscel Scalen, Isoscel incorect
2 3 3 3 Echilateral Echilateral corect
...

Scopul este s descoperii ct mai multe cazuri de test, cu valori att
corecte ct i incorecte. O list cuprinztoare a cazurilor de test este dat n
figura 14.3. Consultai-o doar dup ce ai ncercat propriile cazuri.

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Capitolul 14. Rapoarte de testare


261

Figura 14.3. Exemplu de rezolvare: cazuri de test

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

262

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com


263



Referine

[1] Albahari, J. (2008). C# Concepts: Value vs Reference Types,
http://www.albahari.com/valuevsreftypes.aspx
[2] Altova Umodel (2008). UModel tutorial, http://www.altova.com/
manual2008/UModel/umodelprofessional
[3] Ariadne Training (2008). UML Applied, 2nd edition,
http://ariadnetraining.com
[4] Becker, K. (2008). Using the Model View Controller Pattern in C# ASP
.NET Web Applications, http://www.primaryobjects.com/CMS/
Article82.aspx
[5] Data & Object Factory (2002). Software Design Patterns,
http://www.dofactory.com/Patterns/Patterns.aspx
[6] Fowler, M. (2006). Passive View, http://martinfowler.com/eaaDev/
PassiveScreen.html
[7] Fowler, M. (2006). Supervising Controller, http://martinfowler.com/
eaaDev/SupervisingPresenter.html
[8] Freeman, E., Freeman, E., Bates, B., Sierra, K. (2004). Head First
Design Patterns, O'Reilly Media, Inc.
[9] Gamma, E., Helm, R., Johnson, R., Vlissides, J. M. (1994). Design
Patterns: Elements of Reusable Object-Oriented Software, Addison-
Wesley Professional
[10] Goodliffe, P. (2006). Code Craft: The Practice of Writing Excellent
Code, No Starch Press
[11] Hilyard, J., Teilhet, S. (2006). C# Cookbook, 2nd Edition, O'Reilly
[12] Liptchinsky, V. (2008). Pre-compile (pre-JIT) your assembly on the fly,
or trigger JIT compilation ahead-of-time, http://www.codeproject.com/
Articles/31316/Pre-compile-pre-JIT-your-assembly-on-the-fly-or-tr
[13] Microsoft MSDN Library (2008-2011). Paginile despre clase,
structuri, enumeraii, Model-View-Controller, Model-View-Presenter,
clase pariale, proprieti, clase abstracte, interfee, polimorfism,
http://msdn.microsoft.com/en-us/library/default.aspx
Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com
Florin Leon Aplicaii de ingineria programrii n C#

264
[14] MSDN Forum (2008). Faster Deep Cloning,
http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/
thread/5e13351f-abdb-42d4-93f0-64bff65b8d74
[15] MVCSharp Org. (2011). MVC# Overview, http://www.mvcsharp.org/
Overview/Default.aspx
[16] Myers, G. J., Sandler, C., Badgett, T., Thomas, T. M. (2004). The Art of
Software Testing, 2nd edition, Wiley
[17] Obviex (2010). How To: Encrypt and Decrypt Data Using a Symmetric
(Rijndael) Key (C#/VB.NET), http://www.obviex.com/samples/
Encryption.aspx
[18] SmartForce Ireland Ltd & Classic Systems Solutions (1999). GUI
Design Fundamentals
[19] SpiderWorks Technologies (2011). C# Coding Standards and Best
Programming Practices, http://www.dotnetspider.com/tutorials/
BestPractices.aspx
[20] Wikipedia, The Free Encyclopedia (2008). Paginile despre CIL/MSIL,
Reflector .NET, DLL, DLL hell, Unit testing, Model-View-Controller,
Just-in-time_compilation, http://en.wikipedia.org
[21] Ziff Davis, Inc. (2009). Adopting C#, and Eluding DLL Hell,
http://www.extremetech.com/article2/0,2845,1153065,00.asp

Florin Leon (2012). Aplicatii de ingineria programarii in C#, Tehnopress, Iasi, ISBN 978-973-702-909-6
http://florinleon.byethost24.com

S-ar putea să vă placă și