45
Atribute si interfete Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014 Ioan Asiminoaei 1 Curs 3 Introspectie metadata – Reflection. Atribute. Interfete. Cuprins Introspectie metadata - Reflection o Clasa Type o Exemple de utilizare Atribute preconstruite; definite de dezvoltator (custom); o Definirea atributelor o Interogarea atributelor o Atribute la nivel de clasa, metode, proprietati, campuri, etc. o Clasa AttributeUsage o Parametri pozitionali si parametri cu nume o Atribute preconstruite : DllImport, CLSCompliant, STAThread, Serializable, etc. Interfete o Clasificare preconstruite custom o Declararea interfetelor o Evenimente, Proprietati si Metode pentru Interfete o Interfete multiple o Interfete si ierarhii de clase o Interfete si Generice o Derivarea dintr-o interfata generica o Implementarea explicita a interfetelor o Interfete generice ca operatori o Constrangeri la nivel de interfata o Interfetele IEnumerable si IEnumerator

C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

  • Upload
    others

  • View
    7

  • Download
    0

Embed Size (px)

Citation preview

Page 1: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

1

Curs 3

Introspectie metadata – Reflection. Atribute. Interfete.

Cuprins

� Introspectie metadata - Reflection o Clasa Type

o Exemple de utilizare

� Atribute � preconstruite;

� definite de dezvoltator (custom);

o Definirea atributelor

o Interogarea atributelor

o Atribute la nivel de clasa, metode, proprietati, campuri, etc.

o Clasa AttributeUsage

o Parametri pozitionali si parametri cu nume

o Atribute preconstruite : DllImport, CLSCompliant,

STAThread, Serializable, etc.

� Interfete o Clasificare

� preconstruite

� custom

o Declararea interfetelor

o Evenimente, Proprietati si Metode pentru Interfete

o Interfete multiple

o Interfete si ierarhii de clase

o Interfete si Generice

o Derivarea dintr-o interfata generica

o Implementarea explicita a interfetelor

o Interfete generice ca operatori

o Constrangeri la nivel de interfata

o Interfetele IEnumerable si IEnumerator

Page 2: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

2

Introspectie metadata - Reflection

Spatiul de nume: System.Reflection

Introspectia metadatei (reflection) este procesul prin care un program poate observa si

modifica structura si comportarea sa.

Spatiul de nume System.Reflection contine tipuri ce regasesc informatia despre

assemblies, module, membri, parametri si alte entitati din codul managed prin examinarea

metadatei. Cateva clase din acest spatiu de nume sunt enumerate mai jos. Lista completa in

MSDN.

Class Description

Assembly Represents an assembly, which is a reusable, versionable, and self-describing building block of a common language runtime application.

AssemblyName Describes an assembly's unique identity in full.

ConstructorInfo Discovers the attributes of a class constructor and provides access to constructor metadata.

CustomAttributeData Provides access to custom attribute data for assemblies, modules, types, members and parameters that are loaded into the reflection-only context.

EventInfo Discovers the attributes of an event and provides access to event metadata.

FieldInfo Discovers the attributes of a field and provides access to field metadata.

LocalVariableInfo Discovers the attributes of a local variable and provides access to local variable metadata.

MemberInfo Obtains information about the attributes of a member and provides access to member metadata.

MethodBase Provides information about methods and constructors.

MethodInfo Discovers the attributes of a method and provides access to method metadata.

Module Performs reflection on a module.

Page 3: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

3

ParameterInfo Discovers the attributes of a parameter and provides access to parameter metadata.

PropertyInfo Discovers the attributes of a property and provides access to property metadata.

Clasa Type

Type constituie baza pentru System.Reflection si asigura modalitatea de a accesa

metadata. Obtinerea informatiilor despre ctor, metode, campuri, proprietati si evenimente se

realizeaza prin folosirea membrilor acestei clase.

Un obiect Type reprezinta un tip unic.

Operatorul typeof returneaza un obiect Type.

O referinta la un obiect Type asociat cu un tip poate fi obtinuta in urmatoarele moduri:

• Metoda Object.GetType returneaza un obiect Type ce reprezinta tipul unei instante.

• Metoda statica GetType returneaza un obiect Type ce reprezinta un tip specificat prin numele sau complet.

• Metodele Module.GetTypes, Module.GetType, si Module.FindTypes returneaza obiecte Type ce reprezinta tipurile definite intr-un modul.

• Obiectul System.Reflection.Assembly contine metode pentru a regasi clasele

definte intr-un assembly.

A se consulta declaratia completa in MSDN.

Cand realizam introspectia metadatei trebuie sa avem in vedere urmatoarea ierarhie:

� assembly curent face referire la alti assemblies;

� un assembly este constituit din module;

� un modul contine tipuri;

� un tip contine metode, membri, proprietati, evenimente, etc.

Ierarhia descrisa mai sus este explicata in urmatorul cod.

Assembly curent se obtine cu metoda :

Assembly a = System.Reflection.Assembly.GetExecutingAssembly();

Colectia de assemblies referiti de assembly curent se obtine cu metoda:

a.GetReferencedAssemblies()

Colectia de assemblies incarcati in AppDomain curent se obtine cu metoda :

AppDomain.CurrentDomain.GetAssemblies()

Page 4: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

4

Modulele continute de un assembly se obtin cu metoda :

GetModules() apelata pe un obiect de tip Assembly.

Tipurile exportate de un assembly se obtin cu metoda :

GetExportedTypes() apelata pe un obiect de tip Assembly.

Membrii unui tip se obtin cu metoda :

GetMembers() apelata pe un obiect Type. Metoda returneaza o colectie de tip

MemberInfo. Proprietatea MemberType din MemberInfo furnizeaza informatii despre tipul

membrului : metoda, proprietate, etc.

Exemplu din MSDN (de analizat acest cod)

using System; using System.Reflection; class Module1 {

public static void Main() { // This variable holds the amount of indenting that // should be used when displaying each line of information. Int32 indent = 0; // Display information about the EXE assembly. Assembly a = System.Reflection.Assembly.GetExecutingAssembly(); Display(indent, "Assembly identity={0}", a.FullName); Display(indent+1, "Codebase={0}", a.CodeBase); // Display the set of assemblies our assemblies reference. Display(indent, "Referenced assemblies:"); foreach (AssemblyName an in a.GetReferencedAssemblies() ) { Display(indent + 1, "Name={0}, Version={1}, Culture={2}, PublicKey token={3}", an.Name, an.Version, an.CultureInfo.Name, BitConverter.ToString (an.GetPublicKeyToken()))); } Display(indent, ""); // Display information about each assembly // loading into this AppDomain. foreach (Assembly b in AppDomain.CurrentDomain.GetAssemblies()) { Display(indent, "Assembly: {0}", b); // Display information about each module // of this assembly. // Un assembly este constituit din module foreach ( Module m in b.GetModules(true) ) { Display(indent+1, "Module: {0}", m.Name); }

Page 5: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

5

// Display information about each type // exported from this assembly. indent += 1; foreach ( Type t in b.GetExportedTypes() ) { Display(0, ""); Display(indent, "Type: {0}", t); // For each type, show its members & their // custom attributes. indent += 1; foreach (MemberInfo mi in t.GetMembers() ) { Display(indent, "Member: {0}", mi.Name); DisplayAttributes(indent, mi); // If the member is a method, // display information about its parameters. if (mi.MemberType==MemberTypes.Method) { foreach ( ParameterInfo pi in ((MethodInfo) mi).GetParameters() ) { Display(indent+1, "Parameter: Type={0}, Name={1}", pi.ParameterType, pi.Name); } } // If the member is a property, display information // about the property's accessor methods. if (mi.MemberType==MemberTypes.Property) { foreach ( MethodInfo am in ((PropertyInfo) mi).GetAccessors() ) { Display(indent+1, "Accessor method: {0}", am); } } } indent -= 1; } indent -= 1; } } // Displays the custom attributes applied // to the specified member. public static void DisplayAttributes(Int32 indent, MemberInfo mi) { // Get the set of custom attributes; // if none exist, just return. object[] attrs = mi.GetCustomAttributes(false); if (attrs.Length==0) {return;} // Display the custom attributes applied to this member. Display(indent+1, "Attributes:");

Page 6: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

6

foreach ( object o in attrs ) { Display(indent+2, "{0}", o.ToString()); } } // Display a formatted string indented by the specified amount. public static void Display(Int32 indent, string format, params object[] param) { Console.Write(new string(' ', indent*2)); Console.WriteLine(format, param); } }

Alte exemple.

// creare instanta a clasei DateTime DateTime dateTime = (DateTime)Activator.CreateInstance(typeof(DateTime)); // creare instanta a clasei DateTime, folosind constructor cu // parametri (year, month, day) DateTime dateTime = (DateTime)Activator.CreateInstance(typeof(DateTime), new object[] { 2014, 10, 13 });

Creaza instanta din assembly incarcat in mod dinamic

Din urmatorul cod se creaza un assembly numit Test.dll.

namespace Test { public class Calculator { public Calculator() { ... } private double _number; public double Number { get { ... } set { ... } } public void Clear() { ... } private void DoClear() { ... } public double Add(double number) { ... } public static double Pi { ... } public static double GetPi() { ... } } }

Exemple cu acest assembly pentru introspectie metadata.

// incarcare dinamica assembly din fisierul Test.dll Assembly testAssembly = Assembly.LoadFile(@"c:\Test.dll"); // Obtinerea tipului pentru clasa Calculator din assembly // incarcat in mod dinamic Type calcType = testAssembly.GetType("Test.Calculator"); // creare instanta a clasei Calculator object calcInstance = Activator.CreateInstance(calcType);

Page 7: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

7

// obtinere informatii despre proprietatea: public double Number PropertyInfo numberPropertyInfo = calcType.GetProperty("Number"); // obtinerea valorii proprietatii: public double Number double value = (double)numberPropertyInfo.GetValue(calcInstance, null); // atribuirea unei noi valori pentru proprietatea: // public double Number (calcInstance, 10.0, null); // obtinere informatii despre proprietatea statica Pi: // public static double Pi PropertyInfo piPropertyInfo = calcType.GetProperty("Pi"); // obtinerea valorii proprietatii : public static double Pi double piValue = (double)piPropertyInfo.GetValue(null, null);

// apelarea metodei de instanta Clear(): public void Clear() calcType.InvokeMember("Clear",

BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public, null, calcInstance, null);

// apelare metoda privata a instantei: private void DoClear() calcType.InvokeMember("DoClear",

BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.NonPublic, null, calcInstance, null);

// apelare metoda a instantei: public double Add(double number) double value = (double)calcType.InvokeMember("Add",

BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public,null, calcInstance, new object[] { 20.0 });

// apelare metoda statica publica: public static double GetPi() double piValue = (double)calcType.InvokeMember("GetPi",

BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.Public, null, null, null);

// obtinere valoare camp private: private double _number double value = (double)calcType.InvokeMember("_number",

BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic, null, calcInstance, null);

Page 8: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

8

Atribute

Ideea de baza: autodescrierea componentelor. Compilatorul si CLR pot citi aceste informatii.

De asemenea dezvoltatorul componentei are toate informatiile despre componenta intr-un

singur loc.

Atributele ne furnizeaza informatiile asociate cu tipul definit in C#. Important e ca aceasta

informatie poate fi definita de dezvoltatorul tipului si nu este statica, legata de limbaj.

Aceasta asociere de informatie urmeaza aceleasi principii folosite in dezvoltarea XML.

Putem crea un atribut bazat pe orice informatie dorim.

Exista un mecanism standard pentru definirea atributelor si pentru interogarile membrului sau

tipului la runtime.

Toate atributele, preconstruite sau definite de utilizator, sunt derivate direct sau indirect din System.Attribute.

Atributele mostenesc o anumita comportare implicita:

• atributul poate fi asociat cu orice element tinta;

• poate fi sau nu poate fi mostenit de un element derivat;

• instante multiple pot fi permise sau nu pe acelasi element tinta.

Aceste comportari sunt specificate in AttributeUsageAttribute.

Un atribut este o adnotare ce poate fi plasata pe un element al codului sursa si este folosit

pentru a memora in momentul compilarii, informatii specifice tipului. Aceasta informatie este

memorata in metadata si poate fi accesata fie in timpul executiei aplicatiei, prin procesul

cunoscut sub numele de reflection (introspectie metadata) sau cand un alt utilitar citeste

metadata. Atributele pot schimba comportarea aplicatiei in momentul executiei.

Putem crea propriile noastre clase de atribute, mostenite din Attribute. Definitia unei asemenea clase include numele atributului, comportarea sa implicita si alte informatii.

Exemplu

Urmatorul exemplu creaza si atribuie atribute definite de utilizator unei anumite clase.

Atributul contine numele programatorului si versiunea clasei.

using System;

[AttributeUsage(AttributeTargets.Class|AttributeTargets.Struct, AllowMultiple=true)] public class Autor : Attribute {

string autorName; public double Version; public Autor(string name) { autorName = name; Version = 1.0; }

Page 9: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

9

public string GetName() { return autorName; } } [Autor("Eminescu")] class FirstClass {

/*...*/

}

class SecondClass // nu are atributul Autor {

/*...*/

}

[Autor("Calinescu"), Autor("Creanga", Version=1.1)] class ThirdClass {

/*...*/

}

// Cod pentru testare class AutorInfo { public static void Main() { PrintAutorInfo(typeof(FirstClass)); PrintAutorInfo(typeof(SecondClass)); PrintAutorInfo(typeof(ThirdClass)); } public static void PrintAutorInfo(Type type) { Console.WriteLine("Autor information for {0}", type); Attribute[] attributeArray = Attribute.GetCustomAttributes(type); foreach(Attribute attrib in attributeArray) { if (attrib is Autor) { Autor autor = (Autor)attrib; Console.WriteLine(" {0}, version {1:f}", autor.GetName(), autor.Version); } } Console.WriteLine(); } }

Rezultatul este: Autor information for FirstClass

Eminescu, version 1.00

Page 10: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

10

Autor information for SecondClass

Autor information for ThirdClass

Calinescu, version 1.00

Creanga, version 1.10

Definirea atributelor

Un atribut este in momentul de fata o clasa derivata din System.Attribute. [AttributeUsage(AttributeTargets.Class| AttributeTargets.Struct, AllowMultiple=true)] public class Autor : Attribute { // cod }

Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea

folosita la instantierea unei clase.

Interogarea atributelor

Pentru a interoga un tip sau un membru despre atributele atasate acestuia, trebuie sa utilizam

introspectia metadatei (reflection). Vezi exemplul anterior.

Reflection ne permite de a determina in mod dinamic in momentul executiei, caracteristicile

unui tip.

Putem folosi reflection pentru a citi metadata pentru un intreg assembly si a produce o lista a

tuturor claselor, tipurilor si metodelor definite pentru acel assembly.

Parametrii pozitionali si parametri cu nume

In exemplele anterioare, am examinat atasarea atributelor via constructorul lor.

Vom examina cateva probleme legate de constructorul atributelor.

La inceputul cursului am folosit urmatoarea declaratie :

[Autor("Calinescu"), Autor("Creanga", Version=1.1)] class ThirdClass {

/*...*/

}

Observatie

In momentul cand are loc introspectia metatdatei pentru atribute custom, se vor crea

urmatoarele instante ale clasei Autor:

Autor autor1 = new Autor("Calinescu"); Autor autor2 = new Autor("Creanga"); autor2.Version = 1.1;

Ctor Autor are ca parametru un string. Version (data membru a clasei) este declarat public

in clasa si este setat folosind numele acestuia.

Page 11: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

11

Putem folosi valori implicite folosind parametri pozitionali si parametri cu nume.

Parametrii pozitionali sunt parametrii din constructorul atributului.

Acestia trebuiesc specificati de fiecare data cand folosim atributul.

Parametrii cu nume nu sunt definiti in constructorul atributului, acestia sunt campuri

publice nestatice si proprietati (am folosit in primul exemplu din acest curs).

Parametrii cu nume permit clientului sa seteze atributul campurilor si proprietatilor cand

atributul este instantiat, fara a avea nevoie sa cream un constructor pentru fiecare combinatie

posibila de campuri si proprietati.

Fiecare ctor public poate defini un sir de parametri pozitionali.

Utilizatorul poate referentia ca parametru cu nume orice camp care nu este readonly, static

sau const sau orice proprietate ce include un accesor set – setter – care nu este statica.

Greseli cu parametrii cu nume

Cand folosim parametri cu nume, trebuie sa specificam parametri pozitionali mai intai, si apoi

parametri cu nume, acestia din urma in orice ordine dorim.

Compilatorul incearca sa rezolve mai intai parametrii cu nume si apoi ce ramane, incearca sa

gaseasca un ctor cu signatura potrivita.

Parametrii cu nume pot fi orice camp sau proprietate accesibila publica – incluzind o

metoda setter – care nu este statica sau constanta.

Tipurile parametrilor pozitionali si ai celor cu nume pentru o clasa atribut sunt limitate la

tipurile parametrului atributului, si care poate fi:

• bool, byte, char, double, float, int, long, short, string

• System.Type

• object

• tipul enum cu conditia ca oriunde se gaseste definit sa fie accesibil in mod public.

• un tablou unidimensional ce are ca tipuri de elemente unul din cele de mai sus.

Atributul AttributeUsage

AttributeUsage defineste modul cum sunt folosite atributele.

Sintaxa este:

[AttributeUsage( validon, AllowMultiple = allowmultiple, Inherited = inherited )]

Observam un parametru pozitional, validon, si doi cu nume, AllowMultiple si Inherited.

Page 12: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

12

Parametrul validon

Parametrul validon este de tipul AttributeTargets, si permite sa specificam tipurile pe

care atributul poate fi atasat. Valorile posibile sunt date in enumerarea AttributeTargets.

public enum AttributeTargets { Assembly = 0x0001, Module = 0x0002, Class = 0x0004, Struct = 0x0008, Enum = 0x0010, Constructor = 0x0020, Method = 0x0040, Property = 0x0080, Field = 0x0100, Event = 0x0200, Interface = 0x0400, Parameter = 0x0800, Delegate = 0x1000, All = Assembly │ Module │ Class │ Struct │ Enum │ Constructor │ Method │ Property │ Field │ Event │ Interface │ Parameter │ Delegate, ClassMembers = Class │ Struct │ Enum │ Constructor │ Method │ Property │ Field │ Event │ Delegate │ Interface, }

Implicit este AttributeTargets.All.

Membrii din enumerare pot fi folositi cu operatorul OR (|) ca in exemplul:

[AttributeUsage(AttributeTargets.Field │ AttributeTargets.Property)]

Folosim acest parametru cand vrem sa controlam exact modul de utilizare al unui atribut.

Pentru a fi siguri ca atributele pe care le-am scris sunt folosite pentru tipurile pentru care au

fost proiectate, putem indica in definitia atributului pentru ce este proiectat (elementul tinta pe

care se aplica):

Atribut ce poate fi aplicat tipului class.

[AttributeUsage(AttributeTargets.Class)] public class RemoteObjectAttribute : Attribute {}

Atribut ce poate fi aplicat metodelor. [AttributeUsage(AttributeTargets.Method)] public class AtributTranzactie : Attribute {}

Atribut ce poate fi aplicat campurilor. [AttributeUsage(AttributeTargets.Field)] public class FieldAttribute : Attribute {}

Page 13: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

13

[RemoteObject(RemoteServers.COSETTE)] class SomeClass { [AtributTranzactie] public void Foo() {} [FieldAttribute("Bar", An = Informatica.AN_4)] public int Bar; }

Parametrul AllowMultiple

Ne permite sa definim un atribut ce poate fi folosit o singura data sau de mai multe ori pe

acelasi element tinta.

Implicit toate atributele sunt folosite ca single, deci nu putem declara de doua ori acelasi

atribut pentru acelasi element tinta. Vezi exemplul:

public class SomethingAttribute : Attribute { public SomethingAttribute(String str){} } // Error: "Duplicate single-use Something attribute" [Something("abc")] [Something("def")] class MyClass{}

Parametru AllowMultiple rezolva aceasta problema.

AllowMultiple = true – atribut multiplicat;

= false – atribut single.

Vezi si exemplul:

[AttributeUsage(AttributeTargets.All, AllowMultiple=true)] public class SomethingAttribute : Attribute { public SomethingAttribute(String str){} } [Something("abc")] [Something("def")] class MyClass{}

Parametrul Inherited

Acest parametru ne spune daca atributul poate fi mostenit sau nu. Valoarea implicita este

false.

Parametrii AllowMultiple si Inherited trebuiesc considerati impreuna. Vezi tabelul de

mai jos.

Inherited AllowMultiple Result

true false Atributul derivat suprascrie atributul

de baza.

true true Atributele derivate si cele din clasa de

Page 14: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

14

Inherited AllowMultiple Result

baza sunt combinate.

Exemplu:

using System; using System.Reflection; namespace AttribInheritance { [AttributeUsage( AttributeTargets.All, // AllowMultiple=true, AllowMultiple=false, Inherited=true )] public class SomethingAttribute : Attribute { private string name; public string Name { get { return name; } set { name = value; } } public SomethingAttribute(string str) { this.name = str; } } [Something("abc")] class MyClass { } [Something("def")] class Another : MyClass { } class Test { [STAThread] static void Main(string[] args) { Type type = Type.GetType("AttribInheritance.Another"); foreach (Attribute attr in type.GetCustomAttributes(true)) // type.GetCustomAttributes(false)) { SomethingAttribute sa = attr as SomethingAttribute; if (null != sa) { Console.WriteLine("Custom Attribute: {0}", sa.Name); } } } }

Page 15: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

15

}

Cu AllowMultiple = false, rezultatul este: Custom Attribute: def

iar cu AllowMultiple = true, rezultatul devine:

Custom Attribute: def

Custom Attribute: abc

Identificatorii atributului

Deoarece o metoda returneaza un tip si are parametri (cazul general), un atribut aplicat unei

metode poate crea confuzie in sensul ca nu stim daca se aplica pentru valoarea returnata sau

pentru parametrii metodei.

Trebuie sa precizam la ce se aplica un atribut: la o metoda sau la valoarea returnata de

metoda.

Din acest punct de vedere urmatorul cod este ambiguu.

class SomeClass { [HRESULT] public long Metoda() { return 0; } }

In COM, HRESULT reprezinta valoarea returnata de metodele din interfata (mai putin

AddRef si Release, acestea returneaza ULONG).

Putem defini atributul HRESULT astfel:

public class HRESULTAttribute : Attribute { public HRESULTAttribute(){} }

Alte ambiguitati sunt date de urmatoarele situatii:

1. Metode vs. tip returnat;

2. Evenimente vs. camp vs. proprietate ;

3. Delegate vs. tip returnat;

4. Proprietate vs. accessor vs. valoare returnata din getter vs. valoarea parametrului

unei metode set;

Pentru a fixa lucrurile, putem folosi identificatorul atributului, listat mai jos:

• assembly • module • type • method • property • event

Page 16: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

16

• field • param • return

Sintaxa este:

identificator:atribut

Atentie la : Vezi si exemplul de mai jos.

class SomeClass { [HRESULT] public long Foo() { return 0; } [return: HRESULT] public long Bar() { return 0; } }

Alte exemple:

class SomeClass { [method: HRESULT] public long Foo() { return 0; } [return: HRESULT] public long Bar() { return 0; } [property: HRESULT] public long Goo { get { return 12345; } } }

Vom folosi reflection pentru a determina identificatorul atributului, ca in exemplul urmator:

static void Main(string[] args) { Type type = Type.GetType("AttribIdentifiers.SomeClass"); foreach (MethodInfo m in type.GetMethods()) { foreach (Attribute a in m.GetCustomAttributes(true)) { if (a is HRESULTAttribute) { Console.WriteLine( "method: {0}, " + "CustomAttributes: {1}", m.Name, a); } } ICustomAttributeProvider icap = m.ReturnTypeCustomAttributes; foreach (Attribute a in icap.GetCustomAttributes(true)) { Console.WriteLine( "method: {0}, "

Page 17: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

17

+ "ReturnTypeCustomAttribs: {1}", m.Name, a); } } foreach (MemberInfo m in type.GetProperties()) { foreach (Attribute a in m.GetCustomAttributes(true)) { Console.WriteLine( "property: {0}, " + "CustomAttributes: {1}", m.Name, a); } } }

Rezultatul este:

method: Foo, CustomAttributes: AttribIdentifiers.HRESULTAttribute

method: Bar, ReturnTypeCustomAttribs:

AttribIdentifiers.HRESULTAttribute

property: Goo, CustomAttributes: AttribIdentifiers.HRESULTAttribute

Atribute predefinite

Cadrul de lucru .NET ofera clase de atribute predefinite, dintre care mai importante sunt:

Predefined .NET

Attribute Valid Targets Description

AttributeUsage Class Specifies the valid usage of another attribute class.

CLSCompliant All Indicates whether a program element is compliant

with the Common Language Specification (CLS).

Conditional Method Indicates that the compiler can ignore any calls to

this method if the associated string is defined.

DllImport Method Specifies the DLL location that contains the

implementation of an external method.

MTAThread Method (Main) Indicates that the default threading model for an

application is multithreaded apartment (MTA).

NonSerialized Field Applies to fields of a class flagged as Serializable;

specifies that these fields won’t be serialized.

Obsolete

All except

Assembly, Module,

Parameter, and

Return

Marks an element obsolete—in other words, it

informs the user that the element will be removed

in future versions of the product.

ParamArray Parameter Allows a single parameter to be implicitly treated

as a params (array) parameter.

Serializable Class, struct, enum,

delegate

Specifies that all public and private fields of this

type can be serialized.

STAThread Method (Main) Indicates that the default threading model for an

application is STA.

StructLayout Class, struct Specifies the nature of the data layout of a class or

struct, such as Auto, Explicit, or Sequential.

ThreadStatic Field (static) Implements thread-local storage (TLS)—in other

Page 18: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

18

Predefined .NET

Attribute Valid Targets Description

words, the given static field isn’t shared across

multiple threads and each thread has its own copy

of the static field.

Page 19: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

19

Atributele DllImport si StructLayout

Codul C# poate apela functii in cod nativ ce se gaseste in biblioteci dinamice (extensia .dll).

Aceasta caracteristica a runtime-ului se numeste platform invoke.

Exemplu

Vom apela functia Win32 API MessageBoxA ce se gaseste in user32.dll. Codul este:

public class Test { [DllImport ("user32.dll")] public static extern int MessageBoxA ( int h, string m, string c, int type); [STAThread] public static void Main(string[] args) { MessageBoxA(0, "Hello World", "nativeDLL", 0); } }

Runtime .NET transmite parametrii din codul C# manged catre codul nativ din DLL.

Sintaxa completa pentru DllImport este:

[DllImport("user32", EntryPoint="MessageBoxA", SetLastError=true, CharSet=CharSet.Ansi, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)] public static extern int MessageBoxA ( int h, string m, string c, int type);

Pentru a transmite structuri din codul managed catre codul unmanaged si invers trebuie sa

folosim atributul StructLayout, ce are ca efect construirea structurii exact ca in declaratia ei initiala (adica secvential). Este obligatoriu acest lucru.

Exemplu pentru apelul functiei GetLocalTime(). [StructLayout(LayoutKind.Sequential)] public class SystemTime { public ushort wYear; public ushort wMonth; public ushort wDayOfWeek; public ushort wDay; public ushort wHour; public ushort wMinute; public ushort wSecond; public ushort wMilliseconds; }

Page 20: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

20

In continuare putem apela functia astfel:

public static void Main(string[] args) { SystemTime st = new SystemTime(); GetLocalTime(st); string s = String.Format("date: {0}-{1}-{2}", st.wMonth, st.wDay, st.wYear); string t = String.Format("time: {0}:{1}:{2}", st.wHour, st.wMinute, st.wSecond); string u = s + ", " + t;

MessageBoxA(0, u, "Now", 0); }

Page 21: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

21

Interfete

Interfetele ne dau posibilitatea de a defini o multime de metode, proprietati, indexeri si

evenimente pe care o clasa le poate implementa. Clasa trebuie sa fie derivata din acea

interfata ceea ce este echivalent cu implementarea in cadrul clasei a metodelor definite in

interfata.

Din punct de vedere conceptual interfetele sunt contracte intre doua parti de cod separate.

Scenariul este urmatorul:

• Se defineste o interfata; interfata defineste o anumita comportare.

• Se defineste o clasa ce implementeaza aceasta interfata, clasa este derivata din

interfata.

• Clientii vor utiliza clasa ce a implementat interfata.

O clasificare a interfetelor ar putea fi :

� interfete din BCL / FCL (IComparer, IDisposable, ICloneable, etc.). � interfete definite de utilizator.

Ne vom indrepta atentia asupra interfetelor definite de catre utilizator.

Utilizarea interfetei

In C#, o interfata este un concept de “prima clasa”, adica o trasatura preconstruita a

limbajului, ce declara un tip referinta si include numai declaratiile metodelor. Proprietatile

sunt metode.

Declararea interfetelor

Interfetele pot contine metode, proprietati, indexeri si evenimente, si nici unul nu este

implementat de interfata insasi.

Exemplu

interface IValidate { bool Validate(); }

Observatie Nu trebuie sa declaram ca metodele sunt pur virtuale (=0).

Interfetele sunt tipuri abstracte si nu pot fi instantiate in mod direct. Pentru a folosi o interfata

trebuie sa convertim (cast) o referinta la interfata la obiectul ce suporta acea interfata.

Exista cast implicit si cast explicit.

Page 22: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

22

Exemplu

interface IFigura { void Draw(); } // Implementare interfata IFigura class Cerc: IFigura { public void Draw() { // cod } }

Cast implicit:

IFigura obj; // IFigura este o interfata obj = new Cerc(); obj.Draw();

Observatie: Eroare la compilare

Daca Cerc nu implementeaza interfata IFigura atunci compilatorul genereaza o eroare.

Controlul sigurantei folosirii tipului are loc la compilare => « early binding ».

Cast explicit :

IFigura obj; // IFigura este o interfata // cod... obj = (IFigura)new Cerc(); obj.Draw();

Observatie: Eroare la executie

La compilare nu mai are loc controlul tipului. Daca tipul Cerc nu implementeaza interfata

IFigura va fi generata o exceptie la executie.

Nu putem folosi cast implicit cand lucram cu clase « factory » non-generice. O clasa “factory”

este o clasa ce construieste un alt obiect. De exemplu tipul Car poate fi construit de un tip numit CarFactory. Avantajul folosirii unui tip ce creaza alt tip este ca numai tipul

« factory » este cuplat la tipurile componentei actuale ce furnizeaza interfetele. Clientul stie

numai aceste interfete. Cand e nevoie de a trece de la un furnizor de servicii la altul trebuie sa

modificam numai « clasele factories » ; clientii nu sunt afectati. Cand folosim class factory ce

returneaza un anumit tip de baza comun, vom folosi cast explicit.

public interface IClassFactory { object GetObject( ); } //… IClassFactory factory; /* cod ce initializeaza class factory */ IFigura obj; obj = (IFigura)factory.GetObject( ); obj.Draw( );

Page 23: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

23

Observatie: Cand folosim generice nu mai avem nevoie de cast:

public interface IClassFactory<T> { T GetObject( ); } IClassFactory<IFigura> factory; /* cod ce initializeaza class factory */ IFigura obj; obj = factory.GetObject( ); obj.Draw( );

Un alt exemplu:

public interface IFigura { void Draw(); void Area(); } public interface IStoreData { void Save(); } public class Cerc : IFigura, IStoreData { public void Draw() {...} public void Area() {...} public void Save() {...} }

//cod pe partea clientului IFigura obj1; IStoreData obj2; obj1 = new Cerc(); obj1.Draw(); obj2 = (IStoreData)obj1; obj2.Save();

Observatie:

Trebuie sa programam defensiv (utilizare as, is, try...catch).

... obj2 = obj1 as IStoreData; // asemanator cu QueryInterface din COM if (obj2 != null)

obj2.Save(); else

{ // tratare eroare }

Page 24: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

24

Operatorul is

Operatorul is – test existenta interfata

Pentru a testa un obiect daca implementeaza o anumita interfata folosim operatorul is.

Operatorul is ne permite sa controlam in momentul executiei daca un tip este compatibil cu

alt tip. Sintaxa este:

expresie is ttip

Practic, is spune ca o anumita clasa suporta o anumita interfata, dar nu ca o si

implementeaza.

Operatorul as

Operatorul as face conversia intre tipurile compatibile si are urmatoarea sintaxa:

obiect = expresie as tip

unde expresie este un tip referinta.

In urma acestei conversii trebuie scris cod de verificare a conversiei, adica daca obiect are o

valoare valida. Daca conversia nu reuseste obiect are valoarea null.

Implementarea interfetelor

Fiecare clasa ce implementeaza o interfata trebuie sa defineasca fiecare membru al interfetei.

Evenimente, Proprietati, Metode, Indexeri pentru Interfete

Vom explica acestea pe baza de exemple.

Interfata IPrint din exemplul de mai jos defineste metode, proprietati, indexeri si

evenimente.

Observatie Pentru a defini evenimentul trebuie sa cream un delegate.

public delegate void NumberChangedEventHandler(int number); public interface IPrint { void Metoda(); // metoda int Proprietate { get; set; } // proprietate int this[int index]{ get; set;} // indexer event NumberChangedEventHandler NumberChanged; // eveniment } public class MyClass : IPrint { public event NumberChangedEventHandler NumberChanged; public void Metoda() {...}

Page 25: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

25

public int Proprietate { get {...} set {...} } public int this[int index] { get {...} set {...} } }

Interfete multiple

� In .NET exista mostenire simpla la nivel de clase si mostenire multipla la nivel de

interfete.

� Cand o clasa este derivata dintr-o alta clasa si mai multe interfete, clasa de baza

trebuie sa fie prima in lantul de derivare.

public interface IPrint {} public interface ISave {} public class Baza {} public class Derivata : Baza, IPrint, ISave {}

Coliziuni de nume.

Scenariu 1

O clasa implementeaza doua interfete, interfete ce contin o metoda cu acelasi nume

si parametri.

Regula generala de evitare a coliziunii de nume este prefixarea numelui metodei cu numele

interfetei, lucru cunoscut sub numele de implementarea explicita a interfetelor.

public interface IPrint { void Metoda(); } public interface ISave { void Metoda(); } public class Cerc : IPrint, ISave { void IPrint.Metoda( ) {...} void ISave.Metoda( ) {...} // alte metode si membri }

Page 26: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

26

Utilizare :

Cerc c = new Cerc() ; ((IPrint)c).Metoda() ; ((ISave)c).Metoda();

Scenariu 2.

Clasa de baza contine o metoda ce are nume identic cu al unei metode din interfata.

Cum implementam metoda in clasa derivata din clasa de baza si din interfata?

Rezolvare: implementare explicita a interfetei si cast la utilizarea metodei.

public class Baza { public void Serialize() { Console.WriteLine("Control.Serialize called"); } } public interface ISave { void Serialize(); } public class Derivata : Baza, ISave { public void ISave.Serialize() {...} }

si cast la utilizare.

Scenariu 3. Clasa derivata din clasa ce implementeaza o interfata, are o metoda cu acelasi nume ca cea

din clasa de baza, nume ce corespunde unei metode din interfata

In exemplul urmator metoda Test() este definita in interfata ITest, in clasa de baza Baza si in clasa derivata Derivata.

Rezolvare: In clasa derivata se va implementa metoda Test() ca fiind o metoda “noua” a clasei

derivate, ascunzand metoda din clasa de baza. interface ITest { void Test(); } // Baza implementeaza ITest. class Baza : ITest { public void Test() { Console.WriteLine("Base.Test (implementare ITest)"); } }

Page 27: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

27

class Derivata : Baza { public new void Test() // ascundere metoda din clasa de baza { Console.WriteLine("Derivata.Test"); }}

Apel: Derivata d = new Derivata(); // apel metoda Test din clasa derivata d.Test(); // apel metoda Test definita in interfata ITest si // implementata in clasa Baza ((ITest)d).Test(); Rezultat executie: Derivata.Test Base.Test (implementare ITest) Observatie:

new si casting-ul din ultima linie de cod rezolva problema in mod corect.

Scenariu 4.

Clasa de baza implementeaza o interfata. Metodele din interfata sunt implementate ca virtual

in clasa de baza pentru a permite override in clasa derivata. Cum accesam o asemenea

metoda din clasa de baza avand la dispozitie o instanta a tipului derivat ?

Construim urmatorul exemplu.

interface ITest

{

// Aceasta metoda va fi virtuala in clasa Baza si override in clasa Derivata.

void VirtualTest();

}

// Baza implementeaza interfata ITest.

class Baza : ITest

{

public virtual void VirtualTest()

{

Console.WriteLine("Baza.VirtualTest - implementare VirtualTest..."); }

// Metoda specifica clasei Baza public void MetodaBaza()

{

Console.WriteLine("Baza.MetodaBaza - implementare metoda ...");

} }

class Derivata : Baza {

public override void VirtualTest()

{

// Daca decomentam linia urmatoare, se va apela metoda VirtualTest

// din clasa de Baza

Page 28: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

28

//base.VirtualTest();

Console.WriteLine("Derivata.VirtualTest - implementare VirtualTest...");

}

}

In clasa de test putem incerca urmatorul cod :

Derivata d = new Derivata();

// apel metoda MetodaBaza – normal, nici o problema

d.MetodaBaza();

// Apel metoda VirtualTest(), este cea din clasa Derivata. d.VirtualTest();

// Conversie obiect Derivata la tip Baza

Baza b = d as Baza; // Apel pe acest obiect al metodei VirtualTest()

// Se va apela VirtualTest() din clasa Baza?

b.VirtualTest();

Rezultatul este ca ultimul apel va fi tot la VirtualTest() din clasa Derivata.

Folosim reflection pentru a vedea ce tip reprezinta obiectul b definit mai sus.

Type type = b.GetType();

Console.WriteLine("type Name = {0}", type.Name);

Rezultatul este : type name = Derivata

Rezolvari posibile.

I. O solutie ar fi sa obtinem un pointer la metoda VirtualTest() din clasa Baza si apoi sa

apelam metoda Invoke() pe acest obiect. Codul este urmatorul :

Derivata child = new Derivata();

// Reflection

MethodInfo mib = typeof(Baza).GetMethod("VirtualTest");

RuntimeMethodHandle handle = mib.MethodHandle;

IntPtr functionPointer = handle.GetFunctionPointer();

Action pf = (Action)Activator.CreateInstance(typeof(Action), child, functionPointer);

pf.Invoke();

Observatie

RuntimeMethodHandle este o structura si reprezinta un handle la

reprezentarea interna a metadatei pentru o metoda.

Metoda GetfunctionPointer() este definita astfel: //

// Summary:

// Obtains a pointer to the method represented by this instance.

//

// Returns: // A pointer to the method represented by this instance.

//

// Exceptions:

// System.Security.SecurityException:

// The caller does not have the necessary permission

// to perform this operation.

Page 29: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

29

[SecurityCritical]

public IntPtr GetFunctionPointer();

Valoarea returnata de GetFunctionPointer() este folosita in metoda

Activator.CreateInstance() pentru a crea o instanta a metodei data de

varaibila “functionPointer”, ce se potriveste cu delegate Action().

II. O alta solutie poate fi data si folosind Delegate. Nu apare instanta tipului Derivata si ca atare nu se incadreaza in cerintele problemei. // Reflection

MethodInfo mib = typeof(Baza).GetMethod("VirtualTest");

// Creare delegate

Delegate del = Delegate.CreateDelegate(typeof(Action), null, mib);

del.DynamicInvoke();

Observatie

Action este un delegate din FCL. Metodele ce se potrivesc cu acest delegate returneaza void

si nu au parametri. In FCL exista mai multe prototipuri pentru Action.

III. O alta solutie ar fi ca metoda VirtualTest() sa contina un parametru bool si implementarea

din clasa Derivata sa foloseasca acest parametru.

interface ITest {

// Aceasta metoda va fi virtuala in clasa Baza si override in clasa Derivata.

void VirtualTest(bool apelBaza);

}

// Nu am mai dat implementarea din clasa Baza

class Derivata : Baza

{ public override void VirtualTest(bool apelBaza)

{

if (apelBaza) base.VirtualTest();

else

{ // cod ... }

}

}

Codul pentru testare este urmatorul:

Derivata d = new Derivata() ; d.VirtualTest(true) ; // apel metoda din clasa Baza d.VirtualTest(false) ; // apel metoda din clasa Derivata

Interfete si ierarhii de clase

Intr-o ierarhie tipica de clase, clasa de baza ar trebui sa fie derivata din interfata, furnizand

polimorfismul cu interfata la toate subclasele. Aceasta clasa de baza trebuie sa defineasca toti

membri interfetei ca fiind virtual astfel incat subclasele ii pot suprascrie - override.

Fiecare nivel al clasei din ierarhie poate suprascrie nivelul precedent.

Page 30: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

30

using System.Diagnostics; // Pentru clasa Trace public interface ITrace { void TraceSelf( ); } public class A : ITrace { public virtual void TraceSelf() { Trace.WriteLine("A"); } } public class B : A { public override void TraceSelf() { Trace.WriteLine("B"); // base.TraceSelf(); // putem apela din clasa de baza } } public class C : B { public override void TraceSelf(){Trace.WriteLine("C");} }

Page 31: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

31

Interfete si Generice

In multe situatii este de folos sa definim interfete pentru clase colectie generice sau

pentru clase generice ce reprezinta articole intr-o colectie. Preferinta pentru clasele generice

este de a folosi interfete generice, de ex. IComparable<T> in loc de IComparable pentru a evita operatiile de boxing si unboxing pe tipurile valoare (operatii consumatoare de timp).

FCL defineste mai multe interfete generice utilizate cu clasele colectii din spatiul de nume

System.Collections.Generic.

Exemplu

public interface IList<T> { void AddHead(T item); void RemoveHead(T item); void RemoveAll( ); }

Putem implementa interfata in mod implicit si sa furnizam un intreg pentru tipul generic.

public class NumberList : IList<int> { public void AddHead(int item){...} public void RemoveHead(int item){...} public void RemoveAll( ){...} // cod ... }

Alt exemplu:

IList<int> list = new NumberList(); list.AddHead(3);

Putem mentine polimorfismul cu interfete generice daca folosim interfata ca parametru

generic:

public class ListClient<T> { public void ProcessList(IList<T> list){...} } IList<int> numbers = new NumberList(); IList<string> names = new NameList(); // derivata din IList<string> ListClient<int> numbersClient = new ListClient<int>(); ListClient<string> namesClient = new ListClient<string>(); // reutilzare cod si algoritmi din ProcessList( ): numbersClient.ProcessList(numbers); namesClient.ProcessList(names);

Page 32: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

32

Derivarea dintr-o interfata generica

Cand derivam o interfata dintr-o interfata generica, putem proceda asa:

public interface IBaseInterface<T> { void Metoda(T t); } public interface ISubInterface<T> : IBaseInterface<T> {...}

sau

public interface ISubInterface : IBaseInterface<string> {...}

In mod normal cand derivam din interfete generice ar trebui sa procedam asa (pastrare

caracter generic):

public class List<T> : IList<T> { public void AddHead(T item) {...} // restul implementarii } IList<int> numbers = new List<int>( ); IList<string> names = new List<string>( );

Ceva de genul

// Nu se compileaza

public class List<T,U> : IList<T>,IList<U> {...}

nu este permis.

Implementarea explicita a interfetelor generice

Nu sunt probleme deosebite.

public class NumberList : IList<int> { void IList<int>.AddHead(int item) {...} void IList<int>.RemoveHead(int item) {...} void IList<int>.RemoveAll( ) {...} // cod ... }

Implementarea implicita a interfetelor generice ar putea fi asa:

public class List : IList<int>,IList<string> { public void AddHead(int item) {...} public void AddHead(string item) {...} public void RemoveAll( ) {...} // este pentru ambele interfete

Page 33: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

33

// se creaza confuzie // cod }

In urmatorul caz trebuie sa folosim implementare explicita pentru ca supraincarcarea

metodelor in C# nu ia in considerare tipul returnat.

public interface IList<T> { void AddHead(T item); void RemoveHead(T item); void RemoveAll( ); T GetHead( ); // metoda ce trebuie supraincarcata }

Deci:

public class List : IList<int>,IList<string> { int IList<int>.GetHead( ) {...} string IList<string>.GetHead( ){...} // cod ... }

Interfete generice ca operatori

In C# 2.0, este imposibil sa folosim operatori precum + sau += pe tipuri generice ca

parametri.

Urmatorul cod nu se compileaza:

public class Calculator<T> { public T Add(T argument1, T argument2) { return argument1 + argument2; //nu se compileaza } // cod ... alte metode }

Solutie:

Putem folosi interfete ce definesc operatii generice la nivel de interfata si furnizeaza un tip

concret si implementare la nivel de subclasa :

public interface ICalculator<T> { T Add(T argument1,T argument2); T Subtract(T argument1,T argument2); T Divide(T argument1,T argument2); T Multiply(T argument1,T argument2); }

Page 34: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

34

Clasa Calculator implementeaza interfata ICalculator pentru tipul concret int. public class Calculator : ICalculator<int> { public int Add(int argument1, int argument2) { return argument1 + argument2; } // Restul metodelor }

Constrangeri la nivel de interfata

O interfata poate defini constrangeri pentru tipurile generice ce le utilizeaza.

// T este un tip ce implementeaza interfata IComparable

public interface IList<T> where T : IComparable<T> {...} // T este un tip ce implementeaza ctor implicit public interface IList<T> where T : new() {...} public class List<T> : IList<T> where T : IComparable<T> { public void Remove(T item) {...} // cod ... }

public class ListClient<L,T> where L : IList<T> { public void ProcessList(L list) {...} } public class NumberList : IList<int> {...} ListClient<NumberList,int> client = new ListClient<NumberList,int>( ); NumberList numbers = new NumberList(); client.ProcessList(numbers);

Page 35: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

35

Covarianta si Contravarianta in interfete

Interfete generice « variant »

Putem declara parametri de tip generic in interfete ca fiind covariant sau contravariant.

Covarianta permite metodelor din interfata sa poata returna tipuri ce sunt “mai jos” in

ierarhia de derivare decat cele definite de parametrii de tip generic.

Contravarianta permite metodelor din interfata sa aiba tipuri de argumente ce sunt « mai

sus » in ierarhie decat cel specificat prin parametrul generic.

Observatie

Clasa de baza se considera « mai jos » in ierarhia de derivare.

O interfata generica ce are parametri de tip generic covarianti sau contravarianti se numeste

« variant ».

O interfata care nu e nici covarianta nici contravarianta se numeste invarianta.

Interfetele generice variant se declara folosind cuvintele cheie in si out pentru parametrii

generici.

out : parametru de tip generic covariant;

in : parametru de tip generic contravariant;

Regula pentru out: Tipul este folosit numai ca tip returnat de metodele din interfata si nu este folosit ca tip al

argumentelor metodelor.

Exemplu: interface ICovariant<out R> { // Corect R GetSomething(); // Urmatoarea instructiune genereaza o eroare la compilare. // void SetSometing(R sampleArg); }

Observatie :

Daca avem un delegate generic contravariant ca parametru al metodei, se poate folosi tipul

ca parametru generic pentru delegate.

Exemplu

interface ICovariant<out R> { void DoSomething(Action<R> callback); }

Page 36: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

36

Regula pentru out: Tipul nu este folosit drept constrangere generica pentru metodele din interfata:

interface ICovariant<out R> { // Urmatoarea instructiune genereaza o eroare la compilare // deoarece putem folosi in constrangeri generice numai // tipuri contravariante sau invariante. // void DoSomething<T>() where T : R; }

in: declarare parametru de tip generic ca fiind contravariant. Poate fi folosit pentru

constrangeri generice.

Tipul contravariant poate fi folosit numai ca tip al argumetelor metodelor si nu ca valoare de

retur.

interface IContravariant<in A> { void SetSomething(A sampleArg); void DoSomething<T>() where T : A; // Urmatoarea instructiune genereaza o eroare la compilare // A GetSomething(); }

E posibil sa folosim covarianta si contravarianta in aceeasi interfata, dar pentru parametri

diferiti (nu e posibil sa avem in si out pentru acelasi parametru).

interface IVariant<out R, in A> { R GetSomething(); void SetSomething(A sampleArg); R GetSetSometings(A sampleArg); } Exemple:

interface ICovariant<out R> { R GetSomething(); } class SampleImplementation<R> : ICovariant<R> { public R GetSomething() { // Cod ... return default(R); } }

Page 37: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

37

Clasele ce implementeaza interfete “variante” sunt invariante.

// Interfata este covarianta. ICovariant<Button> ibutton = new SampleImplementation<Button>(); // Object este “mai jos” in ierarhia de derivare; // este clasa de baza (direct sau indirect) pentru Button. ICovariant<Object> iobj = ibutton; // Clasa este invarianta (vedeti observatia de mai sus). SampleImplementation<Button> button = new SampleImplementation<Button>(); // Urmatoarea instructiune genereaza o eroare la compilare // deoarece clasele sunt invariante. // SampleImplementation<Object> obj = button;

“Varianta” in interfete generice (C#)

Suportul pentru varianta permite conversia implicita a claselor ce implementeaza aceste

interfete.

.NET Framework 4 introduce suport pentru varianta pe interfetele urmatoare.

• IEnumerable <T> (T is covariant)

• IEnumerator <T> (T is covariant)

• IQueryable <T> (T is covariant)

• IGrouping <TKey, TElement> ( TKey and TElement are covariant)

• IComparer <T> (T is contravariant)

• IEqualityComparer <T> (T is contravariant)

• IComparable <T> (T is contravariant)

Exemplu complet cu interfete covariante si contravariante

Definire interfete si clase ce implementeaza aceste interfete

Etapa I

namespace Variant

{

/// <summary> /// Interfata covarianta

/// </summary>

/// <typeparam name="R"></typeparam>

public interface ICovariant<out R>

{

Page 38: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

38

R Get();

}

/// <summary> /// Interfata contravarianta

/// </summary> /// <typeparam name="T"></typeparam>

interface IContravariant<in T>

{

void DoPrint(T t);

}

/// <summary> /// Clasa ce implementeaza interfata covarianta

/// Clasa este invarianta

/// </summary> /// <typeparam name="R"></typeparam>

public class ImplementCovariant<R>: ICovariant<R>

{

private R RItem;

public ImplementCovariant(R item)

{ RItem = item;

} public R Get()

{

Console.WriteLine("Get din ImplementCovariant pentru {0}",

RItem.ToString());

return RItem;

}

}

/// <summary>

/// Clasa ce implementeaza interfata contravarianta

/// Clasa este invarianta

/// </summary> /// <typeparam name="T"></typeparam>

public class ImplementContravariant<T>: IContravariant<T>

{

private T TItem;

public ImplementContravariant(T item)

{

TItem = item;

}

public void DoPrint(T t)

{

Console.WriteLine("DoPrint din ImplementContravariant pentru {0}",

t.ToString());

}

}

Page 39: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

39

Etapa II

Definire ierarhie de clase

Baza

Derivata

DerivataDerivata

namespace Variant

{

// Clasa de baza

public class Baza {

public static int Contor = 0; public string Name { get; set; }

public int ID { get; set; }

public Baza():this("No name")

{

//Console.WriteLine("Ctor Baza. ID = {0}; Name = {1}", ID, Name);

} public Baza(string name)

{

ID = Contor;

Contor++;

Name = name;

Console.WriteLine("Ctor Baza. ID = {0}; Name = {1}", ID, Name);

}

}

public class Derivata : Baza

{

public Derivata():base("Ctor Derivata!")

{ }

public Derivata(string name):base( name)

{ }

}

public class DerivataDerivata : Derivata

{

public DerivataDerivata():base("Ctor DerivataDerivata!")

{ }

}

}

Etapa III

Codul pentru testare

Baza b = new Baza();

DerivataDerivata dd = new DerivataDerivata();

// Demonstratie covarianta ImplementCovariant<DerivataDerivata> idd =

new ImplementCovariant<DerivataDerivata>(dd);

// d este un tip mai putin derivat (Derivata)

Derivata d = idd.Get();

d.Name = "Name changed";

Page 40: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

40

Type type = d.GetType();

Console.WriteLine("type " + type.FullName);

Console.WriteLine("d Name ={0}, ID = {1}, {2}",d.Name, d.ID, dd.Name);

// Demonstratie contravarianta

ImplementContravariant<Baza> bin = new ImplementContravariant<Baza>(b);

// dd este un tip mai derivat (DerivataDerivata)

bin.DoPrint(dd);

Page 41: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

41

Construire tipuri enumerabile. Interfetele IEnumerable si IEnumerator.

Sintaxa C# suporta cuvantul cheie foreach pentru a permite iterarea peste continutul oricarui

tip array.

// Iterare peste un array. int[] ints = {10, 20, 30, 40}; foreach(int i in ints) {

Console.WriteLine(i); }

Cod echivalent:

for (int i=0; i < ints.Count; i++) { Console.WriteLine(ints[i].ToString()); }

Observatie

Orice tip ce suporta metoda GetEnumeartor() poate fi evaluat cu constructia foreach.

Implementarea unui tip enumerabil are la baza doua interfete definite in FCL, IEnumerable si IEnumerator.

Interfata IEnumerable este definita astfel: // This interface informs the caller // that the object's subitems can be enumerated. public interface IEnumerable {

IEnumerator GetEnumerator(); }

Metoda GetEnumerator() returneaza o referinta la interfata IEnumerator. IEnumerator furnizeaza infrastructura ce permite iterarea obiectelor interne continute de IEnumerable. // This interface allows the caller to // obtain a container's subitems. public interface IEnumerator {

bool MoveNext (); // Advance the internal position of the cursor. object Current { get;} // Get the current item (read-only property). void Reset (); // Reset the cursor before the first member.

}

Observatie

Tipul System.Array implementeaza IEnumerable si IEnumerator.

Page 42: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

42

Exemplu

public class B {

// cod } public class A: IEnumerable { private B[] tablou = new B[4];

public A() {

// cod pentru completare tablou }

// metoda din interfata IEnumerable

public IEnumerator GetEnumerator() {

return tablou.GetEnumerator(); }

}

In clasa de test putem scrie urmatorul cod:

A a = new A(); // se pp ca in ctor se completeaza “tablou” foreach(B b in a)

Console.WriteLine(b...);

Daca dorim sa ascundem functionalitatea lui IEnumerable de la nivel de obiect, putem

implementa GetEnumerator() astfel: IEnumerator IEnumerable.GetEnumerator() {

return tablou.GetEnumerator(); }

Construire metode de iterare folosind cuvantul cheie yield

Un iterartor este un membru ce specifica cum articolele interne dintr-un container trebuiesc

returnate cand sunt procesate cu foreach. public class A {

private B[] tablou = new B[10]; ... // Metoda pentru iterare public IEnumerator GetEnumerator() {

foreach (B b in tablou) {

yield return b; }

} }

Mai multe informatii in MSDN.

Page 43: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

43

Probleme propuse

P1. Implementare functionalitate foreach intr-o clasa

Enunt problema

Aveti nevoie de o clasa ce contine o lista de obiecte; fiecare din aceste obiecte contin la randul

lor o lista de obiecte.

Doriti sa folositi o bucla imbricata foreach (adica foreach in foreach) pentru a itera toate

obiectele din ambele clase in modul urmator:

foreach (SubGrup sg in grup)

{

foreach (Item i in sg)

{

// operatii pe obiectele Item continute in sg

// care la randul lui este continut in colectia group

}

}

Indicatie:

Se considera urmatoarele clase:

Group, SubGroup si Item.

Clasa Group mentine o colectie de obiecte SubGroup, iar clasa SubGroup mentine o colectie

de obiecte Item.

Clasa Item are descrierea urmatoare:

public class Item

{

// ctor

public Item(string name, int location)

{

itemName = name;

itemLocation = location;

}

private string itemName = "";

private int itemLocation = 0;

public string ItemName

{

get {return(itemName);}

set {itemName = value;}

}

public int ItemLocation

{

get {return(itemLocation);}

set {itemLocation = value;}

}

}

Page 44: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

44

Va trebui sa construiti clasele Group si SubGroup precum si metodele aferente.

Scrieti si codul pentru a testa functionalitatea claselor.

Observatie:

Pentru ca o clasa sa poata fi utilizata intr-o bucla foreach aceasta trebuie sa implementeze un

iterator.

Un iterator poate fi o metoda, un operator supraincarcat, sau accesorul get al unei proprietati

ce returneaza fie un obiect de tipul:

o System.Collections.IEnumerator, sau

o System.Collections. Generic.IEnumerator<T>, sau

o System.Collections.IEnumerable, sau

o System.Collections. Generic.IEnumerable<T>

si care contine cel putin o instructiune yield.

P2. Creare enumeratori personalizati

Enunt problema

Aveti nevoie sa adaugati suport pentru foreach la o clasa care sa va dea posibilitatea de a

parcurge colectia in mai multe moduri:

o de la inceput la sfarist, element cu element ;

o de la inceput la sfarsit dar « sarind » peste anumite elemente (in pseudocod ar fi asa :

FOR I = 1 TO N STEP 3 { // cod}).

o de la sfarsit spre inceput element cu element ;

o de la sfarsit spre inceput dar « sarind » peste anumite elemente.

Observatie :

« Salturile » nu trebuie sa fie « hard coded ».

P3. Construire tip ce suporta sortarea

Enunt : Sa se construiasca un tip ce suporta sortarea.

Rezolvare : Se va construi un tip ce este derivat din IComparer sau IComparable.

public class Figura : IComparable {

public Figura(){}

public Figura(int h, int l)

{

this.Inaltime = h;

this.Latime = l;

}

public int Inaltime { get; set;}

public int Latime {get; set; }

public int CompareTo(object obj)

Page 45: C3 Reflection Atribute Interfeteiasimin/csharp/C3 Reflection...Sintaxa folosita pentru a atasa un atribut la un tip sau membru este asemanatoare cu cea folosita la instantierea unei

Atribute si interfete

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 27.10.2014

Ioan Asiminoaei

45

{

if (this.GetType( ) != obj.GetType( ))

{

throw (new ArgumentException(

"Obiectele comparate trebuie sa fie de tip Figura."));

}

else

{

Figura d2 = (Figura)obj;

long aria1 = this.Inaltime * this.Latime;

long aria2 = d2.Inaltime * d2.Latime;

if (aria1 == aria2)

{

return (0);

}

else if (aria1 > aria2)

{

return (1);

}

else

{

return (-1);

}

}

}

public override string ToString( )

{

return ("Inaltime:" + Inaltime + " Latime:" + Latime);

}

}

// Test

Figura[] tf = new Figura[4]

{

new Figura(1,3),

new Figura(4,3),

new Figura(2,1),

new Figura(6,1)

};

Array.Sort(tf);

Continuati pentru interfata IComparer.

In codul de test ar trebui sa putem scrie ceva de genul :

IComparer ic = new NumeClasaCeImplementeazaIComparer();

Array.Sort(array, ic);

P4. Implementati pattern-ul Observer (Publish / Subscribe) folosind interfete.

Enunt: Clientii se aboneaza la un serviciu meteo si vor sa fie anuntati cand apare o noua

prognoza (1) si/sau conditii meteo deosebite (2) (cod galben : vant, ploi, temperaturi ridicate,

temperaturi scazute, etc.). Implementati pattern-ul Observer pentru tipuri ce se aboneaza la

serviciul (1) sau serviciul (2) sau la ambele servicii (1) si (2).