Sunteți pe pagina 1din 53

IOAN ASIMINOAEI Email: iasimin@infoiasi.

ro

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.

Bibliografie 1. 2. 3. 4. Tom Archer : Inside C# Second Edition Tom Barnaby : Distributed .NET Programming in C# Joseph C. Rattz, Jr. : Language Integrated Query in C# 2008 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 Reflector, ILSpy FxCop ILDASM Microsoft (dezasamblor)

Curs 1 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. Mostenire. Polimorfism.

Componente principale pentru .NET: CLR Common Language Runtime; o CTS Common Type System; 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 de distribuire a aplicatiilor simplificat (nu mai e nevoie de inregistrare in registri, se permit multiple versiuni ale aceleasi biblioteci *.dll) . etc.

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.

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.

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.

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 poate contine un tip?
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 legate de 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 assembly 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() 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.

FCL Framework Class Library


CLR si FCL 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 Contine tipurile de baza folosite de orice aplicatie; 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.
System System.Collections

Tip valoare. Tip referinta


Aceste tipuri reflecta modul cum variabilele sunt alocate si cum functioneaza acestea intern. Toate tipurile se creaza folosind operatorul new. Folosirea operatorului new nu inseamna ca tipurile se aloca in heap. Observatie Tipurile valoare pot fi create si fara a folosi operatorul new.

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. Observatie Toate tipurile create sunt derivate din Object (direct sau indirect).

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

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.
// 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 metoda Main (ce constituie entry point pentru aplicatie) scriem urmatorul cod pentru testare:
class Program { static void Main(string[] args) { Info info = new Info(); info.PrintHostName();

// Tip valoare creat cu operatorul new InfoStructure infoStr = new InfoStructure(info, Environment.SystemDirectory); infoStr.PrintInfoStructure(); // sau InfoStructure creat fara a folosi operatorul new InfoStructure infos; infos.info = new Info(); infos.SystemDirectory = Environment.SystemDirectory; infos.an = 2013; infos.PrintInfoStructure(); Console.ReadLine(); } }

Tipuri referinta : 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. 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.

Clasa Object - MSDN


#region Assembly mscorlib.dll, v2.0.50727 // C:\Windows\Microsoft.NET\Framework\v2.0.50727\mscorlib.dll #endregion using System.Runtime.ConstrainedExecution; using System.Runtime.InteropServices; namespace System { // Summary: // Supports all classes in the .NET Framework class hierarchy and provides low-level services to derived classes. This is the ultimate base class of all classes in the .NET Framework; it is the root of the type hierarchy. [Serializable] [ComVisible(true)] [ClassInterface(ClassInterfaceType.AutoDual)] public class Object { // Summary: // Initializes a new instance of the System.Object class.

[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] public Object(); // Summary: // Determines whether the specified System.Object is equal to // the current System.Object. // // Parameters: // obj: // The System.Object to compare with the current System.Object. // // Returns: // true if the specified System.Object is equal to the current // System.Object; // otherwise, false. // // Exceptions: // System.NullReferenceException: // The obj parameter is null. public virtual bool Equals(object obj); // // Summary: // Determines whether the specified System.Object instances are // considered equal. // // Parameters: // objA: // The first System.Object to compare. // // objB: // The second System.Object to compare. public static bool Equals(object objA, object objB); // // Summary: // Serves as a hash function for a particular type. // // Returns: // A hash code for the current System.Object. public virtual int GetHashCode(); // // Summary: // Gets the System.Type of the current instance. // // Returns: // The System.Type instance that represents the exact runtime // type of the current instance. public Type GetType(); // // Summary: // Creates a shallow copy of the current System.Object. // // Returns: // A shallow copy of the current System.Object. protected object MemberwiseClone(); // // Summary:

// Determines whether the specified System.Object instances are // the same instance. // // Parameters: // objA: // The first System.Object to compare. // // objB: // The second System.Object to compare. // // Returns: // true if objA is the same instance as objB or if both are // null references; // otherwise, false. [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] public static bool ReferenceEquals(object objA, object objB); // // Summary: // Returns a System.String that represents the current // System.Object. // // Returns: // A System.String that represents the current System.Object. public virtual string ToString(); } }

Tipuri din CTS


Tipul class in C# O clasa este un tip definit de utilizator. Clasa contine date membru si metode ce opereaza cu acestea (ctor, proprietati, metode, evenimente, etc.). Instanta unei clase se numeste obiect. Exemplu
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); } }

Instantierea clasei (crearea obiectului) se face folosind operatorul new. Operatorul new poate fi folosit si pentru tipul valoare. Crearea obiectului poate fi facuta astfel:
Persoana p = new Persoana(X, 12);

sau
Persoana p; // nu se creaza obiectul. p are valoarea null. p = new Persoana(X, 12);

Observatie 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 ce initializeaza aceeasi variabila de doua ori (FxCop semnaleaza acest lucru)
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. 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 public protected private Descriere Membrul este accesibil din afara definitiei clasei si a ierarhiei claselor derivate. Membrul nu este vizibil in afara clasei si poate fi accesat numai de clasele derivate. Membrul nu este vizibil in afara clasei si nici in clasele derivate. 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. Accesul este limitat la assembly-ul curent sau la tipurile derivate din clasa continuta.

internal

protected internal *

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 class sealed ClasaFinala { ... } } namespace InfoNested { // este internal class Persoana { // clasa imbricata (nested class in engleza) private class Copil { ... } } 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 Permite modificarea accesibilitatii implicita enum public private public class protected (aici class internal apare ca data membru in alta private clasa) protected internal interface public struct private public internal private

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

Constructori. Inlantuire ctor. Cuvantul cheie this.


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 doi parametri in acest caz public Perosna(int varsta, string nume) { this.varsta = varsta; this.nume = nume; }

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 ? Raspuns: !!! Raspunsul il gasim in urmatorul cod:
public class InfoStatic {

// tip referinta clasa Info creata anterior in acest curs 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();

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. Rezolvarea consta in a folosi o metoda statica in lista de initializare a ctorului. Exemplu
class Baza { protected Baza(int i) { } }; class Derivata : Baza { int i; // Eroare!!! public Derivata() : base(i) { } };

Ctor 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. Ex.
class Bicicleta { public string model; public static int nRoti; // nu are modificatori de acces si nici parametri static Bicicleta () { nRoti = 2; } public Bicicleta() { model = necunoscut ; } }

Clase statice. Clase sealed. 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. 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 pot fi utilizate in procesul de derivare si ca atare nu poate fi extinsa). Aceasta tehnica adauga noi metode pentru un tip in contextul aplicatiei curente. Sa analizam exemplul de mai jos. Se observa ca metodele extinse sunt declarate ca fiind statice si au ca prim parametru tipul pe care il extind si se definesc in cadrul unei clase statice. Observatie Metodele extinse exista numai in assembly in care au fost definite.
using System;

using using using using

System.Collections.Generic; System.Linq; System.Text; System.Reflection;

namespace ExtensionMethod { /// <summary> /// Metode extinse pentru tipul System.Int32 /// Clasa trebuie sa fie statica /// Metoda trebuie sa fie statica /// 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. // Atentie la cati parametri se furnizeaza in // momentul apelului. 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); // 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 appel fara parametri int ns = n.InversareIntreg(); Console.WriteLine("Intreg initial = {0}, si inversat = {1}",n, ns); // Apel metoda extinsa ce aduna doua numere intregi // Appel cu un parametru. 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.

Metode
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 instantei 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. 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 ?

Din nou despre constructori


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.
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) { 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 ... } }

CTS Common Type System


Tipul structura din CTS - 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.

Tipul enumerare din CTS - 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 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) ;

Delegate 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, 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 System.SByte System.Int16 System.Int32 System.Int64 System.UInt16 System.UInt32 System.UInt64 System.Single System.Double System.Object System.Char System.String System.Decimal System.Boolean

Byte SByte Short Integer Long UShort UInteger ULong Single Double Object Char String Decimal Boolean

byte sbyte short int long ushort uint ulong float double object char string decimal bool

unsigned char signed char short int or long __int64 unsigned short unsigned int or unsigned long unsigned __int64 Float Double Object^ wchar_t String^ Decimal Bool

Exemplu complet de definire a unui tip. Veti face acest exemplu la laborator.
using using using using System; System.Collections.Generic; System.Linq; System.Text;

namespace C1_2012 { /// <summary> /// Exemplu de definre a unei clase /// </summary> public class Info { // ctor public Info() { } // Date membru private. Vor fi accesate prin proprietati. private int numar; private string nume; // folosit pentru a defini indexer int[] tablouInt = new int[20]; // Date membru publice /// <summary> /// Descriere pentru data membru x. Acest text va fi afisat /// de Intellisense. /// </summary> public float x; // Date membru statice public static decimal Media; // Proprietati public int Numar { get { return numar; } set { numar = value; } } public string Nume { get { return nume; } set { if (((string)value).Length >= 3) nume = value; } }

// Proprietati automate sunt numai R/W public string ComputerName { get; set; } public int An { get; set; } // indexer public int this[int i] { get { if (i < 20 && i >= 0) return tablouInt[i]; else throw new IndexOutOfRangeException(); } set { if (i < 20 && i >= 0) tablouInt[i] = value; else throw new IndexOutOfRangeException(); } } // Event // EventHandler este un delagate pentru evenimente ce nu au date. public event EventHandler EventInfo; // Metoda ce lanseaza evenimentul public void OnInfo() { if (EventInfo != null) EventInfo(this, null); } // Event cu delegate propriu public delegate void Feedback(object source, int n); public event Feedback EventFeedback; public void OnEventFeedback(object source, int n) { if (EventFeedback != null) EventFeedback(source, n); } // Metoda a instantei public int CalculInt(int x) { OnInfo(); return x + 1; } // Metoda statica /// <summary> /// Acest text va fi afisat de Intellisense /// </summary> /// <param name="d"></param> /// <returns></returns> public static double CalculDouble(double d)

{ return d / 2.0; } // Supraincarcare operatori // Operatorul == se implementeaza impreuna cu operatorul != public static bool operator ==(Info i1, Info i2) { if (!i1.Equals(i2)) return false; return true; } public static bool operator !=(Info i1, Info i2) { return !(i1 == i2); } } }

Codul (partial) pentru testare este :


using using using using System; System.Collections.Generic; System.Linq; System.Text;

namespace C1_2012 { class Program { static void Main(string[] args) { // creare obiect Info info = new Info(); // atasare metoda pentru evenimentul EventInfo info.EventInfo += new EventHandler(info_EventInfo); // apel metoda a instantei info.OnInfo(); int x = info.CalculInt(2); // folosire prorpietati info.An = 2012; // set info.ComputerName = Environment.MachineName; //set int an = info.An; // get // Folosire indexer info[0] = 2; Console.WriteLine("Indexer {0}", info[0]); // apel metoda statica double d = Info.CalculDouble(20.0); // Test operator == si != TestOperatorEgalDiferit(); }

// Metoda pentru event EventInfo static void info_EventInfo(object sender, EventArgs e) { Console.WriteLine("EventInfo ... object = {0}", sender.ToString()); //throw new NotImplementedException(); } private static void TestOperatorEgalDiferit() { Console.WriteLine("\nTest operator == \n"); Info i1 = new Info(); Info i2 = new Info(); Info i11 = i1; if (i1 == i2) Console.WriteLine("i1 si i2 sunt aceleasi obiecte"); else Console.WriteLine("i1 diferit de i2"); if (i1 == i11) Console.WriteLine("i1 si i11 sunt aceleasi obiecte"); else Console.WriteLine("i1 diferit de i11"); Console.WriteLine("\nTest operator !=\n"); if (i1 != i2) Console.WriteLine("i1 diferit de i2"); else Console.WriteLine("i1 si i2 sunt aceleasi obiecte"); // i1 si i11 sunt aceleasi obiecte if (i1 != i11) Console.WriteLine("i1 si i11 nu sunt aceleasi obiecte"); else Console.WriteLine("i1 si i11 sunt aceleasi obiecte..."); } } }

Metode cu si fara parametri


Problemele importante sunt cele legate de modul cum putem declara argumentele unei metode, cum se transfera aceste argumente in cazul unui apel al metodei si daca modificarile unui parametru in corpul metodei sunt vizibile sau nu apelantului. In mod normal parametrii unei metode pot fi transferati prin valoare sau referinta. Trebuie sa avem in vedere faptul ca parametrul poate fi de tip valoare sau referinta si poate fi transmis prin valoare sau prin referinta. De analizat si ref /out ca modificatori ai parametrilor unei metode (sunt descrisi mai jos in acest curs). (*) Se disting urmatoarele situatii : Parametrul de tip valoare transferat prin valoare. Parametrul de tip valoare transferat prin referinta (vezi ref si out din acest curs). Parametrul de tip referinta transferat prin valoare. Parametrul de tip referinta transferat prin referinta (vezi ref si out din acest curs). 1. 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. Observatie Modificarea obiectului inseamna sa obtinem un alt obiect (obiect nou) alocat in heap. Modificarea starii unui obiect inseamna sa modific anumite proprietati, date membru al obiectului dat (in heap este acelasi obiect ca cel initial). Intrebare : Se poate modifica obiectul cand acesta este transmis ca parametru al unei functii? Raspunsul se va baza pe situatiile descrise la (*). vezi ex C1_2009 din d:\exenet De comentat liniile ce contin apel prin referinta
using using using using System; System.Collections.Generic; System.Linq; 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(); 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?

2. Pasarea unui tip referinta prin referinta ref / out vezi ex C1_2009 din d:\exenet
using using using using System; System.Collections.Generic; System.Linq; 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); } } // 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); } } }

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 Unde este tipul alocat? Cum este reprezentata variabila? Care este tipul de baza ? Poate acest tip sa fie baza pentru alte tipuri ? Care e tipul implicit pentru pasarea parametrilor? Tip valoare Pe stiva Copii locale
System.ValueType

Nu Valoare. Se trimite o copie.

Tip referinta In managed heap. Puncteaza la memoria alocata instantei Derivat din orice ce nu e ValueType sau sealed. Da, daca nu e sealed. Referinta.

Poate acest tip sa suprascrie (override) metoda System.Object.Finalize()? Pot defini ctori pt acest tip ?

Cand sunt distruse aceste variabile ?

Nu. Tipurile valoare nu fac obiectul procesului de garbage collection, sunt alocate pe stiva. Da. Numai ctor cu parametru, ctor implicit este rezervat. Cand sunt in afara blocului unde au fost definite.

Da. Indirect prin destructor.

DA!

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) 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.

ref ca parametrii 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; 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 parametrii 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; } } 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); } }

Boxing si Unboxing : consumatoare de timp


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 // nVarsta este convertit la refVarsta object refVarsta = nVarsta; // 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:
int nVarsta = 22; // tip valoare. // (boxed) refVarsta puncteaza la nVarsta object refVarsta = nVarsta; // (Unboxed) inapoi la int. int nAlt = (int)refVarsta; // 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 managed Main(string[] args) cil

{ .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 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 mostenirii 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 privat. 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 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(); } }

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() { 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


Exemplu (Troelsen):
// Clasa de baza abstracta abstract class 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() {} 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"); // Make an array of Shape-compatible objects. Shape[] myShapes = { new Hexagon(), new Circle(), new Hexagon("H1"), new Circle("C"), new Hexagon("H2")}; // Loop over each item and interact with the // polymorphic interface. 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

Proprietati
Proprietatile nu permit accesul direct la membri. Sunt furnizati doi accesori (set, get) ce lucreaza direct cu data membru. Scopul este de a pastra date cit mai corecte in obiectul instantiat. 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. modificatorul static poate fi utilizat pentru proprietate. Modificatorii de acces trebuiesc specificati la nivel de proprietate. Proprietati automate : 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.

Suprascrierea proprietatilor mostenite Trebuie specificata proprietatea 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; } 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).
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; } }

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; } } }

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. Mostenire. :base Polimorfism.

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( ); }

S-ar putea să vă placă și