Limbajul c sharp



Yüklə 1,48 Mb.
səhifə7/14
tarix08.01.2019
ölçüsü1,48 Mb.
#92362
1   2   3   4   5   6   7   8   9   10   ...   14

de acces (constrangerile claselor generice).Cu alte cuvinte,acest tip de

solutie,permite impartirea clientilor in grupe cu nivelele diferite de

acces la informatie,fara a fi necesara introducerea de parole,coduri de

acces,sisteme de securizare...etc.

Clasele generice reprezinta forma cea mai evoluata de structurare a

datelor,in cadrul conceptului general de programare orientata spre obiect.

Atentie insa: genericele deschid o poarta larga spre nenumarate erori de

executie,exceptii de format,cazuri particulare,incompatibilitati,bucle

infinite,tipuri nedefinite,erori de sintaxa,conversii gresite...etc.

-49-


ENUMERARI
Enumerarile sunt un tip special de data,definit de catre utilizator.

Este asemanator cu o arie sau cu o lista,in sensul ca poate arhiva si

ordona grupe de date.Fiecare element poate primi o denumire,astfel incat

sa fie cat mai usor de identificat.Enumerarile au rostul de a memora un

set oarecare de valori constante,ce urmeaza sa fie apoi utilizate in

program,pentru setari sau operatii default.Spre deosebire de variabilele

simple,enumerarile garanteaza faptul ca valoarea aleasa fece parte din

setul de valori acceptabile,arhivat anterior.

Biblioteca System,contine o clasa enum,astfel ca declararea unui astfel

de obiect se face folosind cuvantul enum,urmat de lista de elemente cu

virgula intre ele.Fiecare element poate fi o constanta,din orice tip

Integer cu exceptia tipului Char.Daca nu se specifica tipul de data,se

va utiliza implicit tipul Int32.Asadar,o enumerare este un spatiu denumit

ce include o lista de elemente de tip integer.

Clasa enum mosteneste clasa ValueType si implementeaza interfetele

IComparable,IFormattable si IConvertible (vezi referintele),astfel ca

asigura si un set minimal de metode implicite prin care se pot compara

doua instante ale clasei,se pot face conversii de format intre tipul

Integer si tipul String...etc.

EXEMPLU:


using System;

public class Enumerare {

enum Culori { rosu,galben,albastru,verde,alb };
static void Main(){

Console.WriteLine("Primul element este: {0}",Culori.rosu);

Type col = typeof(Culori);

foreach (string s in Enum.GetNames(col))

Console.WriteLine("{0,-11}={1}",s,

Enum.Format(col,Enum.Parse(col,s),"d"));

Console.ReadLine();

}}

Salvati fila cu numele Enumerare1.cs si compilati.



In exemplul de mai sus,se declara o enumerare,apoi se utilizeaza o

bucla foreach,pentru a citi toate elementele din lista,dar si pentru a

face conversia valorilor numerice atribuit automat.Pentru a atribui

alte valori,se utilizeaza operatorul de atribuire "=".

EXEMPLU: enum Culori{ rosu=22,galben=33,albastru,verde=55,alb };

de remarcat este faptul ca in declaratia de mai sus,culoarea albastru

va primi automat valoarea 33 (cea a elementului precedent + 1) ,iar

culoarea alb va primi automat valoarea 56).Pentru verificare,puteti sa

repetati exercitiul cu declaratia de mai sus.

Enumerarile se utilizeaza frecvent,fie pentru a preseta un set de

variabile,fie pentru a verifica daca o valoare oarecare face parte din

setul de valori acceptabile.De exemplu,pentru a crea un filtru de valori,

se declara o enumerare,apoi se apeleaza rutina prin care se verifica daca

valoarea respectiva face parte din enumerare.

Daca se utilizeaza o bucla de tip SWITCH ... CASE este posibil ca

fiecare element din enumerare sa declanseze o anumita functie de raspuns.

-50-

EXEMPLU:


using System;

public class Enumerare {

enum Culori { rosu,galben,albastru,verde,alb };

static void Main(){

Culori col = Culori.rosu | Culori.verde;

switch(col) {

case Culori.verde:

Console.WriteLine("Culoarea verde este in lista!");

break;

}

Console.ReadLine();



}}

Salvati fila cu numele Enumerare2.cs si compilati.

In exemplul de mai sus,bucla switch...case nu numai ca verifica daca

elementul cautat face parte din lista,dar permite si executia unei rutine

de raspuns la apel.Intr-un program mai mare,utilizatorii vor avea cate un

set de valori prestabilite,in functie de optiunile pentru care au optat.

In momentul executiei,fiecare utilizator va putea avea o configuratie

proprie,in functie de unul sau mai multe astfel de seturi de valori

prestabilite.

Daca elementele din enumerare sunt de alt tip decat Int32,acest tip

trebuie specificat explicit,atat atunci cand se declara enumerarea cat si

atunci cand se citeste un element al sau.

EXEMPLU:

using System;

public class Enumerare {

enum Domeniu : long { Max = 123456789L,Min = 4321L };

static void Main() {

long x = (long)Domeniu.Max;

long y = (long)Domeniu.Min;

Console.WriteLine("Valoarea maxima este = {0},x);

Console.WriteLine("Valoarea minima = {0}",y);

Console.ReadLine();

}}

Salvati exemplul cu numele Enumerare3.cs si compilati.


Enumerarile sunt esentiale nu numai ca tip de data in sine,dar si

pentru intelegerea unor structuri de date complexe,cum sunt iteratorii,

sau pentru implementarea unor interfete cum sunt:IEnumerator,IEnumerable.

Tipul enum,este important mai ales pentru a garanta siguranta in

executie a sistemului.Din acest motiv,este esential ca toate operatiile

cu si asupra elementelor din enumerari sa se faca prin rutine automate.

Daca utilizatorul seteaza manual datele din enumerari,sau poate interveni

direct asupra lor,printr-un mecanism oarecare,atunci aceastea nu vor mai

prezenta nici un fel de avantaj fata de o arie de date sau o variabila

simpla.Alegeti acest tip de data,atunci cand doriti sa implementati un

set de rutine automate,independente de interactiunea cu utilizatorul.

Aceasta recomandare este valabila si atunci cand enumerarile sunt

incluse la randul lor in structuri mai complexe (vezi si iteratorii),

sau in procese de setare si actualizare a unei aplicatii.

-51-

ITERATORI


Dupa cum le spune si numele,iteratorii sunt structuri de date destinate

unor operatii repetitive (iterative).Iteratorii nu sunt o inventie a

limbajului C#,ci exista sub o forma sau alta in toate limbajele de

programare.Buclele FOR...NEXT,FOREACH,DO...WHILE sunt exemplele cele mai

simple de operatii iterative.Totusi,in conceptul general de programare

orientata spre obiect,termenul de iterator se utilizeaza doar pentru

obiectelele sau functiile destinate sa parcurga elementele unei colectii,

sau sa permita navigarea prin selectie,sortarea,filtrarea sau selectarea

elementelelor de un anumit tip.Cu alte cuvinte,iterartorii sunt o solutie

software pentru automatizarea unor procese.

In particular,in limbajul C# aceste operatii sunt simplificate prin

existenta unui set de interfete: IEnumerable si IEnumerable,respectiv

IEnumerator si IEnumerator.Aceste interfete definesc un set intreg de

metode standard usor de implementat.Se utilizeaza pentru a selecta si

returna grupuri de elemente dintr-o colectie.Functia prin care se pot

returna datele dorite,prezinta urmatoarele caracteristici:

1.-elementul returnat trebuie sa fie unul din cele patru tipuri mentionate

mai sus: IEnumerable,IEnumerator,IEnumerable sau IEnumerator

2.-pentru a desemna datele returnate se utilizeaza cuvantul "yield" urmat

de cuvantul cheie "return" (yield = a produce,a returna)

3.-fiecare iterator trebuie a fie denumit distinct,la fel ca o clasa.O

clasa poate contine mai multi iteratori.Daca o colectie necesita mai

multi iteratori alternativi,in momentul compilarii se va crea o clasa

speciala pentru fiecare iterator,pentru a permite un mai bun control

al memoriei consumate (se impacheteaza datele).

Cea mai simpla operatie o reprezinta parcurgerea succesiva a datelor

dintr-o colectie.

EXEMPLU:


using System;

using System.Collections;

class ListClass : System.Collections.IEnumerable {

public System.Collections.IEnumerator GetEnumerator()

{ for (int i = 0, i < 10; i++) { yield return i; }

}}

class ProgramulMeu{



static void Main(){

ListClass listClass1 = new ListClass();

foreach( int i in listClass1)

{ System.Console.WriteLine("Valoarea returnata este: "+i);}

Console.ReadLine();

}}

Salvati fila cu numele Iterator1.cs si compilati.



In exemplul de mai sus,clasa ListClass implementeaza o interfata de

tip IEnumerable si supraincarca metoda GetEnumerator() cu o metoda noua

personalizata,in care se genereaza si se returneaza 10 elemente de tip

int.Obiectul listClass1,generat din aceasta clasa este un iterator ce

permite parcurgerea membrilor sai cu ajutorul unei bucle foreach.

Un iterator este foarte usor de recunoscut,de la prima vedere,dupa

cuvantul cheie yield return.

-52-


Nu se justifica construirea unui iterator,doar pentru a parcurge toate

elementele dintr-o colectie.Acelasi rezultat se poate obtine cu o bucla

simpla,FOREACH sau FOR...NEXT.In mod normal,iteratorul contine o functie

specializata,prin care se executa o serie oarecare de operatii asupra

datelor returnate,fara a modifica datele din resursa exploatata.Fie ca

este vorba de operatii aritmetice sau de formatare,fie ca se executa

selectii,sortari sau filtrari,iteratorul trebuie sa automatizeze un set

oarecare de operatii.

EXEMPLU:

using System;

using System.Collections;

class ListClass : System.Collections.IEnumerable {

string[] nume = { "Ion","Dan","Stefan","Constantin"};

public System.Collections.IEnumerator GetEnumerator()

{ for (int i=0; i< nume.Length; i++) { yield return nume[i]+"escu,";}

}}

class ProgramulMeu{



static void main(){

ListClass listClass1 = new ListClass();

Console.WriteLine("Numele dun lista sunt: ");

Console.WriteLine("");

foreach (string i in listClass1)

{ System.Console.Write(i); }

Console.ReadLine();

}}

Salvati fila cu numele Iterator2.cs si compilati.In exemplul de mai



sus,iteratorul nu numai ca parcurge intreaga colectie,dar executa si o

operatie oarecare (adauga sufixul "escu").In mod similar,se pot executa

serii de calcule aritmetice (Exemplu: calculul impozitelor etc.).Pentru

fiecare set de operatii,se poate defini un astfel de iterator personalizat

ce poate fi arhivat in memorie sub forma de biblioteca DLL.Cu o astfel

de solutie,se pot valorifica datele dintr-o resursa,dupa algoritmi

personalizati.Spre deosebire de un tabel sau o baza de date,o astfel de

solutie prezinta o siguranta crescuta in exploatare,deoarece datele nu

pot fi valorificate decat in prezenta iteratorului.

Mai mult decat atat,interfata IEnumerable expune un enumerator de

tip generic si un set complet de metode,ce permit operatii similare cu

sistemul de interogari SQL utilizat in cazul bazelor de date.Dintre

metodele acestei interfete,merita amintite:Aggregate,All

Any,Average,Contains,Count,Distinct<

TSource>,Elements,First,GroupBy,GroupJoin<

TSource>,Join,Last,Max,Min,OrderBy<

TSource>,Select,Single,Sum,ToList,

Union,Where,Zip (vezi referinta MSDN).

Exista mai multe metode supraincarcate,pentru fiecare dintre operatiile

de mai sus,astfel ca aceasta interfata se poate adapta practic la orice

necesitati de programare curenta.Interfata poate fi apelata direct,caz

in care nu este necesar sa redefiniti sau sa supraincarcati nici una

dintre metode,ci puteti apela direct metoda standard.Cambinand iteratorii

cu selectii de tip LINQ (vezi si capitolul urmator),se obtine o foarte

mare flexibilitate de filtrare a datelor de orice tip.

-53-


EXEMPLU:

using System;

using System.Linq;

using System.Collections.Generic;


class ProgramulMeu{

class Angajat

{ public string Nume { get; set; }

public int Vechime { get; set; }

}

static void Main() {



Angajat[] an1 = {

new Angajat { Nume="Ion Ionescu",Vechime=18 },

new Angajat { Nume="Mihai Popescu",Vechime=14},

new Angajat { Nume="Stefan Georgescu",Vechime=3 },

new Angajat { Nume="Tudor Pop",Vechime=2 }

};

IEnumerable query = an1.OrderBy(angajat => angajat.Vechime);



foreach (Angajat a in query)

{ Console.WriteLine("Nume= {0} vechime= {1} ani",

a.Nume,a.Vechime); }

Console.ReadLine();

}}

Salvati fila cu numele Iterator3.cs si compilati.



In acest exemplu se creaza colectia an1 direct din tipul IEnumerable

si apoi se apeleaza metoda OrderBy() pentru a obtine sortarea elementelor

in functie de Vechime.

EXEMPLU:


using System;

using System.Linq;

using System.Collections.Generic;

class ProgramulMeu {

class Angajat { public string Nume { get; set; }

public bool Casatorit { get; set; } }

static void Main() { Angajat[] an1= {

new Angajat { Nume = "Maria Anton",Casatorit=false},

new Angajat { Nume = "Ion Ionescu",Casatorit=true },

new Angajat { Nume = "Mihai Popescu",Casatorit=true },

new Angajat { Nume = "Stefan Georgescu",Casatorit=true },

new Angajat { Nume = "Tudor Pop",Casatorit=false}

};

int nr1 = an1.Count( p => p.Casatorit == false);



int nr2 = an1.Count( p => p.Casatorit == true);

Console.WriteLine("{0} angajati sunt necasatoriti.",nr1);

Console.WriteLine("{0} angajati sunt casatoriti.",nr2);

Console.ReadLine();

}}

Salvati fila cu numele Iterator4.cs si compilati.



In acest caz se apeleaza metoda Count(Func,Boolean)

pentru a separa grupuri de elemente,in functie de un criteriu boolean.Se

observa ca interfata IEnumarable este apelata implicit (prin Count()).

-54-


EXEMPLU:

using System;

using System.Linq;

using System.Collections.Generic;


class ProgramulMeu {

class Copil { public string Nume { get; set; } }

class Angajat { public string Nume { get; set; }

public Copil[] c1 { get; set; } }

static void Main(){

List an1 = new List {

new Angajat {

Nume = "Ion Ionescu", c1 = new Copil[]{ new Copil{ nume="Ion"}}},

new Angajat {

Nume = Mihai Popescu",c1 = new Copil[]{} },

new Angajat {

Nume = "Ana Pop",c1= new Copil[]{ new Copil{ Nume="Maria" },

new Copil{ Nume="Mihai" }}}

};

IEnumerable nr = from Angajat in an1 where Angajat.c1.Any()



select Angajat.Nume;

foreach (string a in nr)

{ Console.WriteLine("Angajatul {0} are copii.",a); }

Console.ReadLine();

}}

Salvati fila cu numele Iterator5.cs si compilati.



Observati ca in acest caz,s-a utilizat o selectie LINQ,asemanatoare

cu o comanda de tip SQL.

Numarul de astfel de solutii,este practic infinit.Mecanismul de iterare

a unei colectii de date cu un astfel de iterator prezinta o serie intreaga

de avantaje:

1.-toate datele sunt incluse in obiecte,fiind astfel usor de manevrat in

memoria de operare,usor de gestionat si usor de eliberat din memorie

2.-metodele standard sunt simple,intuitive,usor de aplicat si pot fi

apelate direct (fara sa fie redefinite sau supraincarcate )

3.-iteratorii nu modifica resursa,nu adauga variabile suplimentare,nu

interfereaza cu alte date din sistem si utilizeaza tampoane de memorie

proprii,fara pointeri sau link-uri auxiliare

4.-datele sunt destul de bine securizate,deoarece un programator neavizat

nu poate exploata resursa,decat daca are acces la fila DLL si cunoaste

codul iteratorului.

Bineinteles ca executabilele pot fi deschise si studiate cu un utilitar

de genul ildasm.exe,dar este necesar ca programatorul sa detina notiuni

avansate de programare pentru a descifra codul,caz in care este foarte

putin probabil sa modifice negativ functionalitatea programului.

Interfetele necesare sunt arhivate in System.Collections.Generic si

respectiv in System.Linq.Are rost sa studiati intreaga lista de metode,

pentru fiecare interfata.Puteti sa formulati combinatii personalizate,sau

puteti sa preluati si transformati formule standard,prezentate in alte

exemple.Pentru formularea selectiilor de tip LINQ vezi si capitolul

urmator.

-55-


SELECTII LINQ
LINQ (Language-Integrated Query) este denumirea prescurtata pentru un

set de tehnologii software ce permit selectarea unor subseturi sau seturi

de date,din structuri de date de tip colectie.In general,o selectie este

o expresie prin care se solicita o preluare de informatii,dintr-o sursa de

date.Acest gen de solutie a fost dezvlotat mai ales pentru prelucrarea de

date arhivate in tabele si in baze de date (date preformatate).Fiecare

sistem de baze de date,a fost conceput cu un anumit format,astfel ca si

selectiile de date au trebuit sa respecte anumite criterii fixe.Cel mai

cunoscut limbaj de acest gen,este SQL (Structured Query Line).LINQ nu

este decat o extensie a limbajului SQL,creata cu scopul de a permite o

flexibilitate crescuta in preluarea de date,din surse formatate diferit.

Astfel,prin selectii LINQ se pot prelua si prelucra date arhivate in

memoria de operare,in tampoane temporare,in arii de date sau in liste,

in file de tip text,XML,in tabele si baze de date,sau in orice alt tip

de suport de memorie.

Tehnologia LINQ implica trei etape diferite:

1.Constructia sursei de date,se poate face astfel:

-se arhiveaza date pe un suport fix

-se preiau date din una sau mai multe surse din retea

-se construiesc date complet noi in memoria de operare

-se convertesc datele existente in mediul de executie

2.Formularea expresiei de interogare (selectie)

3.Executia expresiei LINQ si procesarea datelor preluate din sursa.

Cel mai simplu exemplu,preia datele din memoria de executie.

EXEMPLU:

using System;

using System.Linq;

using System.Collections.Generic;

class Expresie {

static void Main(){

int[] lista = new int[] { 15,97,92,81,60,3 };

IEnumerable selectie =

from numar in lista where numar < 80 select numar;

Console.WriteLine("Numerele mai mici decat 80 sunt:");

foreach (int i in selectie)

{ Console.Write(i = " "); }

Console.ReadLine();

}}

Salvati exemplul cu numele Linq1.cs si compilati.



O expresie de tip selectie LINQ se formuleaza la fel ca si o expresie

de tip SQL,cu ajutorul unor clauze,ce pot fi declarate intr-o anumita

ordine prestabilita.Astfel,o expresie LINQ trebuie sa inceapa cu clauza

"from",urmata de resursa in care sunt arhivate datele si trebuie sa se

termine cu clauza "select" prin care se pot transforma datele preluate

intr-o secventa noua de date,reformatate sau reformulate.Acest tip de

transformare mai poarta si numele de "proiectie" (projection).Intre cele

doua clauze obligatorii,pot exista una sau mai multe clauze optionale,cum

sunt: where,orderby sau join,prin care se specifica tipul de operatii

necesare pentru a transforma datele preluate.

-56-

De exemplu,in exercitiul anterior clauza select prelucreaza datele



din lista si preia doar pe cele care respecta clauza where.Pentru a

sorta datele si in ordine descendenta,se poate adauga o clauza "orderby".

EXEMPLU:

using System;

using Linq;

using System.Collections.Generic;

class Expresie {

static void Main(){

int[] lista = new int[] { 15,97,92,81,60,3 };

IEnumerable selectie =

from numar in lista

where numar < 80

orderby numar descending

select numar;

Console.WriteLine("Numerele mai mici decat 80 sunt: ");

foreach (int i in selectie)

{ Console.Write(i + " "); }

Console.ReadLine();

}}

Salvati fila cu numele Linq2.cs si compilati.



Se pot combina doua sau mai multe clauze de acelasi tip,sau se pot

combina doua sau mai multe conditii,cu ajutorul operatorilor OR sau AND.

EXEMPLU:

using System;

using System.Linq;

using System.Collections.Generic;

class Expresie {

static void Main(){

int[] lista = new int[] { 15,97,92,81,60,3 };

IEnumerable selectie =

from numar in lista

where numar < 80 && numar > 10

select numar;

Console.WriteLine("Numerele selectate sunt: ");

foreach (int i in selectie)

{ Console.Write(i + " "); }

Console.ReadLine();

}}

Salvati fila cu numele Linq3.cs si compilati.



Daca sursa de date este la randul sau o colectie de date,se pot utiliza

doua sau mai multe clauze "from",pentru a separa fiecare element.

EXEMPLU: from country in countries

from city in country.Cities

where city.Population > 100000

select city;

va selecta toate obiectele de tip city din fiecare colectie country,

arhivata in colectia countries si va extrage doar pe cele care respecta

conditia din where.

Pentru ca expresia sa evalueze si rezultatul unei alte expresii se

poate utiliza clauza "let".

-57-


EXEMPLU:

using System;

using System.Linq;

using System.Collections.Generic;

class Expresie {

static void Main() {

string[] lista = { "Popescu","Danescu","Stefanescu" };

var selectie = from nume in lista

let subsir = nume.Split(new char[] {'e'})[0]

select subsir;

Console.WriteLine("Rezultatul obtinut este: ");

foreach (string i in selectie)

{ Console.Write(i + " "); }

Console.ReadLine();

}}

Salvati fila cu numele Linq4.cs si compilati.Observati si faptul ca



tipul de data IEnumerable poate fi inlocuit cu succes prin tipul "var".

Pentru a asocia sau combina date preluate din doua surse diferite,se

poate utiliza clauza "join".Selectia se va face cu ajutorul unei operatii

de comparare intre elementele specificate din fiecare sursa de date.

In LINQ,operatii de tip "join" se pot efectua si pe secvente de date ce

contin tipuri diferite de data.Dupa operatia "join" trebuie neaparat sa

urmeze o clauza select sau groupby,prin care sa se specifice elementele

ce urmeaza sa fie preluate din secventa obtinuta prin reuniune.Tipul var,

denumit si tip anonim,poate fi utilizat atunci cand prin operatia de

reuniune doriti sa obtineti un tip de data nou,diferit de cele initiale.

EXEMPLU:

var categoryQuery =

from cat in categories

join prod in products on cat equals prod.Category


Yüklə 1,48 Mb.

Dostları ilə paylaş:
1   2   3   4   5   6   7   8   9   10   ...   14




Verilənlər bazası müəlliflik hüququ ilə müdafiə olunur ©muhaz.org 2024
rəhbərliyinə müraciət

gir | qeydiyyatdan keç
    Ana səhifə


yükləyin