+ All Categories
Home > Documents > Laboratoarele nu se pot recupera ! Fiecare student va ...iasimin/csharp/C1_C2 Arhitectura...

Laboratoarele nu se pot recupera ! Fiecare student va ...iasimin/csharp/C1_C2 Arhitectura...

Date post: 14-Jul-2018
Category:
Upload: vudat
View: 226 times
Download: 0 times
Share this document with a friend
52
Pag. 1 din 52 Arhitectura Framework .NET Ioan Asiminoaei email: [email protected] IOAN ASIMINOAEI Email: [email protected] Mod de adresare pentru e-mail : In subject veti scrie cine sunteti (Nume, prenume complet, anul si forma de studii, Tema abordarii) Evaluare (60 * puncte_laborator + 40 * puncte_test_scris) / 1000 Puncte_Laborator >= 60, maxim = 100 Puncte_test_scris >= 40, maxim = 100 Laboratoarele nu se pot recupera ! Fiecare student va respecta orarul grupei din care face parte ! Nu se da test partial. Evaluarea de la mijlocul semestrului este cea de la laborator.
Transcript

Pag. 1 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

IOAN ASIMINOAEI

Email: [email protected]

Mod de adresare pentru e-mail :

In subject veti scrie cine sunteti (Nume, prenume

complet, anul si forma de studii, Tema abordarii)

Evaluare

(60 * puncte_laborator + 40 * puncte_test_scris) / 1000

Puncte_Laborator >= 60, maxim = 100

Puncte_test_scris >= 40, maxim = 100

Laboratoarele nu se pot recupera !

Fiecare student va respecta orarul

grupei din care face parte !

Nu se da test partial. Evaluarea de la

mijlocul semestrului este cea de la

laborator.

Pag. 2 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

Bibliografie

1. Tom Archer : Inside C# Second Edition

2. Tom Barnaby : Distributed .NET Programming in C#

3. Joseph C. Rattz, Jr. : Language Integrated Query in C# 2008

4. Chris Sells, Michael Weinhardt: Windows Forms 2.0

Programming

5. Andrew Troelsen: Pro C# 2008 and the .NET 3.5 Platform,

Fourth Edition

6. MSDN

7. Steve Resnik, Richard Crane, Chris Bowen: Essential Windows Communication Foundation for .NET Framework

3.5

8. Charles Petzold: Programming Windows with Windows

Forms ...

9. David Sceppa : Programming ADO.NET

10. codeproject, codeguru, etc.

Utilitare

CSharpDeveloper – free

DevCSharp Express – free (limitat la anumite tipuri de aplicatii).

Visual Studio 2008, 2010, 2013, 2015

Reflector, ILSpy - decompilatoare

FxCop

ILDASM – Microsoft (dezasamblor)

Pag. 3 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

Curs 1-2: Arhitectura .NET Framework

Cuprins

Arhitectura .NET Framework

� CLR – Common Language Runtime

o CTS – Common Type System

o CLS – Common Language Specification

� BCL (FCL) – Base Class Library (Framework Class

Library)

o Tipuri de aplicatii ce pot fi dezvoltate sub aceasta platforma

o Spatii de nume

� Trasaturi principale ale limbajului C#.

� Tipuri

o Tip Valoare o Tip Referinta

� Metode

o ale instantei o statice

� Modificatori de acces pentru tip.

� Constructori. Constructori statici.

� Clase statice. Metode extinse.

� Proprietati. Delegates. Evenimente.

� Mostenire.

� Polimorfism.

Pag. 4 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

Arhitectura framework .NET poate fi reprezentata astfel :

• Biblioteca de clase de baza din .NET (BCL)

• Common Language Runtime (CLR)

Componente principale pentru .NET:

• CLR – Common Language Runtime;

o CTS – Common Type System;

o CLS – Common Language Specification;

• BCL / FCL – Base Class Library / Framework Class Library.

Trasaturi .NET:

• Interoperabilitate cu codul existent (COM poate interopera cu .NET si invers, apel

functii din C/C++);

• Integrare completa si totala a limbajului (mostenire intre tipuri create in limbaje

diferite, manipularea exceptiilor, depanare) ;

• Motor de runtime comun tuturor limbajelor (CLR) ;

• Biblioteca unica de clase (FCL/BCL) ;

• Constructia componentelor COM mult mai usoara (nu e nevoie de IClassFactory,

IUnknown, IDispatch, cod IDL, etc.) ;

• Model simplificat de distribuire a aplicatiilor (nu mai e nevoie de inregistrare in

registri, se permit multiple versiuni ale aceleasi biblioteci *.dll) .

• etc.

Pag. 5 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

C# Limbaj dezvoltat de MS pentru .NET.

Toate exemplele din curs vor fi date folosind acest limbaj.

Trasaturi principale ale acestui limbaj :

• Nu se mai lucreaza cu pointeri ;

• Management automat al memoriei (C# nu suporta « delete » pe un obiect creat) ;

• Supraincarcarea operatorilor ;

• Suport pentru programarea bazata pe atribute ;

• Tipuri generice ;

• Suport pentru metode anonime ;

• Simplificari in implementarea modelului « delegate/event » ;

• Abilitatea de a defini un singur tip in mai multe fisiere – « partial keyword» ;

• Suport pentru cereri – LINQ;

• Suport pentru tipuri anonime;

• Abilitatea de a extinde functionalitatea unui tip existent via metode extinse;

• Operatorul lambda (=>) ce simplifica lucrul cu delegates;

• Sintaxa de initializare a unui obiect nou creat ce da posibilitatea de a seta valorile

proprietatilor in momentul crearii obiectului.

Pag. 6 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

Definitii

Cod managed = cod gazduit de platforma .NET (scris in limbaje acceptate de .NET, ex. C#,

VB .NET, F#, etc.);

Fiecare tip este descris de metadata. Metadata este construita de compilator.

Cod unmanaged = cod ce nu e specific platformei .NET (de regula scris in alte limbaje, ex.

C, C++, Pascal, etc.).

Assembly = unitatea binara ce contine cod managed (definitie prescurtata) – poate avea

extensia dll sau exe dar ca structura sunt diferite fata de fisierele dll/exe din COM sau aplicatii

Win32.

Un assembly poate fi gazduit intr-un singur fisier (single file assembly) sau poate fi constituit

din mai multe fisiere (multifile assemblies). In cazul multifile assemblies unitatile

componente se numesc module. Cand se construieste assembly (multifile) unul din aceste

module este modulul primar ce va contine manifest (metadata).

Concluzie

Un assembly este o grupare logica de unul sau mai multe module ce este distribuit si

« versionat » ca o singura unitate.

Toate compilatoarele ce lucreaza sub platforma .NET emit cod (MS)IL si metadata.

Cod sursa (C#) -> Compilator C# -> fisier ce contine cod IL si metadata.

IL (Intermediate Language) referit ca CIL (Common Intermediate Language – ultima

denumire acceptata) sau MSIL.

Codul CIL este compilat in instructiuni specifice CPU de pe masina.

Entitatea ce compileaza codul se numeste just-in-time (JIT) compiler sau Jitter.

Pag. 7 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

Metadata

Pe langa instructiunile CIL, un assembly .NET contine metadata care descrie fiecare tip

(class, struct, enum, etc.) precum si membrii fiecarui tip (proprietati, metode,

evenimente, date membru, etc.).

Metadata poate fi inetrogata folosing reflection.

Manifest – metadata pentru assembly

Contine informatii despre assemblies necesari si assembly-ul curent pentru a functiona

corect : versiune, informatii despre copywright, etc.

Pag. 8 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

CTS – Common Type System

CTS – este o specificatie – descrie cum sunt definite tipurile si modul de comportare al

acestora.

Un tip poate contine zero sau mai multi membri.

Ce contine CTS?

class ; struct ; enum ; delegate ; event ;

membri (tipuri preconstruite sau tipuri din BCL sau tipuri construite de dezvoltatori) ;

Spatiul de nume (namespace)

Namespace constituie o grupare logica de tipuri, continute intr-un assembly.

Exemplu

System.IO contine tipuri ce permit lucrul cu fisiere ;

System.Collections.Generic contine tipuri pentru colectii generice ;

System.Collections contine tipuri pentru colectii non-generice, etc.

Daca o aceeasi aplicatie este dezvoltata in VB .NET si apoi in C#, acestea vor folosi acelasi

spatiu de nume.

Pentru a accesa un anumit spatiu de nume se foloseste directiva using si se adauga o

referinta in proiect la assembly-ul respectiv.

Observatie :

Pentru System nu trebuie adaugata referinta la assembly.

Majoritatea assemblies-urilor din .NET framework sunt localizati in GAC (Global Assembly

Cache).

Exemplu

// Hello world in C# using System; public class Hello {

static void Main() {

Console.WriteLine("Hello world - C#"); }

} ' Hello world in VB Imports System Public Module Hello Sub Main()

Pag. 9 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

Console.WriteLine("Hello world - VB") End Sub End Module // Hello world in C++/CLI #include "stdafx.h" using namespace System; int main(array<System::String ^> ^args) {

Console::WriteLine(L" Hello world - C++/CLI"); return 0;

}

Observatie:

1. Se foloseste acelasi spatiu de nume System. Este in topul ierarhiei.

2. Se foloseste aceeasi metoda statica WriteLine din clasa Console.

3. Sintaxa difera de la limbaj la limbaj.

Pag. 10 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

BCL – Base Class Library (FCL – Framework Class Library)

CLR si BCL permit dezvoltarea urmatoarelor tipuri de aplicatii:

XML Web services;

Serviciile Web sunt construite la un nivel superior protocoalelor HTTP, XML, SOAP,

protocoale ce permit componentelor sa comunice independent de sistemul pe care se afla.

Spatiul de nume System.Web.Services defineste tipurile ce asigura functionalitatea

serviciilor Web

Web Forms – aplicatii bazate pe HTML

ASP.NET furnizeaza un set complet de tipuri pentru dezvoltarea de aplicatii bazate pe Web.

Acesta ofera compilarea dinamica a paginilor Web, abilitatea de a scrie scripturi in mai multe

limbaje .NET si abilitatea de a reutiliza tipuri .NET din pagini Web. Clasele principale pentru

ASP.NET se gasesc in spatiul de nume System.Web.UI.Page.

Windows Forms

Spatiul de nume System.Windows.Forms al cadrului de lucru .NET furnizeaza tipuri ce

suporta crearea de aplicatii cu interfata grafica (GUI), aplicatii dezvoltate pentru sistemele de

operare Windows. Tipurile din aceast spatiu de nume sunt similare in functionalitate cu

clasele din MFC sau alte biblioteci de clase (wxWidget). Important este ca tipurile din .NET

pot fi utilizate de orice limbaj compatibil cu .NET.

Clasele ajutatoare pentru dezvoltarea aplicatiilor Windows se gasesc sub acest spatiu de

nume : clase pentru butoane, controale, dialoguri, combo boxuri, etc.

Windows Console Applications – aplicatii de tip consola (CUI – Console User Interface).

WPF – Windows Presentation Foundation – aplicatii cu interfata grafica – GUI.

Windows services – aplicatii controlate de Windows Service Control Manager folosind

.NET.

Component library – componente dezvoltate de utilizator ce pot fi folosite in alte aplicatii

sau componente.

Exemple de spatii de nume

Spatiu de nume Descriere System Contine tipurile de baza folosite de orice aplicatie; System.Collections Contine tipurile ce gestioneaza colectii de obiecte ; include

colectiile stive, cozi, tabele hash, etc. System.Drawing Tipuri pentru grafice. System.Globalization Tipuri pentru NLS - National Language Support –comparare

stringuri, formatare, calendar. System.IO Tratare fisiere. System.Net Tipuri ce permit comunicatia in retea. System.Management Folosit in WMI (Windows Management Instrumentation). System.Reflection Permite inspectia metadatei.

Pag. 11 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

Tip valoare. Tip referinta.

Aceste tipuri reflecta modul cum variabilele sunt alocate si cum functioneaza acestea intern.

Toate tipurile se creaza folosind operatorul new.

Observatie.

Folosirea operatorului new nu inseamna ca tipurile se aloca in heap.

Declarare variabile si initializare

Ierarhia de clase a tipului sistem

Tot ce este derivat din System.ValueType se aloca pe stiva (tip valoare), orice altceva se

aloca in heap (tip referinta) si este eliberat de catre garbage collector.

Echivalente int <=> System.Int32 int n <=> System.Int32 n ;

Pag. 12 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

Tipurile numerice din .NET suporta proprietatile MinValue si MaxValue.

Tip valoare : variabila contine valoarea.

� Nu poate fi null (o variabila de tip value are intotdeauna o valoare) daca nu e declarat

“nullable”.

� Folosirea unei asemenea variabile ca argument al unei functii are ca efect pasarea

valorii. Modificarea valorii in cadrul functiei este locala.

Tipurile “nullable” sunt instante ale structurii System.Nullable<T>. Unui tip « nullable »

i se poate atribui o valoare conform tipului T sau valoarea null. Abilitatea de a atribui null

la tipuri numerice sau boolean este folositoare cand se lucreaza cu baze de date sau pentru a

marca faptul ca o variabila nu a fost initializata.

De exemplu un tip numeric intr-o tabela dintr-o baza de date poate avea o valoare sau poate fi

nedefinit (null).

Exemplu:

// se aloca 32 biti pentru nVarsta iar valoarea este 22 System.Int32 nVarsta = 22; // <=> int nVarsta = 32 ; // m este de tip int si nullable int ? m = null; // <=> Nullable<System.Int32> m = null ;

Pentru a determina valoarea unui asemenea tip se folosesc proprietatile HasValue si Value

ca in exemplul de mai jos :

class ExNullable { public static void Main() { int? m = null; if (m.HasValue == true) { System.Console.WriteLine("m = " + m.Value); } else { System.Console.WriteLine("m = Null"); } } }

De fiecare data cand declaram o variabila de un anumit tip, sistemul aloca numarul de octeti

asociati tipului respectiv si se poate lucra in mod direct cu memoria alocata.

Intrebare :

Un tip valoare poate contine tip referinta ?

Raspuns : DA.

Reamintim ca tipul struct este tip valoare.

Putem construi o structura ce contine ca data membru un tip referinta.

Sa analizam urmatorul cod.

Pag. 13 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

// definim un tip referinta public class Info { string HostName; public Info() { HostName = Environment.MachineName; } public void PrintHostName() { Console.WriteLine("Machine Name = {0}", HostName); } }

/// <summary> /// Definim un tip valoare ce contine un tip referinta /// </summary> public struct InfoStructure { // tip referinta public Info info; // tip referinta public string SystemDirectory; public int an; // tip valoare public InfoStructure(Info _info, string _sd) { info = _info; SystemDirectory = _sd; an = 2012; } public void PrintInfoStructure() { Console.WriteLine("PrintInfoStructure"); info.PrintHostName(); Console.WriteLine("System directory : {0}", SystemDirectory); Console.WriteLine("An = {0}", an); } }

In Main scriem urmatorul cod pentru testare

class Program { static void Main(string[] args) { Info info = new Info(); info.PrintHostName(); InfoStructure infoStr = new InfoStructure(info, Environment.SystemDirectory); infoStr.PrintInfoStructure(); // sau InfoStructure creat fara a folosi operatorul new InfoStructure infos;

Pag. 14 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

infos.info = new Info(); infos.SystemDirectory = Environment.SystemDirectory; infos.an = 2013; infos.PrintInfoStructure(); Console.ReadLine(); } }

Pag. 15 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

Tipuri referinta

Tipurile referinta sunt similare cu referintele din C++; pot fi considerati ca pointeri

siguri.

O referinta poate fi null. Cand referinta nu este null atunci puncteaza la obiectul de tipul

specificat si care a fost deja alocat in heap.

Observatie Referinta la un tip referinta este memorata pe stiva.

Exemplu:

System.String strString = "Hello, World";

Efect:

• s-a alocat memorie in heap;

• s-a copiat sirul de caractere “Hello, World”;

• se returneaza o referinta la aceasta valoare.

• referinta este memorata pe stiva. In continuare urmeaza o descriere a principalelor tipuri din CTS.

Tipuri din CTS – Common Type System Tipul class in C# O clasa este un tip definit de utilizator. Clasa este un tip referinta.

O clasa poate contine declaratii pentru urmatorii membri:

• Constructori

• Destructori

• Constante

• Campuri

• Metode

• Proprietati

• Indexers-i

• Operatori

• Evenimente

• Delegates

• Clase

• Interfete

• Structuri

Instanta unei clase se numeste obiect si se creaza folosind operatorul new. Clasele statice si

abstracte nu pot fi instantiate.

Pag. 16 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

Observatie Destructorii se folosesc, in general, in clase ce contin resurse unmanaged si vor fi discutati la

cursul despre gestiunea memoriei - Garbage Collection. Destructorii sunt apelati de Garbage

Collector.

O clasa poate sa mosteneasca o singura clasa si poate implementa mai multe intefete, altfel

spus exista mostenire simpla la nivel de clase si mostenire multipla la nivel de interfete.

Sintaxa pentru definirea unei clase este (forma simplificata):

[atribut] [nivel_de_acces] [tip_clasa] class nume_clasa [:clasa_de_baza, Interfata_1, Interfata_2,...] { // corpul clasei }

unde:

atribut : Optional. Reprezinta un atribut (este o clasa derivata din System.Attribute). Vezi

cursul ce descrie atributele.

nivel_de_acces: stabileste "vizibilitatea" clasei. Valoarea implicita este internal - clasa

definita la nivel de namespace - sau private - clasa imbricata.

tip_clasa: Optional. In cazul cand se foloseste poate avea valorile:

abstract, new (folosit pentru clase imbricate), sealed, static.

Exemplu namespace Curs

{ class Persoana // echivalent internal class Persoana { // Date membru (campuri, variabile membru) public string nume; public int varsta; // ctor public Persoana(string nume, int varsta) { this.nume = nume; this.varsta = varsta; } // metoda a instantei public void Display() { Console.WriteLine("Nume: {0}, Varsta: {1}",

nume, varsta); } }

}

Crearea obiectului poate fi facuta astfel:

Persoana p = new Persoana("X", 12);

Pag. 17 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

sau

Persoana p; // nu se creaza obiectul. p are valoarea null. p = new Persoana("X", 12); sau Persoana p = new Persoana() { nume = “X”, varsta = 12 }

Observatie 1. Operatorul new poate fi folosit si pentru a crea tipuri valoare.

2. In C++ putem crea obiectele pe stiva printr-un apel de forma

Persoana p;

sau in heap folosind sintaxa :

Persoana p = new Persoana("X", 12);

In C++ trebuie sa avem grija sa dealocam din heap acest obiect (delete p;). In C# nu mai

trebuie sa facem acest lucru.

Orice clasa are cel putin un ctor. Daca nu-l definim noi, compilatorul va genera un ctor

implicit. Daca am declarat un ctor cu parametri, compilatorul nu va mai genera un ctor

implicit. In majoritatea cazurilor modificatorul de acces pentru ctor este public, dar aceasta nu

constituie o regula.

Ctor initializeaza starea obiectului. Daca avem un tip ce are o multime de date membru nu

suntem obligati sa trecem initializarea acestora in ctor. Ctor implicit inainte de a crea obiectul

in memorie se asigura ca toate datele membru au valori implicite. Ctor va atribui valori

implicite pentru tipurile valoare si valoarea null pentru tipurile referinta. De obicei valorile

numerice sunt initializate cu zero.

Exemplu de cod eronat (FxCop semnaleaza acest lucru, e doar un avertisment, nu o eroare in

adevaratul sens al cuvantului)

class Persoana { int varsta = 0 ; string nume ; public Persoana()

{ nume = “X” ; }

}

Data membru varsta este initializata de doua ori. A doua oara o face ctor.

Pag. 18 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

Un tip poate avea definiti mai multi ctori. Diferenta este data de numarul parametrilor si de

tipul acestora.

Modificator de acces in

C# pentru tipuri Descriere

public Membrul este accesibil din afara definitiei clasei si a ierarhiei

claselor derivate.

protected Membrul nu este vizibil in afara clasei si poate fi accesat

numai de clasele derivate.

private Membrul nu este vizibil in afara clasei si nici in clasele

derivate.

internal

Membrul este vizibil numai in interiorul unitatii curente de

compilare, numai din fisierele din acelasi assembly. Acest

modificator creaza un hibrid intre public si protected, totul

depinzind in ultima instanta de locul unde se afla codul. O

utilizare comuna a acestui modificator este in dezvoltarea

bazata pe componente pentru ca permite unui grup de

componente sa coopereze intr-un mod privat.

protected internal * Accesul este limitat la assembly-ul curent sau la tipurile

derivate din clasa continuta.

Observatie :

La nivel de namespace un tip are modificatorul de acces internal sau public.

Clasele « imbricate » (« nested ») pot avea oricare din modificatorii de acces de mai sus.

Ex : namespace Info { class Persoana { ...} // implicit este internal public class Client { ... }

// Clasa de baza ce poate fi extinsa in procesul de derivare. // Contine cel putin o metoda sau proprietate ce trebuie // implementata de clasa derivata. // Nu poate fi instantiata.

public class abstract BazaInfo { ... }

// Nu poate fi folosita in procesul de derivare. public sealed class ClasaFinala { ... } } namespace InfoNested { class Persoana

{ private class Copil { ... } }

Pag. 19 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

public class Client { private class Banca { ... } public class Adresa { ... } protected class Comanda { ... } } // contine numai metode / date statice public static class Print { ... }

}

Modificatori de acces pentru date membru (fields) :

Membru in Accesibilitate

implicita

Permite modificarea accesibilitatii

enum public -

class

(aici class

apare ca data

membru in alta

clasa)

private public

protected

internal

private

protected internal

interface public -

struct private public

internal

private

In C# trebuie sa indicam pentru fiecare data membru modificatorul de acces.

Constructori. Inlantuire constructori. Cuvantul cheie this. public class Persoana { int varsta; string nume; public Persoana() : this(0,””)

{} public Persoana (int varsta) : this(varsta, “”) {} public Persoana (string nume) : this (0, nume); // constructorul general public Perosna(int varsta, string nume) { this.varsta = varsta; this.nume = nume; }

}

Pag. 20 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

Metode statice, membri statici

Metodele statice nu pot lucra cu instante ale tipului. Se apeleaza furnizand numele clasei

urmat de . (punct) si apoi numele metodei.

public class Info { public static Print

{ Console.WtiteLine(“Metoda statica Print din clasa Info”); }

}

iar apelul este de forma

Info.Print() ;

Membri statici pot opera numai cu date statice si pot apela metode statice din tipul definit.

Campurile statice sunt create o singura data indiferent de cate instante ale tipului se vor crea.

Toate instantele create vor avea acceasi valoare pentru o data statica.

Intrebare :

Putem folosi un tip referinta ca fiind static in interiorul altui tip?

Raspunsul il gasim in urmatorul cod:

public class InfoStatic { public static Info info = new Info(); // metoda a instantei public void PrintInstanta() {

// in clasa Info de la exemplul anterior am declarat // HostName ca fiind public

Console.WriteLine("class InfoStatic. Metoda a instantei. Machine name = {0} ", info.HostName); info.PrintHostName(); } // metoda statica public static void PrintStatic() { Console.WriteLine("class InfoStatic. Metoda statica. {0} ",

info.HostName); } }

Testarea functionalitatii acestei clase se poate face astfel:

// test class InfoStatic, apel metoda statica

InfoStatic.PrintStatic(); // apel metoda a instantei InfoStatic infoStatic = new InfoStatic(); infoStatic.PrintInstanta();

Pag. 21 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

Specificarea informatiei la run-time in lista de initializare a constructorului

Probleme legate de membrii statici si membrii instanta in initializarea constructorilor.

In C# numai membrii statici pot fi utilizati, in lista de initializare, cand se apeleaza

constructorii din clasa de baza. Mai exact, daca ctor din clasa derivata nu are parametri iar

ctor din clasa de baza are parametri atunci in lista de initializare trebuie specificati membri

statici.

Exemplu

class Baza { protected Baza(int i) { } }; class Derivata : Baza { int i;

// Eroare!!! Explicati! public Derivata() : base(i) { } };

Rezolvarea consta in a folosi o membri statici in lista de initializare a ctorului.

Constructor static

Reguli

• Clasa data (sau o structura) poate defini un singur ctor static.

• Ctor static nu are modificatori de acces si nu poate avea parametri.

• Un ctor static se executa o singura data, indiferent de cate obiecte s-au creat din tipul

respectiv.

• Runtime-ul invoca ctor static cand creaza o instanta a clasei sau inainte de a accesa

primul membru static invocat de apelant.

• Ctor static se executa inaintea oricarui ctor al instantei.

Exemplu class Bicicleta { public string model; public static int nRoti; static Bicicleta () { nRoti = 2; } public Bicicleta()

{ model = "necunoscut" ; }

}

Pag. 22 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

Clase statice. Metode extinse.

Daca am definit o clasa ca fiind statica, aceasta nu poate fi instantiata cu operatorul new si

trebuie sa contina numai membri (date, metode) statici.

Totul se aloca pe stiva si ca urmare garbage collector nu are in vedere asemenea tipuri.

Unde sunt folosite ?

Vezi metodele extinse si nu numai.

Metodele extinse permit ca pentru tipurile compilate existente sa se adauge noi

functionalitati, fara a fi nevoiti sa rescriem tipul. Metodele extinse se aplica si pentru clasele

« sealed » (o clasa « sealed » nu poate fi utilizata in procesul de derivare).

Aceasta tehnica adauga noi metode pentru un tip in contextul aplicatiei curente.

Analizati cu atentie exemplul de mai jos.

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Reflection; namespace ExtensionMethod {

/// <summary> /// Metode extinse pentru tipul System.Int32 /// 1. Clasa trebuie sa fie statica /// 2. Metoda trebuie sa fie statica /// 3. Primul parametru al metodei this urmat de tipul pe care /// se va aplica metoda /// </summary>

public static class MetodeExtinse {

// Metoda permite unui obiect sa afiseze assembly // in care este definit

public static void AfisareAssemblyGazda(this object obj) { Console.WriteLine("{0} Este definit in:\n\t->{1}\n", obj.GetType().Name, Assembly.GetAssembly(obj.GetType())); } // Inverseaza cifrele unui numar intreg (Ex. 13 -> 31) // Metoda extinsa pentru tipul int public static int InversareIntreg(this System.Int32 i) { // Transform intregul in string si apoi

// iau toate caracterele char[] digits = i.ToString().ToCharArray(); // Inversez articolele in array Array.Reverse(digits);

Pag. 23 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

// Construiesc un nou string string newDigits = new string(digits); // Conversie la intreg si return return int.Parse(newDigits); } // metoda extinsa pentru tipul int public static int Aduna(this System.Int32 n, int m) { return n + m; } } // Test class Program { static void Main(string[] args) { int Index = 12; int n = 13; // apel metoda extinsa int ns = n.InversareIntreg(); Console.WriteLine("Intreg initial = {0},

si inversat = {1}",n, ns); // apel metoda extinsa ce aduna doua numere intregi n = Index.Aduna(n); // n = n + Index Console.WriteLine("Adunare : " + n.ToString()); // apel metoda extinsa pe tipul object object o = n; o.AfisareAssemblyGazda(); } } }

Desi metodele AfisareAssemblyGazda, Aduna, InversareIntreg au fost definite ca

fiind statice in cadrul unei clase statice, ele se apeleaza pe o instanta a tipului. Analizati

prototipurile metodelor extinse si modul de apel.

Ce observati ?

Primul parametru al metodei extinse indica tipul pentru care se aplica acea metoda.

Pag. 24 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

Metode ale instantei. Metode statice.

Metodele sunt totdeauna definite in interiorul clasei sau structurii.

Metodele pot fi:

• instance (apelata ca o instanta a tipului in interiorul caruia metoda a fost definita)

sau

• static, unde metoda este asociata cu tipul insusi.

Metodele pot fi declarate ca virtual, abstract sau sealed.

Metodele pot fi supraincarcate (overloaded), suprascrise (overriden) si/sau ascunse

(hidden – vezi operatorul new).

Metodele instantei sunt apelate pe instanta obiectului.

Metodele statice nu sunt apelate pe instanta clasei ci prin prefixarea numelui metodei cu

numele clasei unde este definita.

Exercitiu

Presupunem ca implementam un tip ce contine o data membru statica.

Este posibil sa folosim aceasta data membru statica intr-o metoda a instantei tipului ?

Cuvantul cheie base

Scenariu

Presupunem ca am construit o clasa ce poate fi mostenita si furnizeaza mai multi

ctori. Folosim aceasta clasa intr-un proces de derivare iar clasa derivata

implementeaza mai multi ctori.

Intrebare :

Ce constructor se va apela din clasa de baza in momentul cand instantiem clasa derivata ?

base este folosit pentru apelul constructorilor din clasa de baza. Acesta se va folosi in

constructorul clasei derivate pentru a indica ce constructor va fi apelat - din clasa de baza.

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Exemplu { public class Baza { int n; string nume; public Baza(int _n) { Console.WriteLine("Baza ctor param int"); this.n = _n; } public Baza(int _n, string _str) :this(_n) {

Pag. 25 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

//this.n = _n; Console.WriteLine("Baza ctor param int si string"); this.nume = _str; } // alte metode ... }

public class Derivata : Baza { int x; public Derivata(int _x) : base(_x) { Console.WriteLine("Derivata ctor"); this.x = _x; } public Derivata(int _x, string s) : base(_x, s) { this.x = _x; Console.WriteLine("Derivata ctor param int, string"); } // alte metode ... } }

Supraincarcarea operatorilor (overloading)

Supraincarcarea operatorilor permite implementari ale operatorilor, implementari definite de

utilizator, pentru operatii unde unul sau ambii operanzi sunt tipuri definite de utilizator, tipuri

class sau struct.

Operatori supraincarcabili (MSDN)

Operators Overloadability

+, -, !, ~, ++, --, true, false These unary operators can be overloaded.

+, -, *, /, %, &, |, ^, <<, >> These binary operators can be overloaded.

==, !=, <, >, <=, >= The comparison operators can be overloaded

(but see note below).

&&, || The conditional logical operators cannot be

overloaded, but they are evaluated

using & and |, which can be overloaded;

see 7.11.2 User-defined conditional logical

operators.

[ ] The array indexing operator cannot be

overloaded, but you can define indexers.

( ) The cast operator cannot be overloaded, but you

Pag. 26 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

can define new conversion operators

(see explicit andimplicit).

+=, -

=, *=, /=, %=, &=, |=, ^=, <<=, >>=

Assignment operators cannot be overloaded,

but +=, for example, is evaluated using +, which

can be overloaded.

=, ., ?:, ->, new, is, sizeof, typeof These operators cannot be overloaded.

Observatie Operatorii de comparatie, daca sunt supraincarcati, trebuie supraincarcati in pereche. Daca ==

este supraincarcat, atunci trebuie supraincart si !=.

Exemplu (MSDN)

// complex.cs

using System;

public struct Complex

{

public int real;

public int imaginary;

public Complex(int real, int imaginary)

{

this.real = real;

this.imaginary = imaginary;

}

public static Complex operator +(Complex c1, Complex c2)

{

return new Complex(c1.real + c2.real, c1.imaginary + c2.imaginary);

}

Utilizare

Complex num1 = new Complex(2,3);

Complex num2 = new Complex(3,4);

Complex sum = num1 + num2;

Definire operatori pentru conversie

Se pot folosi operatori de conversie implicit sau explicit. Conversia explicita obliga la utilizare

cast.

Exemplu (MSDN) pentru conversie explicita

struct Digit

{

Pag. 27 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

byte value;

public Digit(byte value) //constructor

{

if (value > 9)

{

throw new System.ArgumentException();

}

this.value = value;

}

public static explicit operator Digit(byte b)

// explicit byte to digit conversion operator

{

Digit d = new Digit(b); // explicit conversion

System.Console.WriteLine("Conversion occurred.");

return d;

}

}

class TestExplicitConversion

{

static void Main()

{

try

{

byte b = 3;

Digit d = (Digit)b; // explicit conversion

}

catch (System.Exception e)

{

System.Console.WriteLine("{0} Exception caught.", e);

}

}

}

Exemplu (MSDN) conversie implicita

struct Digit

{

byte value;

public Digit(byte value) //constructor

{

if (value > 9)

{

throw new System.ArgumentException();

}

this.value = value;

}

Pag. 28 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

public static implicit operator byte(Digit d)

// implicit digit to byte conversion operator

{

System.Console.WriteLine("conversion occurred");

return d.value; // implicit conversion

}

}

class TestImplicitConversion

{

static void Main()

{

Digit d = new Digit(3);

byte b = d; // implicit conversion -- no cast needed

}

}

Pag. 29 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

Tipuri din CTS – Common Type System

Tipul structura - struct

Este asemanator cu cel din C. Layout-ul de memorie este diferit.

Compatibilitate cu structurile din C daca se foloseste atributul [StructLayout(Sequential)].

Structurile pot contine campuri si metode ce opereaza pe aceste date.

Structurile pot defini constructori, pot implementa interfete si pot contine orice numar de

proprietati, metode, evenimente si operatori supraincarcati.

Cuvantul cheie folosit in C# este struct.

struct Punct { public float x; public float y; // Constructor public Punct( float _x, float _y)

{ x = _x; y = _y; } // Metode public void Display() { Console.WriteLine(“ (x = {0}, y = {1}) “, x, y); }

}

Revedeti si exemplul cu InfoStructure prezentat la inceputul cursului.

Observatii:

� Campurile pot fi initializate numai daca sunt declarate const sau static.

Structura nu poate sa declare un ctor implicit.

� Structurile pot declara ctor cu parametri.

� Structura nu poate fi folosita in procesul de derivare.

� Structurile sunt copiate la atribuire.

� Sunt tipuri valoare.

� Structura poate implementa interfete.

� In C# struct este diferit de class.

� In C++ struct = public class.

Pag. 30 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

Tipuri din CTS – Common Type System

Tipul enumerare - enum

Enumerarile ne permit sa grupam o pereche de nume/valoare.

Cuvantul rezervat in C# este enum.

enum Stare { Valid = 1, Modificat = 2, Sters = 3 }

Tipul delegate din CTS - delegate

Delegates sunt echivalentul in .NET pentru pointeri la functii din C.

Delegate este o clasa derivata din System.MulticastDelegate.

In C# cuvantul cheie folosit este delegate.

Ex delegate bool EsteNumarPrim(int n);

Acest delegate poate puncta la orice metoda ce returneaza un bool si are ca parametru de

intrare un int.

Pentru exemplul dat, prototipul metodei este :

public bool EstePrim(int n) ;

Delegates in .NET constituie baza arhitecturii bazata pe evenimente si permit apel de metode

in mod asincron.

Observatie:

La intalnirea unei asemnea declaratii, compilatorul de C# va genera o clasa derivata din

System.MulticastDelegate. Mai multe detalii in cursul despre delegates.

Tipul “membri” din CTS

Un tip membru este un element al multimii

{constructor, finalizer, // destructor in C# static constructor, nested type – tip imbricat, operator, method, property, indexer, field, read-only field,

Pag. 31 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

constant, event}.

Fiecare membru are o anumita vizibiltate

(public, private, protected, internal, protected internal). Anumiti

membri pot fi declarati ca fiind abstract sau virtual sau static.

Tipul de data preconstruit (“intrinsec”) din CTS – tip VALOARE Tip Data in CTS VB .NET C# C++/CLI Keyword

System.Byte Byte byte unsigned char System.SByte SByte sbyte signed char System.Int16 Short short short System.Int32 Integer int int or long System.Int64 Long long __int64 System.UInt16 UShort ushort unsigned short System.UInt32 UInteger uint unsigned int or unsigned long System.UInt64 ULong ulong unsigned __int64 System.Single Single float Float System.Double Double double Double System.Object Object object Object^ System.Char Char char wchar_t System.String String string String^ System.Decimal Decimal decimal Decimal System.Boolean Boolean bool Bool

Metode cu si fara parametri

ref ca parametri ai metodei

Cuvantul cheie ref spune compilatorului C# ca argumentele pasate puncteaza la aceeasi

memorie ca si variabilele din codul apelant. Daca metoda apelata modifica valorile,

modificarile sunt vazute in codul apelant.

Restrictie:

Cand folosim ref, trebuie sa initializam argumentele inainte de a le folosi ca argumente ale

functiei. Exemplu:

class Color { public Color() { this.red = 0; this.green = 127; this.blue = 255; } protected int red; protected int green; protected int blue;

Pag. 32 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

public void GetRGB( ref int red, ref int green, ref int blue) { red = this.red; green = this.green; blue = this.blue; } }

class TestRef { static void Main(string[] args) { Color c = new Color(); // Initializare int red = 0; int green = 0; int blue = 0; c.GetRGB(ref red, ref green, ref blue); Console.WriteLine("R={0}, G={1}, B={2}", red, green, blue); } }

out ca parametri ai metodei

Are acelasi efect ca si ref, dar diferenta principala este ca nu e necesara initializarea

parametrilor inainte de apel.

Parametrii prefixati cu out trebuiesc modificati in metoda apelata, iar parametrii prefixati cu

ref pot fi modificati.

Exemplu: class Color { public Color() { this.red = 0; this.green = 127; this.blue = 255; } protected int red; protected int green; protected int blue; public void GetRGB(out int red, out int green, out int blue) { red = this.red; green = this.green; blue = this.blue;

Pag. 33 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

} }

class TestOut { static void Main(string[] args) { Color c = new Color(); int red; int green; int blue; c.GetRGB(out red, out green, out blue); Console.WriteLine("R={0}, G={1}, B={2}", red, green, blue); } }

Pag. 34 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

Pasarea unui tip referinta prin valoare (parametru al metodei)

Daca o variabila tip referinta este un argument al unei functii, atunci se poate modifica

continutul variabilei, adica starea obiectului dar nu si obiectul.

Intrebare :

Se poate modifica obiectul cand acesta este transmis ca parametru al unei functii?

vezi ex C1_2009 din d:\exenet

De comentat liniile ce contin apel prin referinta

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace C1_2009 { class Mate { public int Aduna(int x, int y) { return x + y; } public double Aduna(float x, float y) { return x + y; } public string Aduna(double x, double y, string text) { return " x + y = " + (x + y).ToString() +

" parametrul 3 este : " + text; } } class Persoana { public string nume; public int varsta; public Persoana(string nume, int varsta) { this.nume = nume; this.varsta = varsta; } public void Display() { Console.WriteLine("Nume: {0}, Varsta: {1}",

nume, varsta); } } class Program { static void Main(string[] args) { Mate m = new Mate();

Pag. 35 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

Console.WriteLine(" 1 + 2 = {0} ", m.Aduna(1, 2)); Console.WriteLine(" 1.5 + 2.0 = {0}", m.Aduna(1.5F, 2.0F)); Console.WriteLine(" 1.5 + 2.0 = {0} ", m.Aduna(1.5, 2.0, "Aduna cu trei parametri")); Console.WriteLine("\n\nTest Persoana parametru prin valoare"); Persoana p = new Persoana("Elena", 21); p.Display(); TransmitePersoanaPrinValoare(p); p.Display(); Console.ReadLine(); } static void TransmitePersoanaPrinValoare(Persoana p) { // Schimbam varsta? p.varsta = 99; // Apelantul va vedea aceasta reatribuire? // Cream un obiect nou p = new Persoana("Vasile", 99); } } }

Ce se intampla?

Pasarea unui tip referinta prin referinta

vezi ex C1_2009 din d:\exenet

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace C1_2009 { class Mate { public int Aduna(int x, int y) { return x + y; } public double Aduna(float x, float y) { return x + y; } public string Aduna(double x, double y, string text) { return " x + y = " + (x + y).ToString() +

" parametrul 3 este : " + text; } } class Persoana { public string nume; public int varsta;

Pag. 36 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

public Persoana(string nume, int varsta) { this.nume = nume; this.varsta = varsta; } public void Display() { Console.WriteLine("Nume: {0}, Varsta: {1}",

nume, varsta); } } // test class Program { static void Main(string[] args) { Mate m = new Mate(); Console.WriteLine(" 1 + 2 = {0} ", m.Aduna(1, 2)); Console.WriteLine(" 1.5 + 2.0 = {0}", m.Aduna(1.5F, 2.0F)); Console.WriteLine(" 1.5 + 2.0 = {0} ",

m.Aduna(1.5, 2.0, "Aduna cu trei parametri")); Console.WriteLine(

"\n\nTest Persoana parametru prin valoare"); Persoana p = new Persoana("Elena", 21); p.Display(); TransmitePersoanaPrinValoare(p); p.Display(); Console.WriteLine(

"\n\nTest Persoana parametru prin referinta"); p.varsta = 21; p.Display(); TransmitePersoanaPrinReferinta(ref p); p.Display(); Console.ReadLine(); } static void TransmitePersoanaPrinValoare(Persoana p) { // Schimbam varsta? p.varsta = 99; // Apelantul va vedea aceasta reatribuire? p = new Persoana("Vasile", 99); } static void TransmitePersoanaPrinReferinta(ref Persoana p) { // Schimbam varsta? p.varsta = 99; // Apelantul va vedea aceasta reatribuire? p = new Persoana("Vasile", 99); } } }

Pag. 37 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

Care este rezultatul?

Discutie

Reguli (de aur!):

• Daca un tip referinta este pasat prin referinta, apelatul poate schimba valoarea

starii obiectului (datele) cat si obiectul la care se face referire – se poate returna

un nou obiect.

• Daca un tip referinta este pasat prin valoare, apelatul poate schimba starea

datelor obiectului dar nu si obiectul la care se face referire.

Rezumat tip valoare si tip referinta

Intrebare Tip valoare Tip referinta

Unde este tipul alocat? Pe stiva In managed heap.

Cum este reprezentata

variabila?

Copii locale Puncteaza la memoria

alocata instantei

Care este tipul de baza ? System.ValueType Derivat din orice ce nu e

ValueType sau sealed.

Poate acest tip sa fie baza

pentru alte tipuri ?

Nu Da, daca nu e sealed.

Care e tipul implicit pentru

pasarea parametrilor?

Valoare. Se trimite o copie. Referinta.

Poate acest tip sa suprascrie

(override) metoda

System.Object.Finalize()?

Nu. Tipurile valoare nu fac

obiectul procesului de

garbage collection, sunt

alocate pe stiva.

Da. Indirect prin destructor.

Pot defini ctori pt acest tip ? Da. Numai ctor cu

parametru, ctor implicit

este rezervat.

DA!

Cand sunt distruse aceste

variabile ?

Cand sunt in afara blocului

unde au fost definite.

Cand nu mai e nevoie le

distruge garbage collector

(mod nedeterminist).

Tipul Nullable – se aplica numai tipului valoare

Nullable<bool> bOk = null ; // corect bool ? bOK = null ; // sintaxa prescurtata

Testul se face pe null. Vezi si proprietatile HasValue si Value.

// Citeste int din baza de date. int? i = dr.GetIntFromDatabase(); if (i.HasValue)

Console.WriteLine("Valoarea lui 'i' este: {0}", i.Value); else

Console.WriteLine("Valoarea lui 'i' este nedefinita."); // Citeste bool din baza de date. bool? b = dr.GetBoolFromDatabase(); if (b != null)

Pag. 38 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

Console.WriteLine("Valoare lui 'b' este: {0}", b.Value); else

Console.WriteLine("Valoarea lui 'b' este nedefinita.");

Prototipul pentru

public int? GetIntFromDatabase() {

return valoare; /* valoare trebuie sa fi fost

definta ca fiind Nullable */ }

Operatorul ??

ne permite sa atribuim o valoare pentru un tip declarat ca Nullable daca valoarea

acestuia este null.

Ex.

int? data = dr.GetIntFromDatabase() ?? 100;

Daca valoarea gasita este null se va returna valoarea 100.

Proprietati

Proprietatile nu permit accesul direct la membri, la campurile unde sunt memorate in fapt

datele. Sunt furnizati doi accesori (set, get) ce lucreaza direct cu data membru. Scopul este de

a pastra date cit mai corecte in obiectul instantiat.

• Proprietati clasice – au nevoie de camp suplimentar pentru memorare valoare.

• Pproprietati automate – nu au nevoie de camp suplimentar pentru memorare valoare.

Definirea si folosirea proprietatilor

O propritate in C# consta din declararea unui camp si a unui accesor folosit pentru a-i

modifica valoarea. Accesorii sunt referiti ca metode setter si getter.

[attributes] [modifers] <type> <property-name>{ [ set { <accessor-body> } ] [ get { <accessor-body >} ] }

Observatii

Nu e nevoie sa definim ambii accesori.

• get face proprietatea read

• set face proprietatea write

• proprietatea nu poate fi utilizata ca parametru intr-o metoda.

Pag. 39 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

• modificatorul static poate fi utilizat pentru proprietate.

Modificatorii de acces trebuiesc specificati la nivel de proprietate.

Proprietati automate : obligatoriu trebuie declarati ambii accesori get/set.

get / set pot avea modificatori de acces.

public int Intreg { get ; private set ;}

Proprietatea Intreg va fi setata in cadrul clasei. In afara clasei Intreg apare ca Read Only.

Nu mai trebuie sa declaram un camp suplimentar in cadrul clasei :

public class Persoana {

public string Name {get ; set ;} }

Dezavantaj: nu putem scrie cod pentru get / set.

Nou C# 6.0 public class Persoana

{

/* Getter only property with inline initialization */

public string Name { get; } = "Popescu"

/* Property with inline initialization */

public decimal Salar { get; set; } = 12345;

}

Exista deosebiri intre proprietati automate si campuri publice din clasa?

• Campurile (fields) pot fi folosite ca argumente cu ref/out. Proprietatile nu pot fi

folosite in acest mod.

• Un camp va furniza aceeasi valoare cand este apelat de mai multe ori (exceptie fire de

executie). O proprietate cum ar fi DateTime.Now furnizeaza valori diferite.

• Proprietatile pot genera exceptii, campurile nu.

• Proprietatile pot produce efecte secundare sau timpul de executie este mult mai mare.

Campurile nu – cu conditia sa fie folosite corect.

• Proprietatile suporta accesibilitati diferite, campurile nu. Campurile pot fi facute

readonly.

• Introspectia metadatei pentru proprietati se face cu metoda GetProperties, iar

pentru campuri cu metoda GetFields.

• Proprietatile pot fi folosite in interfete, campurile nu.

interface IPerson { string FirstName { get; set; } string LastName { get; set; } }

Pag. 40 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

Exemplu de folosire interfata (implementare):

class Person: IPerson {

private string _name;

public string FirstName {

get {

return _name ?? string.Empty;

} set {

if (value == null) throw new System.ArgumentNullException("value"); _name = value;

} } ...

}

Evenimente

Evenimentele permit unei clase sau unui obiect de a notifica alte clase sau obiecte cand s-a

intamplat ceva in cadrul obiectului. Clasa ce trimite evenimentul se numeste publisher si clasa

ce primeste (sau trateaza evenimentul, raspunde la eveniment) se numeste subscriber.

Evenimentele au urmatoarele proprietati:

� Obiectul publisher deteremina cand se genereaza evenimentul; subscriber-ul determina

ce actiune se va executa la aparitia evenimentului.

� Un eveniment poate avea mai multi subscriber-i, adica mai multe clase pot declara

metode ce trateaza acel eveniment. In acest caz metodele ce trateaza evenimentul sunt

apelate in mod sincron.

� Un subscriber poate trata mai multe evenimente de la publisher-i diferiti.

� Evenimentele ce nu au subscriber nu sunt generate.

Toate evenimentele din FCL sunt bazate pe delegate EventHandler, ce este definit astfel:

public delegate void EventHandler(object sender, EventArgs e);

.NET Framework 2.0 defineste o versiune generica a acestui delegate, EventHandler<TEventArgs>.

Utilizare pattern EventHandler

1. Stabilire parametri pentru eveniment. Clasa trebuie derivata din

System.EventsArgs. Se declara proprietati in aceasta clasa, proprietati ce sunt

vizibile in “publisher” si in “subscriber”. In ex. de mai jos proprietatea este Message.

public class CustomEventArgs : EventArgs {

Pag. 41 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

public CustomEventArgs(string s) { msg = s; } private string msg; public string Message { get { return msg; } } }

2. Stabilire delegate.

a. Daca folosim versiunea generica EventHandler<TEventArgs> nu

avem nimic de declarat.

b. In caz contrar definim delegate-ul (in ex se numeste CustomDelegate)

vizibil in publisher:

public delegate void CustomEventHandler( object sender, CustomEventArgs a);

3. Declaram evenimentul in clasa publisher.

3.1 In cazul (2.a, versiunea non-generica) declaratia este:

public event EventHandler RaiseCustomEvent;

In cazul (2.a, versiunea generica) declaratia este:

public event EventHandler<CustomEventArgs> RaiseCustomEvent;

3.2 In cazul (2.b) declaratia este:

public event CustomEventHandler RaiseCustomEvent;

4. In clasa publisher trebuie definita o metoda ce va face posibil apelul subscriber-ilor.

Aceasta metoda se apeleaza din cadrul altei metode din aceasta clasa, altfel spus se

genereaza evenimentul. Codul cel mai simplu ar putea fi: protected virtual void OnRaiseEvent(// parametri) {

// cod stabilire valori pentru sender si paramsEvent // ... // Cazul generic. Decomentati linia de mai jos.

// EventHandler<CustomEventArgs> handler = RaiseCustomEvent;

// Cazul non-generic. Decomentati linia de mai jos // CustomEventHandler handler = RaiseCustomEvent;

if (handler != null)

handler(sender, paramsEvent); }

Observatie

Pag. 42 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

Aceasta metoda va fi apelata de alte metode din clasa publisher.

In clasa subscriber va trebui sa ne inscriem pentru acest eveniment astfel:

class Subscriber

{

private string id;

public Subscriber(string ID, Publisher pub)

{

id = ID;

// Atasare metoda la evenimentul RaiseCustomEvent

// Inscriere pentru eveniment

pub.RaiseCustomEvent += HandleCustomEvent;

}

// Definire metoda HandleCustomEvent

void HandleCustomEvent(object sender, CustomEventArgs e)

{

// cod ...

}

}

Boxing si Unboxing

Conversii

Boxing = conversia de la tip valoare la tip referinta.

Unboxing = conversia de la tip referinta la tip valoare.

Conversia din tip valoare la tip referinta (boxing)

Se creaza o copie noua a obiectului ce va fi supus conversiei. Exemplu int nVarsta = 22; // tip valoare object refVarsta = nVarsta; // nVarsta este convertit la refVarsta // nu e nevoie de o conversie explicita

1. se aloca memorie in heap, atat pentru a mentine valoarea obiectului cat si pentru a

mentine starea acestuia (metode, structuri interne, tabela de metode virtuale).

2. Se copie valoarea la noua adresa.

3. Adresa obiectului nou alocat este plasata pe stiva si acum puncteaza la un obiect

referinta.

Conversia din tip Referinta la tip valoare (unboxing)

Nu se creaza o noua copie a obiectului supus conversiei.

In acest caz conversia poate fi facuta la orice tip. Se aplica reguli stricte definite in CTS.

Exemplu:

Pag. 43 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

int nVarsta = 22; // tip valoare. object refVarsta = nVarsta; // (boxed) refVarsta puncteaza la nVarsta int nAlt = (int)refVarsta; // (Unboxed) inapoi la int. // este nevoie de o conversie explicita

Sa urmarim urmatorul cod si apoi sa vedem ce este in CIL. …

int n1 = 32; object refn1 = n1; // boxing Console.WriteLine("Initial n1 = {0}", n1, refn1); Console.WriteLine("Initial refn1 = {0}", refn1); n1 = (int) refn1; // unboxing n1 = 33; Console.WriteLine("Dupa Initial n1 = {0},

refn1 = {1}", n1, refn1); … In CIL avem: .method private hidebysig static void Main(string[] args) cil managed { .entrypoint .custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = ( 01 00 00 00 ) // Code size 73 (0x49) .maxstack 3 .locals init ([0] int32 n1, [1] object refn1) IL_0000: ldc.i4.s 32 IL_0002: stloc.0 IL_0003: ldloc.0 IL_0004: box [mscorlib]System.Int32 IL_0009: stloc.1 IL_000a: ldstr "Initial n1 = {0}" IL_000f: ldloc.0 IL_0010: box [mscorlib]System.Int32 IL_0015: ldloc.1 IL_0016: call void [mscorlib]System.Console::WriteLine(string, object, object) IL_001b: ldstr "Initial refn1 = {0}" IL_0020: ldloc.1 IL_0021: call void [mscorlib]System.Console::WriteLine(string, object) IL_0026: ldloc.1 IL_0027: unbox [mscorlib]System.Int32 IL_002c: ldind.i4 IL_002d: stloc.0 IL_002e: ldc.i4.s 33 IL_0030: stloc.0 IL_0031: ldstr "Dupa Initial n1 = {0}, refn1 = {1}" IL_0036: ldloc.0

Pag. 44 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

IL_0037: box [mscorlib]System.Int32 IL_003c: ldloc.1 IL_003d: call void [mscorlib]System.Console::WriteLine(string, object, object) IL_0042: call string [mscorlib]System.Console::ReadLine() IL_0047: pop IL_0048: ret } // end of method Test::Main

Mostenire si polimorfism

Mostenirea faciliteaza reutilizarea codului.

Reutilizarea codului poate fi facuta in doua moduri :

• mostenire clasica ce stabileste o relatie de « este un » - « is-a » ;

• containment / agregare ce stabileste o relatie de « are un » - « has-a ».

Cand stabilim o relatie « is-a » intre clase, construim de fapt o dependenta intre doua sau mai

multe clase. Ideea este ca noua clasa poate extinde functionalitatea clasei existente (clasa de

baza).

Daca o clasa este declarata « sealed » atunci aceasta nu poate fi folosita drept clasa de baza

pentru o alta clasa (clasa “sealed” nu poate fi extinsa prin procesul de mostenire).

In .NET exista mostenire simpla a claselor si mostenire multipla a interfetelor.

In cazul polimorfismului vom folosi cuvintele cheie virtual si override pentru metoda in

cauza.

• virtual se foloseste in clasa de baza.

• override se foloseste in clasa derivata.

Observatie Functia suprascrisa trebuie sa aiba acelasi nivel de acces ca si functia virtuala pe care o

suprascrie.

Un membru virtual nu poate fi declarat private.

Exemplu:

class Persoana { public string name; public Persoana(string name) { this.name = name; } public virtual void Calcul() { Console.WriteLine( "Persoana.Calcul apelata pentru {0}", name);

Pag. 45 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

} } class ContractPersoana : Persoana { public ContractPersoana(string name) : base(name) { } public override void Calcul() { Console.WriteLine( "ContractPersoana.Calcul apelata pentru {0}", name); } } class Salariat : Persoana { public Salariat (string name) : base(name) { } public override void Calcul() { Console.WriteLine( "Salariat.Calcul apelata pentru {0}", name); } } class TestPolimorfism { protected Persoana[] persoane; public void LoadPersoane() { // Simulare incarcare din baza de date persoane = new Persoana[2]; persoane[0] = new ContractPersoana("ABBA"); persoane[1] = new Salariat("Evora"); } public void DoCalcul() { for (int i = 0; i < persoane.GetLength(0); i++) { persoane[i].Calcul(); } } static void Main(string[] args) { TestPolimorfism t = new TestPolimorfism(); t.LoadPersoane(); t.DoCalcul(); } }

Pag. 46 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

Metode: combinatie new si virtual Putem combina new si virtual cand declaram o functie.

Pentru ca este new ea ascunde orice functie mostenita cu aceeasi semnatura.

Pentru ca este virtual ea poate fi suprascrisa in clasele derivate.

Exemplu class Persoana { public string name; public Persoana(string name) { this.name = name; } public virtual void Calcul() { Console.WriteLine( "Persoana.Calcul apelata pentru {0}", name); } } class Salariat : Persoana { public Salariat (string name) : base(name) { } public new virtual void Calcul() { Console.WriteLine( "Salariat.Calcul apelata pentru {0}", name); } } class ContractPersoana : Salariat { public ContractPersoana(string name) : base(name) { } public override void Calcul() { Console.WriteLine( "ContractPersoana.Calcul apelata pentru {0}", name); } } class Test { protected Persoana[] persoane; public void LoadPersoane()

Pag. 47 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

{ persoane = new Persoana[2]; persoane[0] = new ContractPersoana("ABBA"); persoane[1] = new Salariat("Evora"); } public void DoCalcul() { for (int i = 0; i < persoane.GetLength(0); i++) { persoane[i].Calcul(); } } static void Main(string[] args) { Test t = new Test(); t.LoadPersoane(); t.DoCalcul(); } }

Rezultatul va fi:

?

Urmatoarele doua declaratii sunt identice: public new virtual void Calcul() //public virtual void Calcul()

Implementare polimorfism folosind clase abstracte

In acest caz in clasa de baza se declara metoda ca fiind abstract iar in clasa derivata

override.

Exemplu (Troelsen):

// Clasa de baza abstracta abstract class Shape {

public Shape() {} public Shape(string name = "NoName")

{ PetName = name; } public string PetName { get; set; } // Metoda abstracta. Se forteaza scrierea codului // in clasa derivata – in caz contrar clasa derivata // trebuie declarata abstracta public abstract void Draw();

}

Clasa derivata: class Circle : Shape {

public Circle() {}

Pag. 48 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

public Circle(string name) : base(name) {} public override void Draw() {

Console.WriteLine("Drawing {0} the Circle", PetName); }

} class Hexagon : Shape {

public Hexagon() {} public Hexagon(string name) : base(name) {} public override void Draw() {

Console.WriteLine("Drawing {0} the Hexagon", PetName); }

}

in Main putem scrie codul: static void Main(string[] args) {

Console.WriteLine("***** Polymorphism *****\n"); // Construim un array de obiecte Shape compatibile. Shape[] myShapes = {

new Hexagon(), new Circle(), new Hexagon("H1"), new Circle("C"), new Hexagon("H2")};

// Iterare pe articolele din array si apelul metodei Draw(). foreach (Shape s in myShapes) {

s.Draw(); } Console.ReadLine();

}

Rezultatul va fi: ***** Polymorphism ***** Drawing NoName the Hexagon Drawing NoName the Circle Drawing H1 the Hexagon Drawing C the Circle Drawing H2 the Hexagon

Suprascrierea proprietatilor mostenite

Proprietatea trebuie specificata ca fiind virtual in clasa de baza pentru a o suprascrie, iar in

clasa derivata override..

using System; class FlatFile { public FlatFile(string fileName) { this.fileName = fileName; }

Pag. 49 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

protected string fileName; public virtual string FileName { get { return fileName; } } } class FlatTable : FlatFile { public const string FILENAME = "flatfile.txt"; public FlatTable() : base(FILENAME) {} public override string FileName { get { return "Flat table"; } } }

Clasa abstracta ce contine o proprietate abstracta

abstract class AbstractBaseClass { public abstract double AbstractProperty { get; set; } }

In exemplul urmator este descrisa suprascrierea proprietatilor mostenite (proprietatile sunt

declarate abstract). Acelasi mecanism: abstract in clasa de baza si override in clasa derivata.

using System; using System.Collections; abstract class Persoana { protected Persoana(int Id, int ore) { this.Id = Id; OreLucrate = ore; } protected int Id; public int PersoanaId { get { return Id; } } protected int OreLucrate; protected double costOra = -1; // initializare public abstract double CostOra { get; } }

Pag. 50 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

class ContractPersoana : Persoana { public ContractPersoana(int Id, double _ore, int _oreLucrate) : base(Id, _oreLucrate) { costOra = _ore; } protected double costOra; public override double CostOra { get { return costOra; } } }

Pag. 51 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

In acest curs am abordat urmatoarele teme:

Arhitectura .NET Framework

� CLR – Common Language Runtime

o CTS – Common Type System

o CLS – Common Language Specification

� BCL (FCL) – Base Class Library (Framework Class

Library)

o Tipuri de aplicatii ce pot fi dezvoltate sub aceasta platforma

o Spatii de nume

� Trasaturi principale ale limbajuui C#.

� Tipuri

o Tip Valoare o Tip Referinta

� Metode

o ale instantei o statice

� Modificatori de acces pentru tip.

� Constructori. Constructori statici.

� Clase statice. Metode extinse.

� Proprietati. Delegates. Evenimente.

� Mostenire.

� Polimorfism.

Pag. 52 din 52

Arhitectura Framework .NET

Ioan Asiminoaei email: [email protected]

Probleme propuse:

Observatie:

Problemele se considera complet rezolvate daca se prezinta si codul ce testeaza

implementarile.

1. Implementati polimorfismul folosind clase de baza abstracte

Enunt problema: C1_P1

Trebuie sa construim mai multe clase ce parteajeaza proprietati comune, metode, evenimente,

indexeri; implementarile pot fi diferite pentru fiecare clasa. Aceste clase nu trebuie sa

partajeze numai cod comun dar sa fie si de natura polimorfica, altfel spus codul ce foloseste

un obiect al clasei de baza ar trebui sa fie in stare sa foloseasca un obiect al oricarei clase

derivate din clasa de baza in acelasi mod.

2. Implementati polimorfismul folosind interfete

Enunt problema : C1_P2

Trebuie sa implementati functionalitatea polimorfica pe o multime de clase existente. Aceste

clase sunt deja derivate dintr-o clasa de baza (alta decat Object), si nu puteti adauga

functionalitatea polimorfica folosind clase de baza abstracte sau concrete. In plus trebuie sa

adaugati functionalitate polimorfica la o structura.

Observatie :

Clasele de baza abstracte sau concrete nu pot fi utilizate in acest din urma caz.

Indicatie:

Puteti considera urmatoarele clase (T este un tip generic): public class Comanda<T> : List<T> { // … } public class Client<T> : List<T> { // … }

Doriti sa adaugati posibilitatea de a afisa fiecare din cele doua obiecte in mod polimorfic.

Pentru aceasta creati interfata IPrint ce defineste metoda Print care va fi implementata de

cele doua clase. public interface IPrint { void Print( ); }


Recommended