Limbajul c sharp



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

}}

De exemplu,daca doriti ca obiectul de tip Panel1 sa nu emita mesaje



la fiecare click de mouse,se va exclude mesajul WM_MOUSECLICK din lista

obiectului ( cu remove { handler -= WM_MOUSECLICK } ).

Se observa ca EventHandler functioneaza in obiectul sender la fel ca

o proprietate,dar in loc de Set() si Get(),accepta metodele Add() si

respectiv Remove().

Cu un astfel de mecanism,mesajele inutile nu numai ca nu vor mai fi

interpretate,dar nici macar nu vor mai fi emise,simplificand foarte mult

munca procesorului (se elibereaza memorie,pentru sute de pointeri sau

pentru alte operatii).

Nu este esential sa intelegeti mecanismul de lucru pentru evenimente,

decat daca proiectati programe profesionale.Platforma Visual C# ofera o

interfata extrem de facila,in care este suficient sa executati un click

pe evenimentul dorit si apoi sa completati codul pentru metoda de tratare

a evenimentului.Nu este bine sa atribuiti prea multe operatii unui singur

eveniment.Daca este esential,impartiti codul in mai multe functii de

raspuns,sau intre mai multe evenimente apropiate (butoane diferite).

-32-

Un tip special de metode,sunt cele ce pot fi utilizate in expresii,



pentru a executa diferite operatii.Acest gen de metode poarta si numele

de "operatori".Se pot defini astfel de clase,atunci cand lucrati frecvent

cu un anumit gen de operatii,pentru care nu exista un operator standard.

De exemplu,daca doriti sa transformati un numar analog,intr-un numar

digital,puteti scrie o clasa care executa conversia,salvati fila sub forma

de biblioteca DLL si apoi utilizati clasa pe post de operator.

EXEMPLU:

using System;

using System.Collections;

namespace NumarDigital {

public class Digital {

public static void Digit1(String Operand){

IEnumarator OperandEnum = Operand.GetEnumarator();

int CharCount = 0;

Console.WriteLine("Numarul in format digital este: ");

while (OperandEnum.MoveNext()){

CharCount++;

Console.Write(" '{0}' ",OperandEnum.Current);

}

Console.ReadLine();



}

}}

Salvati fila cu numele Digit1.cs.Pentru a crea fila DLL editati comanda:



csc /target:library /out:NumarDigital.DLL Digit1.cs

Apoi puteti exploata resursa cu o fila de genul:

using System;

using NumarDigital;

class telefon1 {

public static void Main(){

Console.WriteLine("Introduceti numarul de telefon (10 cifre): ");

string nr1 = Console.ReadLine();

Digital.Digit1(nr1);

}}

Salvati fila cu numele Digital1.cs.Pentru executabil editati comanda:



csc /out:Digital1.exe /reference:NumarDigital.DLL Digital1.cs

Exercitiul de mai sus este foarte simplist.Practic separa sirul in

caractere si afiseaza numarul sub forma de cifre izolate.Pentru a completa

programul,ar trebui ca numarul sa fie separat in digiti,in format numeric

de tip byte,ce vor fi arhivati intr-o arie.Apoi metoda returneaza aria,de

unde pot fi preluati si utilizati (de exemplu pentru a apela un numar de

telefon).Pentru exercitiu,puteti incerca sa realizati un astfel de

program complet,ce preia numarul sub forma de string si returneaza digiti

in format byte.

Cu acelasi tip de solutie,puteti sa definiti orice alt tip de operator

personalizat.Exemplu: executa automat calculul taxelor si impozitelor

pentru o anumita suma.

O singura clasa,poate contine mai multe astfel de metode,fiecare

dintre ele reprezentand un operator diferit.Acest mecanism,nu numai ca

va poate simplifica foarte mult viata,dar confera si un grad foarte mare

de siguranta (nu oricine poate apela biblioteca DLL personalizata).

-33-

Clasele C# permit supraincarcarea constructorilor cu conditia sa existe



o diferenta intre cele doua definitii: numarul de parametri,tipul lor,

modificatorii,domeniul de vizibilitate etc.Prin acest mecanism,este

posibil ca o clasa sa contina mai multi constructori diferiti,ce pot fi

apelati in functie de contextul programului.Fiecare astfel de constructor

va crea o instanta diferita a clasei respective (obiectele create vor fi

diferite,in functie de constructorul apelat).

EXEMPLU:

using System

class Point {

public double x,y;

public Point(){ this.x=0; this.y=0; }

public Point(double x double y){

this.x = x; this.y = y; }

}

class Test {



static void Main() {

Point a = new Point();

Console.WriteLine("a.x= {0}",a.x);

Point b = new Point(7,3);

Console.WriteLine("b.x= (0}",b.x);

Console.ReadLine();

}}

Salvati fila cu numele Constructori.cs si compilati.



Observati ca in clasa Point sunt definiti doi constructori distincti.

Primul nu are parametri,in timp ce cel de al doilea accepta doi parametri

de tip double.Daca se apeleaza primul constructor,variabila x va fi

initializata cu valoarea 0 (cea implicita),iar daca se apeleaza cel de

al doilea constructor,variabiala x va fi initializata cu valoarea din

apel (primul parametru).Acest mecanism este destul de frecvent si pentru

multe dintre clasele standardizate.Exista un constructor "default" in

care obiectul creat este initializat cu valori "default" si unul sau mai

multi constructori ce permit personalizarea obiectului in functie de

necesitatile de moment ale programatorului.

Destructorul se semanlizeaza cu o tilda:

EXEMPLU: using System;

class Point{ public double x,y;

public Point(double x double y){ this.x=x; this.y=y; }

~Point(){ Console.WriteLine("A fost apelat constructorul!");}

class Test{ static void Main() {

Point b = new Point(7,3);

Console.WriteLine("b.x= {0}",b.x);

Console.ReadLine();

}}

Salvati fila cu numele Destructor.cs si compilati.



Destructorul este apelat intotdeauna inainte de a elibera complet

obiectul din memorie,inclusiv de catre "garbage collector".Pentru a

putea observa apelul destructorului,lansati executabilul Destructor.exe

din Command Prompt cu comanda: Destructor.exe si apoi tastati Enter

ATENTIE: destructorul nu elibereaza memoria,ci doar executa un set

oarecare de operatii,inainte de eliberarea automata a memoriei.

-34-

Limbajul C# introduce si o inovatie: constructorul static,ce poate fi



apelat fara a construi o instanta a clasei respective.O astfel de clasa

se va utiliza in programe,pentru a putea initializa seturi intregi de

variabile,cu valori "default",fara sa se incarce memoria si cu un obiect

sursa.


EXEMPLU:

using System

class Text {

public static string s;

static Text() { s = "Text default"; }

}

class Test{



static void Main() {

Console.WriteLine(Text.s);

Console.ReadLine();

}}

Salvati fila cu numele Constructori2.cs si compilati.



Clasa Text contine un constructor static.Daca se va salva aceasta

clasa sub forma de biblioteca DLL,atunci membrul sau static s,va putea

fi apelat direct,fara a mai construi un obiect de tip s.

Daca intr-o clasa toate metodele si proprietatile sunt de tip static,

se poate crea o clasa intreaga de tip static.

EXEMPLU: static class StaticUtilities {

public static void HelperMethod() { ... }

}

Intr-o astfel de clasa,toti membrii pot fi apelati direct,fara sa mai



fie necesara crearea unui obiect din clasa respectiva.

EXEMPLU: StaticUtilities.HelperMethod(); // este un apel valid.

Clasele pot mosteni o alta clasa,la fel ca si in C++.

EXEMPLU:


using System;

class A {

public void F() { Console.WriteLine("Metoda F din clasa A");}

}

class B : A {



public void G() { Console.WriteLine("Metoda G din clasa B");}

}

class Test {



static void Main() {

B obiect1 = new B();

obiect1.F(); // mostenita din A

obiect1.G();

A obiect2 = obiect1; //primeste metoda F() din obiect1

obiect2.F();

Console.ReadLine();

}}

Salvati fila cu numele Mostenire.cs si compilati.



In exemplul de mai sus,observati ca obiect1 de tip B mosteneste clasa

A,in timp ce obiect2 de tip A nu primeste decat metoda F() din clasa A,

chiar daca o primeste prin intermediul obiectului obiect1.Daca se incearca

apelul obiect2.G() se returneaza o eroare (metoda nedefinita).

-35-

Exista si situatii cand o clasa poate fi definita in mai multe file



sursa separate.Acest gen de situatii poarta numele de clase partiale si

se intanesc fie atunci cand definitia clasei este prea stufoasa,fie cand

o clasa complexa este creata automat,cu date preluate de la mai multi

clienti din retea.In toate aceste situatii,se va utiliza cuvantul cheie

"partial" pentru a semnala faptul ca exista si definitii declarate in alta

fila sursa.

EXEMPLU: // Fila1.cs contine:

partial class ClasaMea {

private int[] counts;

public string ToString() { ....} }

// Fila2.cs contine:

partial class ClasaMea{

private int value;

private void Helper() { ......} }

Cand se vor compila cele doua file,se va construi o singura clasa in care

sunt incluse toate definitiile din cele doua file surse.Pentru un exemplu

complet,vezi constructia bibliotecii DLL "FunctiileMele" din capitolul

Compilator.Acest mecansim este valabil pentru orice tip de data,nu doar

pentru clase.Principalul avanataj al acestui mecanism se poate observa

atunci cand se actualizeaza o biblioteca DLL,sau o fila sursa.In loc sa

fie rescrise toate filele sursa,se adauga doar fila auxiliara ce contine

codurile pentru actualizare.


STRUCTURI
Structurile sunt un fel de strabunice ale claselor.De fapt,tipul class

a derivat progresiv din tipul struct,pana cand s-a ajuns la forma actuala.

Deosebirea fundamentala consta in faptul ca structurile sunt date de tip

valoare (sunt obiecte reale) in timp ce clasele sunt date de tip referinta

(sunt obiecte virtuale).Si structurile pot accepta membri si metode,

inclusiv constructori si destructori,dar nu includ si mecanismul de

mostenire,specific claselor.Tipul struct este pastrat ca tip de data,nu

doar pentru compatibilitatea cu programele mai vechi,ci si pentru faptul

ca ofera o solutie mult mai economica,pentru numaroase situatii de

programare.Declararea unei clase si apoi construirea unui obiect din clasa

respectiva,nu numai ca necesita declararea unui pointer,dar ocupa un volum

cel putin dublu de memorie (o data pentru clasa,si apoi pentru obiect).

In toate situatiile in care este necesar un spatiu denumit,doar pentru a

delimita domeniul de vizibilitate al unui grup oarecare de date,este mult

mai economic sa se utilizeze tipul struct,decat tipul class.

La fel ca si clasele,structurile pot organiza grupuri mari de date,

sub forma de stiva,pot include constructori si metode pentru prelucrarea

datelor,dar cu un consum mai mic de memorie.Tipul struct este preferabil

ori de cate ori se cunoaste exact grupul de date cu care se lucreaza si

tipul de operatii ce urmeaza sa fie executate asupra lor.

Prin contrast,tipul class,este recomandabil ori de cate se lucreaza in

mod curent cu un anumit tip de date,dar este probabil ca vor exista mai

multe implementari,sau va fi nevoie de numeroase solutii personalizate.

In plus,clasele sunt esentiale,atunci cand se valorifica solutii standard,

mostenite din clasele definite in bibliotecile standard.

-36-


EXEMPLU:

using System;

using System.Collections;

class Point {

public int x,y;

public Point(int x,int y) {

this.x = x;

this.y = y; }}

class Test {

static void Main() {

long mem1,mem2,mem3;

mem1 = System.GC.GetTotalMemory(false);

Point[] points = new Point[10000];

for (int i=0;i<10000;i++)

points[i] = new Point(i,i*i);

mem2 = System.GC.GetTotalMemory(false);

mem3 = mem2-mem1;

Console.WriteLine("Memoria initiala: {0:F}",mem1);

Console.WriteLine("Memoria dupa alocare: {0:F}",mem2);

Console.WriteLine("Diferenta = {0:F}",mem3);

Console.ReadLine();

}}

Salvati fila cu numele Struct1.cs si compilati.La executie puteti



observa ca pentru a gestiona cele 10000 de puncte de tip Point,au fost

create 10000 de obiecte,cu un consum de memorie de 204256 bytes.Copiati

exemplul si inlocuiti tipul class prin struct:

using System;

using System.Collections;

struct Point {

public int x,y;

public Point(int x,int y) {

this.x = x;

this.y = y; }}

class Test {

static void Main() {

long mem1,mem2,mem3;

mem1 = System.GC.GetTotalMemory(false);

Point[] points = new Point[10000];

for (int i=0;i<10000;i++)

points[i] = new Point(i,i*i);

mem2 = System.GC.GetTotalMemory(false);

mem3 = mem2-mem1;

Console.WriteLine("Memoria initiala: {0:F}",mem1);

Console.WriteLine("Memoria dupa alocare: {0:F}",mem2);

Console.WriteLine("Diferenta = {0:F}",mem3);

Console.ReadLine();

}}

Salvati fila cu numele Struct2.cs si compilati.La executie,puteti



observa ca in acest caz,s-au consumat doar 80024 de bytes,pentru cele

10000 de puncte de tip Point,deoarece s-a construit un singur obiect

de tip arie,cu 10000 de elemente.

-37-


Exemplul de mai sus,este un exemplu tipic de solutie pentru optimizarea

codului.Nu numai ca s-au inlocuit 10000 de obiecte prin unul singur,dar

s-a renuntat si la cei 10000 de pointeri spre fiecare obiect.

Din acest motiv,tipul struct este utilizat extensiv si in bibliotecile

standard,alaturi de clase.De exemplu,biblioteca System contine si o astfel

de structura dedicata pentru operatiile cu date calendaristice,denumita

DateTime.Membrii sai,pot fi apelati la fel ca si cei ai claselor standard.

EXEMPLU:


using System;

class DataNasterii {

static void Main(){

int an,luna,zi;

Console.WriteLine("Introduceti anul nasterii: ");

an = System.Convert.ToInt32(Console.ReadLine());

Console.WriteLine("Introduceti luna in cifre -Ex. 5 pentru luna Mai:");

luna = System.Convert.ToInt32(Console.ReadLine());

Console.WriteLine("Introduceti ziua nasterii: ");

zi = System.Convert.ToInt32(Console.ReadLine());

DateTime datanasterii = new dateTime(an,luna,zi);

DateTime acum = DateTime.Now;

long impulsuri = acum.Ticks - datanasterii.Ticks;

TimeSpan durata = new TimeSpan(impulsuri);

Console.WriteLine("De la data nasterii,au trecut pana azi {0:f}:",acum);

Console.WriteLine(" {0:N0} impulsuri",impulsuri);

Console.WriteLine(" {0:N0} secunde ",durata.TotalSeconds);

Console.WriteLine(" {0:N0} minute",durata.TotalMinutes);

Console.WriteLine(" {0:N0} zile,{1} ore,{2} minute,{3} secunde",

durata.Days,durata.Hours,durata.Minutes,durata.Seconds);

Console.ReadLine();

}}

Salvati fila cu numele Struct3.cs si compilati.



In mod similar,puteti scrie o aplicatie ce masoara intervalul de timp

dintre doua evenimente,sau dintre doua date calendaristice.

Daca analizati putin membrii structurii DateTime,puteti observa ca

exista 11 constructori pentru tipul DateTime cu parametrii de tip int32

sau int64,ce permit formule foarte sofisticate de formatare a datelor de

tip data calendaristica.Cu maximum de economie de memorie,se pot face

operatii extrem de complexe.

Ori de cate ori oscilati intre tipul class si tipul struct,este bine

sa evaluati necesitatile viitoare si solutiile de procesare scontate,dar

sa faceti si o analiza sumara a consumului de memorie.Cu cat se va

utiliza mai putina memorie,si cu cat memoria consumata va fi eliberata

mai rapid,cu atat aplicatia va fi mai performata si va fi executata mai

usor.Pentru analiza memoriei,cel mai simplu este sa apelati la membrii

clasei GC (garbage collector) din System (vezi si Struct1.cs).Evaluati

memoria consumata in diferite puncte de executie ale programului,si apoi

alegeti solutia cea mai buna.In cazul programelor mari,este bine sa

programati si o caseta de control,in care se afiseaza in permanenta

consumul de memorie.Pastrati aceasta caseta,pana cand terminati,apoi

optimizati programul.In final,dupa epuizarea etapei de depanare si control

caseta poate fi eliminata,pentru a nu deruta utilizatorul.

-38-

INTERFETE



Interfetele sunt un contract intre programator si aplicatie.O astfel

de interfata,impune implementarea in program a tuturor datelor declarate

in interfata.Sunt un fel de clase abstracte,create special pentru a fi

mostenite.O interfata nu poate fi utilizata pentru a crea obiecte sau

functionalitati,ci doar pentru a forma un fel de sablon al aplicatiei.

Sunt utilizate mai ales in mediul vizual,unde poata numele de interfete

grafice.Au rostul de a organiza componentele unui program,intr-o maniera

fixa,cu care utilizatorul a fost deja familiarizat anterior.

EXEMPLU: In interfata se declara o fereastra si un meniu.

Toate programele in care se utilizeaza aceasta interfata vor

utiliza pentru prezentarea datelor o fereastra cu meniul respectiv.

Pentru a declara o interfata,se utilizeaza cuvantul cheie "interface",

in loc de "class".Din punct de vedere tehnic,o interfata este un fel de

clasa abstracta,ce nu poate fi utilizata pentru a construi obiecte.Intr-o

interfata,se includ doar declaratii,fara nici o solutie de implementare.

O interfata poate contine metode,proprietati si evenimente,dar nu poate

contine constructori,destructori sau operatori supraincarcati.Interfata

este prin definitie creata pentru a fi mostenita,asa ca toate datele

incluse in interfata sunt publice.Nu se pot utiliza nici un fel de

modificatori (gen virtual,static etc.).

O clasa care implementeaza o interfata,trebuie sa asigure si declaratia

completa a tuturor datelor importate din interfata.

EXEMPLU:

using System;

interface Conversie { void SetText(); }

class Test : Conversie {

static void Main() {

Test t1 = new Test();

t1.SetText();

Console.ReadLine(); }

public void SetText(){

Console.WriteLine("Se executa metoda contractata !");}

}

Salvati fila cu numele Interfata1.cs si compilati.



Se observa urmatoarele etape:

1.-se declara interfata Conversie ce contine metoda SetText()

2.-se creaza clasa Test ce mosteneste interfata Conversie

3.-se declara explicit metoda contractata (metoda SetText())

4.-se construieste un obiect din clasa Test

5.-se apeleaza metoda SetText()

In exempul de mai sus,interfata contine o singura metoda ce returneaza

un text default.Se observa cu usurinta ca o astfel de functionalitate se

poate exploata pentru a forta presetarea unor anumite valori (setarea

mediului de executie),inainte de a incepe executia propriu zisa a unui

program.De cele mai multe ori,aceasta presetare implica construirea unui

set de obiecte vizuale,prin care utilizatorul va putea comunica cu

aplicatia,cu ajutorul unor clik-uri de mouse.Acest gen de interfata,poarta

numele de "interfata grafica cu utilizatorul".Cea mai cunoscuta este

interfata API Windows,in care utilizatorul va beneficia doar de obiecte

vizuale de tip Windows.

-39-

Interfetele permit un mecanism de mostenire multipla.O singura clasa,



poate mosteni simultan mai multe interfete.

EXEMPLU: class ClasaMea: Interfata1,Interfata2,Interfata3{...}

Deasemenea,o interfata poate mosteni o alta interfata.

EXEMPLU: interface Interfata2: Interfata1 { ...}

Atunci cand se utilizeaza un astfel de mecanism de mostenire multipla,

depanarea unei metode mostenite multiplu poate deveni uneori destul de

confuza.Pentru a evita supraincarcarea unui metode mostenite din mai

multe interfete succesiv,este posibil ca la nivel de clasa de implementare

sa se faca o declaratie explicita a metodei respective.In acest caz,

metoda respectiva nu va mai fi declarata public,ci va fi declarata cu

ajutorul unui nume calificat (spatiu denumit).O astfel de metoda nu va

mai putea fi apelata ca simplu membru al clasei respective ci va trebui

construit initial un obiect,apoi se va apela metoda obiectului.Prin

acest mecanism,se garanateaza ca metoda este cea implementata explicit.

EXEMPLU:

using System;

interface Conversie { void SetText();}

class Test: Conversie {

void Conversie.SetText{

Console.WriteLine("Se executa metoda contractata !");

}}

class Executie {



static void Main(){

Test t1 = new Test();

Conversie t2 = t1;

t2.SetText();

Console.ReadLine();

}}

Salvati fila cu numele Interfata2.cs si compilati.



In exemplul de mai sus,daca se face apelul t1.SetText() se va returna

un mesaj de eroare,deoarece metoda Test.SetText() nu este statica sau

publica.Presupundand ca in exemplul de mai sus ar fi existat mai multe

metode SetText(),mostenite din interfete diferite,acest mecanism asigura

apelul metodei SetText() definita in clasa Test,spre deosebire de orice

alta metoda SetText() implementata altfel.

Bibliotecile standard contin numeroase astfel de interfete,ce pot

fi utilizate pentru a implementa functionalitati standard.De exemplu,

billioteca System contine si intefetele: IComparable,IConvertible,

IDisposable etc.

EXEMPLU: daca o clasa oarecare mosteneste interfata IDisposable din

System,atunci este sigur ca exista si o metoda denumita Dispose() pentru

operatii de eliberare a memoriei (deoarece interfata IDisposable contine

ca membru unic metoda Dispose()).

Interfetele permit crearea de solutii standard,ce pot fi utilizate si

de alti programatori.Apeland utilitarul ildasm.exe,un programator va putea

observa ce intefete sunt implementate si ce functionalitati pot fi apelate

in modulul importat.

EXEMPLU: deschideti modulul Interfata1.exe cu ildasm.exe pentru a

putea observa: intefata Conversie si clasa de implementare Test.

Codul metodei SetText va putea fi studiat in clasa de implementare (Test).

-40-


CLASELE DE TIP DELEGATES

Exista numeroase situatii de programare in care este utila inlocuirea

apelului unei functii,cu un pointer.Exemplu: atunci cand o functie este

utilizata pentru a furniza un parametru unei alte functii.In alte situatii

este necesar ca o anumita functie sau metoda sa fie executata atunci cand

se indeplineste o anumita conditie.Pentru acest scop,este necesar ca

metoda respectiva sa fie conectata la evenimentul respectiv,printr-o

structura oarecare de date.Limbajul C# a rezolvat acest gen de situatii,cu


Yüklə 1,48 Mb.

Dostları ilə paylaş:
1   2   3   4   5   6   7   8   9   ...   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