+ All Categories
Home > Documents > C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta...

C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta...

Date post: 01-Mar-2020
Category:
Upload: others
View: 2 times
Download: 0 times
Share this document with a friend
51
Delegates Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 1/51 Asiminoaei Ioan Delegates Cuprins Partea a - I - a Ce este un delegate? Definirea unui delegate. Clasele de baza System.MulticastDelegate si System.Delegate. Invocarea metodelor callback. Covarianta (relaxed delegates) delegates. Liste de delegates. Delegates si Reflection. Exemple Partea a – II - a Apel sincron. Apel asincron. Delegates anonimi. Expresii lambda. Evenimente Pattern-ul Publish / Subscribe Exemple.
Transcript
Page 1: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 1/51

Asiminoaei Ioan

Delegates

Cuprins

Partea a - I - a

Ce este un delegate?

Definirea unui delegate.

Clasele de baza System.MulticastDelegate si System.Delegate.

Invocarea metodelor callback.

Covarianta (relaxed delegates) delegates.

Liste de delegates.

Delegates si Reflection.

Exemple

Partea a – II - a

Apel sincron. Apel asincron.

Delegates anonimi.

Expresii lambda.

Evenimente

Pattern-ul Publish / Subscribe

Exemple.

Page 2: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 2/51

Asiminoaei Ioan

Ce este un delegate ?

In esenta, un delegate este un obiect type-safe ce puncteaza la o metoda (sau posibil o

lista de metode) din cadrul aplicatiei, metoda ce poate fi invocata mai tarziu. Un obiect

delegate mentine urmatoarele informatii :

• Adresa metodei pe care se face apel;

• Argumentele (daca exista) acestei metode;

• Valoarea de retur (daca exista) a acestei metode.

Dupa ce am creat delegate si am furnizat informatiile necesare, acesta poate invoca in

mod dinamic metoda (metodele) la care puncteaza.

Metodele pot fi apelate sincron sau asincron.

Definirea unui delagate in C#, exemplu:

public delegate void Feedback( Object value,

Int32 item, Int32 numItems);

Prototipul metodei ce poate fi apelat cu acest delegate este: public void Nume_Metoda(object value, int item, int numItems) ;

Cand compilatorul proceseaza acest cod, va genera o clasa sealed derivata din

System.MulticastDelegate.

Clasa poate avea urmatorul prototip (cod incomplet):

class sealed Feedback : System.MulticastDelegate {

// Constructor public Feedback(Object target, Int32 methodPtr); // Metoda cu acelasi prototip ca cel specificat // de codul sursa public void Invoke( Object value,

Int32 item, Int32 numItems);

// Metode ce permit apelul asincron public virtual IAsyncResult BeginInvoke(

Object value, Int32 item, Int32 numItems, AsyncCallback callback, Object object);

public virtual void EndInvoke(IAsyncResult result); }

Page 3: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 3/51

Asiminoaei Ioan

Observatie

Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke

returneaza void in acest caz.

Metoda Invoke nu o vom apela explicit din cod, desi se poate face si acest lucru (se

apeleaza pe un obiect de tip delegate).

Delegates pot “puncta” la metode ce contin parametri prefixati cu ref si out sau un

array de parametri marcati cu cuvantul cheie params.

Exemplu

public delegate string AltDelegate(out bool a,

ref bool b, int c);

clasa generata ar arata cam asa:

sealed class AltDelegate : System.MulticastDelegate { public AltDelegate (object target, uint functionAddress); public string Invoke(out bool a, ref bool b, int c); public IAsyncResult BeginInvoke(out bool a, ref bool b, int c,

AsyncCallback cb, object state); public string EndInvoke(out bool a, ref bool b,

IAsyncResult result); }

Observatie

Metodele Invoke si EndInvoke returneaza string in acest caz. Observati modul de

creare al clasei AltDelegate.

Pattern-ul de baza folosit de C# la intalnirea unui delegate poate fi urmatorul :

// pseudo-code public sealed class DelegateName : System.MulticastDelegate { // constructor

public DelegateName (object target, uint functionAddress); // metoda Invoke pentru apel sincron public delegateReturnValue Invoke(

allDelegateInputRefAndOutParams ); // metoda pentru apel asincron public IAsyncResult BeginInvoke(

allDelegateInputRefAndOutParams,

Page 4: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 4/51

Asiminoaei Ioan

AsyncCallback cb, object state);

// metoda pentru terminarea apelului asincron public delegateReturnValue EndInvoke(

allDelegateRefAndOutParams, IAsyncResult result);

}

Page 5: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 5/51

Asiminoaei Ioan

Clasele de baza System.MulticastDelegate si System.Delegate

O descriere completa o gasiti in MSDN.

public abstract class MulticastDelegate : Delegate {

// Returns the list of methods "pointed to." public sealed override Delegate[] GetInvocationList(); // Overloaded operators. public static bool operator ==(MulticastDelegate d1,

MulticastDelegate d2); public static bool operator !=(MulticastDelegate d1,

MulticastDelegate d2); // Used internally to manage the list of methods // maintained by the delegate. private IntPtr _invocationCount; private object _invocationList;

} public abstract class Delegate : ICloneable, ISerializable {

// Methods to interact with the list of functions. public static Delegate Combine(

params Delegate[] delegates); public static Delegate Combine(Delegate a, Delegate b); public static Delegate Remove(Delegate source,

Delegate value); public static Delegate RemoveAll(Delegate source,

Delegate value); // Overloaded operators. public static bool operator ==(Delegate d1, Delegate d2); public static bool operator !=( Delegate d1, Delegate d2); // Properties that expose the delegate target. public MethodInfo Method { get; } public object Target { get; }

}

Campuri principale din System.MulticastDelegate

Camp Tip Descriere

_target System.Object Se refera la obiectul pe care se va lucra cand

metoda callback va fi apelata. Acest camp

este folosit pentru metode callback ale

instantei.

_methodPtr System.Int32 Un intreg folosit intern de CLR pentru a

Page 6: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 6/51

Asiminoaei Ioan

identifica metoda callback apelata.

_prev System.MulticastDelegate Se refera la un alt obiect delegate. In mod

normal are valoarea null. Este folosit pentru

a crea o lista inlantuita de obiecte

MulticastDelegate.

Constructorii pentru delegate au doi parametri: o referinta la un object si un intreg ce

identifica metoda callback.

Pentru metodele instantei, _target retine referinta la obiect, iar pentru metodele

callback statice, _target = null.

MulticastDelegate defineste doua proprietati: Target si Method.

Proprietatea Target returneaza o referinta la obiectul pe care se va lucra daca metoda

callback apelata este o metoda a instantei. Daca metoda este statica Target returneaza

null.

Proprietatea Method returneaza un obiect System.Reflection.MethodInfo, obiect

ce identifica metoda callback.

Invocarea metodelor callback

Exemplu. Metoda ProcessItems are ca parametru un delegate de tip FeedBack – definit la

inceputul cursului. Metoda are ca parametru o referinta la o metoda (in C asta inseamna

pointer la o functie).

public void ProcessItems(Feedback feedback) {

for (Int32 item = 0; item < items.Length; item++) {

if (feedback != null) {

// // Daca s-a specificat o functie callback, // atunci o apelam. //

feedback(items[item], item, items.Length);

} }

}

Page 7: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 7/51

Asiminoaei Ioan

Un alt exemplu simplu de delegate (Andrew Troelsen) namespace SimpleDelegate {

// Acest delegate poate puncta la orice metoda ce are ca // parametri doi intregi si returneaza un intreg. public delegate int BinaryOp(int x, int y); public class SimpleMath {

public static int Add(int x, int y) { return x + y; } public int Subtract(int x, int y) { return x - y; }

}

class Test {

static void Main(string[] args) {

Console.WriteLine(" - Exemplu Delegate -\n"); // Cream un obiect BinaryOp ce puncteaza la // SimpleMath.Add() Metoda statica BinaryOp b = new BinaryOp(SimpleMath.Add); // Invocam metoda Add (indirect) folosind obiectul // delegate. Console.WriteLine("10 + 10 = {0}", b(10, 10)); // Metoda a instantei SimpleMath s = new SimpleMath(); BinaryOp dif = new BinaryOp(s.Subtract); Console.WriteLine(" 20 – 10 = {0}", dif(20,10)); Console.ReadLine();

} } }

Observatie

In loc de apelul

int result = b(10,10) ;

putem scrie si int result = b.Invoke(10, 10);

Page 8: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 8/51

Asiminoaei Ioan

Vezi exemplele cu delegates (proiect ...) class A { public delegate void D1(string msg); public delegate void D2(string msg); private D1 d1_delegat; private D2 d2_delegat; public void OnD1(D1 metodaClient)

{ d1_delegat = metodaClient; } public void OnD2(D2 metodaClient) { d2_delegat = metodaClient; } public void ApelDelegates() { ... if (d1_delegat != null) d1_delegat("D1!"); ... if (d2_delegat != null) d2_delegat("D2"); }

}

Codul din metoda Main poate fi: A a = new A(); a.OnD1(new A.D1(MainD1)); // d1_delegat = MainD1 a.OnD2(new A.D2(MainD2)); a.ApelDelegates();

si metodele MainD1, MainD2 – in aceeasi clasa cu metoda Main public static void MainD1(string msg) { Console.WriteLine(msg); } public static void MainD2(string msg) { Console.WriteLine(msg); }

Page 9: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 9/51

Asiminoaei Ioan

Covarianta si contravarianta in delegates

.NET Framework 3.5 , 4.0 si Visual Studio 2008 au introdus suport pentru

varianta pentru determinarea semnaturii metodelor cu tipurile delegate, adica putem

atribui la delegates nu numai metode ce se potrivesc cu semnatura delegate-ului, dar si

metode ce returneaza tipuri situate mai jos in ierarhia de derivare (covarianta) sau

accepta parametri ce sunt de un tip situat mai sus in ierarhia de derivare (contravarianta)

fata de tipul specificat de delagate.

Aceasta include atat delegates generici cat si delegates non-generici.

Sa urmarim aceste lucruri in exemplele de mai jos.

public class First { } // Clasa Second este situata “mai sus” in ierarhia de derivare public class Second : First { } // Definim doi delegates: unul non-generic si unul generic public delegate First SampleDelegate(Second a); public delegate R SampleGenericDelegate<A, R>(A a);

iar metodele atribuite pot fi:

// Se potriveste cu semnataura public static First ASecondRFirst(Second first) { return new First(); } // Tipul returnat este “mai” derivat. public static Second ASecondRSecond(Second second) { return new Second(); } // Tipul argumentului este mai putin derivat. public static First AFirstRFirst(First first) { return new First(); } // Tipul returnat este “mai” derivat si // tipul argumentului este mai putin derivat public static Second AFirstRSecond(First first) { return new Second(); }

Urmatorul exemplu ilustreaza conversia implicita intre semnataura metodei si tipul

delegate.

// Atribuim o metoda ce se potriveste ca semnatura la // un delegate non-generic. // Nu e necesara conversia. SampleDelegate dNonGeneric = ASecondRFirst; // Atribuim o metoda cu un tip returnat “mai” derivat // si tipul argumentului mai putin derivat la

Page 10: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 10/51

Asiminoaei Ioan

// un delegate non-generic. // Se foloseste conversia implicita. SampleDelegate dNonGenericConversion = AFirstRSecond; // Atribuim o metoda ce se potriveste ca semnataura // la un delegate generic. // Nu e necesara conversia. SampleGenericDelegate<Second, First> dGeneric = ASecondRFirst; // Atribuim o metoda cu un tip returnat « mai putin » derivat // si tipul argumentului « mai derivat » la // un delegate generic. // Se foloseste conversia implicita. SampleGenericDelegate<Second, First> dGenericConversion = AFirstRSecond;

Page 11: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 11/51

Asiminoaei Ioan

Delegate - Varianta in parametri de tip generic

In .NET Framework 4, putem realiza conversia implicita intre delegates, astfel

incat delegates generici ce au specificat tipuri diferite ca parametri generici pot fi atribuiti

unul altuia cu conditia ca tipurile sa fie mostenite unul din altul asa cum e cerut de

varianta.

Cuvintele cheie sunt:

� in pentru delegate contravariant;

� out pentru delegate covariant.

// Tipul T este declarat covariant folosind cuvantul cheie out. public delegate T SampleGenericDelegate <out T>(); public static void Test() { SampleGenericDelegate <String> dString = () => " "; // Putem face urmatoarea atribuire deoarece T este marcat // cu out (covariant) si Object este mai jos in ierarhie // decat String SampleGenericDelegate <Object> dObject = dString; }

In exemplul urmator, SampleGenericDelegate<String> nu poate fi convertit in mod

explicit la SampleGenericDelegate<Object>, desi String este derivata din Object.

Problema se rezolva daca marcam parametrul generic T cu out.

public delegate T SampleGenericDelegate<T>(); public static void Test() { SampleGenericDelegate<String> dString = () => " "; // You can assign the dObject delegate // to the same lambda expression as dString delegate // because of the variance support for // matching method signatures with delegate types. SampleGenericDelegate<Object> dObject = () => " "; // The following statement generates a compiler error // because the generic type T is not marked as covariant. // SampleGenericDelegate <Object> dObject = dString; }

Page 12: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 12/51

Asiminoaei Ioan

Delegates predefiniti in .NET

.NET Framework 4 introduce suport pentru varianta pentru parametri de tip generic in

urmatorii delegates:

• Delegate Action din namespace System, de exemplu, Action <T > si Action <T1, T2 >

• Delegates Func din namespace System, de exemplu, Func <TResult > si Func <T, TResult >

• Delegate Predicate <T >

• Delegate Comparison <T >

• Delegate Converter <TInput, TOutput >

Daca un delegate generic are parametri generici covarianti sau contravarianti, poate fi

referit ca un delegate generic variant.

Exemplu delegate covariant:

public delegate R DCovariant<out R>();

Exemplu delegate contravariant:

public delegate void DContravariant<in A>(A a);

Exemplu delegate covariant si contravariant

public delegate R DVariant<in A, out R>(A a);

Exemplu : cast de la clasa de baza la clasa derivata

In cadrul unei ierarhii de clase construim un singur delegate ce va puncta la metode ce

returneaza tipuri de clase conform regulilor de mostenire a claselor.

Consideram clasa B derivata din A.

class A {} class B : A {}

iar in clasa de test putem scrie :

// Definim un delegate ce va puncta la o metoda fara parametri // si care returneaza o instanta a tipului A. public delegate A ObtinA();

Page 13: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 13/51

Asiminoaei Ioan

public static A GetA() {

return new A(); } public static B GetB() {

return new B(); } static void Main(string[] args) {

Console.WriteLine("***** Covarianta Delegate *****\n"); ObtinA targetA = new ObtinA(GetA); A a = targetA(); Console.WriteLine("Am obtinut {0}", a);

// Covariance permite aceasta atribuire. // Atentie! ObtinA returneaza un obiect de tip A // Il folosim aici pt a obtine o instanta a clasei B ObtinA targetB = new ObtinA(GetB); B b = (B)targetB(); Console.WriteLine("Am obtinut {0}", b);

}

Un exemplu complet cu varianta delegates bazat pe o ierarhie de clase

Consideram urmatoarea ierarhie de clase.

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Delegate { class Persoana { } class Client : Persoana { } class Salariat : Persoana { } class Manager : Salariat{ }

}

Page 14: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 14/51

Asiminoaei Ioan

PersoanaClass

Client

Persoana

Class

Salariat

Persoana

Class

Manager

Salariat

Class

In clasa de test avem urmatorul cod :

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Delegate { class Program { delegate T Actiune<T>(); static void Main(string[] args) { // incercare covarianta Actiune<Client> getClient = () => new Client();

// Linia urmatoare nu se compileaza

Actiune<Persoana> getPersoana = getClient; } } }

Rezolvare: se declara delegate astfe (covariant)l:

delegate T Actiune<out T>();

Acum getPersoana va returna un Client care este derivat din Persoana.

Page 15: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 15/51

Asiminoaei Ioan

Covarianta (out) si contravarianta (in) using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Delegate { class Program { delegate T Actiune<out T>(); // Delegate pentru demo contravarianta // Tipul T nu e declarat cu in, deci contravarianta

// nu va functiona delegate void ActiuneContravarianta<T>(T t); static void Main(string[] args) { // incercare covarianta Actiune<Client> getClient = () => new Client(); Actiune<Persoana> getPersoana = getClient; // incercare contravarianta ActiuneContravarianta<Persoana> printPersoana = (persoana) => Console.WriteLine(persoana); // Nu se compileaza ActiuneContravarianta<Client> printClient =

printPersoana; Console.ReadLine(); } } }

Varianta corecta: delegate void ActiuneContravarianta<in T>(T t);

Codul complet si corect este dat in continuare. using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Delegate { class Program

Page 16: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 16/51

Asiminoaei Ioan

{ delegate T Actiune<out T>(); delegate void ActiuneContravarianta<in T>(T t); static void Main(string[] args) { // incercare covarianta Actiune<Client> getClient = () => new Client(); Actiune<Persoana> getPersoana = getClient; // incercare contravarianta ActiuneContravarianta<Persoana> printPersoana =

(persoana) => Console.WriteLine(persoana);

// Se compileaza acum ActiuneContravarianta<Client> printClient =

printPersoana; Console.ReadLine(); } } }

Daca vom incerca in Main ceva de genul:

ActiuneContravarianta<Salariat> printSalariat =

(salariat) => Console.WriteLine(salariat); ActiuneContravarianta<Client> printClient2 = printSalariat;

nu va functiona deoarece Client nu este derivat din Salariat.

Page 17: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 17/51

Asiminoaei Ioan

Liste de delegates (Delegates Chains)

Pe acelasi obiect apelam mai multe metode callback. Campul _prev din

MulticastDelegate este folosit pentru a mentine lista inlantuita de delegate.

Clasa Delegate defineste urmatoarele metode pe care le putem folosi in gestionarea

listei inlantuite de obiecte delegate.

class System.Delegate {

// Combines the chains represented by head and tail; // head is returned. // NOTE: head will be the last delegate called.

public static Delegate Combine(Delegate tail,

Delegate head);

// Creates a chain represented by the array of delegates. // NOTE: entry 0 is the head // and will be the last delegate called. public static Delegate Combine(Delegate[] delegateArray); // Removes a delegate matching value’s // Target/Method from the chain. // The new head is returned and will be the // last delegate called. public static Delegate Remove(Delegate source,

Delegate value); }

Cand se construieste un obiect delegate, campul _prev = null. Pentru a construi lista

inlantuita de delegate folosim metodele Combine, ca mai jos :

class A { public delegate void D1(string msg); public delegate void D2(string msg); private D1 d1_delegat; private D2 d2_delegat; public void OnD1(D1 metodaClient)

{ d1_delegat += metodaClient; // Combine } public void OnD2(D2 metodaClient) {

Page 18: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 18/51

Asiminoaei Ioan

d2_delegat += metodaClient; // Combine } public void ApelDelegates() { ... if (d1_delegat != null) d1_delegat("D1!"); ... if (d2_delegat != null) d2_delegat("D2"); }

} in Main A a = new A(); a.OnD1(new A.D1(MainD1)); a.OnD2(new A.D2(MainD2)); a.OnD1(new A.D1(MainD1_1)); a.ApelDelegates();

si metodele MainD1, MainD2 – in aceeasi clasa cu metoda Main public static void MainD1(string msg) { Console.WriteLine(msg); } public static void MainD1_1(string msg) { Console.WriteLine(msg); } public static void MainD2(string msg) { Console.WriteLine(msg); }

Operatorul += este sinonim cu Combine, iar -= este sinonim cu Remove.

Page 19: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 19/51

Asiminoaei Ioan

Mai mult control asupra metodei Invoke

Algoritmul de executie al metodleor callback este unul “serial”.

In momentul cand se folosesc “lanturi” de delegates, valoarea returnata este data de

ultimul delegate ce se executa. Acest lucru poate constitui in unele cazuri o problema.

O alta situatie, in cazul « lanturilor » de delegates, este cea data de generarea unei

exceptii sau executia unei metode “lente” in cazul unei metode callback.

Pentru situatiile cand algoritmul de executie al metodelor callback (algoritm serial) nu

este suficient de bun, putem folosi metoda de instanta GetInvocationList din

MulticastDelegate. Aceasta metoda o putem folosi pentru a apela fiecare delegate in

mod explicit dintr-o lista de delegates. In fapt aceasta metoda returneaza o colectie de

delegates, colectie pe care o iteram si executam fiecare delegate din colectie.

Metoda este definita astfel:

public class MulticastDelegate { // Creates a delegate array; each item is a clone from the chain. // NOTE: entry 0 is the tail, which would normally // be called first.

public virtual Delegate[] GetInvocationList(); }

Metoda GetInvocationList opereaza cu referinte la delegate si returneaza un tablou

de referinte la delegates. Se creaza o clona pentru fiecare obiect delegate din lista.

Fiecare clona are campul _prev = null.

Exemplu de folosire

delegate String GetStatus(); //

// Delegate[] arrayOfDelegates = // status.GetInvocationList(); // Declar o lista vida de delegate. GetStatus getStatus = null;

//Construiesc lista de delegates

getStatus += new GetStatus(new A().MetodaA); getStatus += new GetStatus(new B().MetodaB); getStatus += new GetStatus(new C().MetodaC); string results = GetResults(getStatus);

Page 20: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 20/51

Asiminoaei Ioan

Construiesc functia ce apeleaza aceasta lista de delegates si returneaza rezultatele. static String GetResults(GetStatus status) {

if (status == null) return null; StringBuilder res = new StringBuilder();

// Obtinem lista de delegates

Delegate[] ad = status.GetInvocationList();

// Iteram pe fiecare delegate din lista foreach (GetStatus getStatus in ad) {

try {

//Construim rezultatul

res.AppendFormat("{0}{1}{1}", getStatus(), Environment.NewLine);

} catch (Exception e) {

// exceptie res.AppendFormat(“Exceptie...” +

e.Message); }

} // Returnam rezultatul

return res.ToString();

}

Observatie

Folosind aceasta tehnica putem controla fiecare delegate si putem “reactiona” (scriind

cod) pentru a trata exceptiile.

Page 21: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 21/51

Asiminoaei Ioan

Delegate si Reflection

In metodele callback discutate pana acum, informatia necesara (parametrii) erau stiuti in

momentul compilarii.

Tratam problema completarii acestor parametri in momentul executiei plus problema

apelarii unei anumite metode callback. Este exact ceea ce intimpla in programarea

Windows. Un eveniment genereaza un mesaj, daca exista un handler pentru mesaj acesta

va fi tratat (va fi apelata metoda asociata acestui eveniment), altfel nu.

Metodele folosite sunt CreateDelegate si DynamicInvoke.

Metodele din clasa delegate ce realizeaza acest lucru sunt (consultati MSDN):

Name Description

CreateDelegate(Type, MethodInfo)

Creates a delegate of the specified type to represent the

specified static method.

CreateDelegate(Type, Object, MethodInfo)

Creates a delegate of the specified type that represents

the specified static or instance method, with the

specified first argument.

Starting with the .NET Framework version 2.0 Service

Pack 1, this method can be used to access non-public

methods if the caller has been granted

ReflectionPermission with the ReflectionPermissionFlag

.RestrictedMemberAccess flag and if the grant set of the

non-public methods is restricted to the caller’s grant set,

or a subset thereof. (See Security Considerations for

Reflection.)

To use this functionality, your application should target

the .NET Framework version 3.5 or later.

CreateDelegate(Type, Object, String)

Creates a delegate of the specified type that represents

the specified instance method to invoke on the specified

class instance.

CreateDelegate(Type, MethodInfo, Boolean)

Creates a delegate of the specified type to represent the

specified static method, with the specified behavior on

failure to bind.

CreateDelegate(Type, Type, String)

Creates a delegate of the specified type that represents

the specified static method of the specified class.

Page 22: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 22/51

Asiminoaei Ioan

CreateDelegate(Type, Object, MethodInfo, Boolean)

Creates a delegate of the specified type that represents

the specified static or instance method, with the

specified first argument and the specified behavior on

failure to bind.

CreateDelegate(Type, Object, String, Boolean)

Creates a delegate of the specified type that represents

the specified instance method to invoke on the specified

class instance with the specified case-sensitivity.

CreateDelegate(Type, Type, String, Boolean)

Creates a delegate of the specified type that represents

the specified static method of the specified class, with

the specified case-sensitivity.

CreateDelegate(Type, Object, String, Boolean, Boolean)

Creates a delegate of the specified type that represents

the specified instance method to invoke on the specified

class instance, with the specified case-sensitivity and the

specified behavior on failure to bind.

CreateDelegate(Type, Type, String, Boolean, Boolean)

Creates a delegate of the specified type that represents

the specified static method of the specified class, with

the specified case-sensitivity and the specified behavior

on failure to bind.

si in final

public class Delegate {

// Invocare metoda callback a obiectului delegate, // pasindu-i parametrii la runtime public Object DynamicInvoke(Object[] args);

}

Toate metodele CreateDelegate construiesc un obiect nou de tip Delegate,

identificat de primul parametru de tip Type.

Ceilalti parametri determina metoda callback pe care obiectul derivat din Delegate o va

implementa precum si informatii auxiliare.

Metoda DynamicInvoke ne permite sa invocam o metoda callback a obiectului

delegate, pasindu-i parametrii la runtime.

DynamicInvoke face un control al parametrilor (acelasi numar, acelasi tip, aceeasi

pozitie) pentru metoda callback invocata. In caz de esec se genereaza o exceptie.

DynamicInvoke returneaza obiectul returnat de metoda callback.

Exemplu (MSDN) using System; using System.Reflection; using System.Security.Permissions;

Page 23: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 23/51

Asiminoaei Ioan

// Declare three delegate types for demonstrating // the combinations of static versus // instance methods and open versus closed delegates. // public delegate void D1(C c, string s); public delegate void D2(string s); public delegate void D3(); // // A sample class with an instance method and a static method. // public class C { private int id; public C(int id) { this.id = id; } public void M1(string s) { Console.WriteLine("Instance method M1 on C: id = {0}, s = {1}",this.id, s); } public static void M2(string s) { Console.WriteLine("Static method M2 on C: s = {0}", s); } } // End of class C // Clasa de test public class Example { public static void Main() { C c1 = new C(42); // Get a MethodInfo for each method. // metoda a instantei MethodInfo mi1 = typeof(C).GetMethod("M1", BindingFlags.Public | BindingFlags.Instance); // metoda statica MethodInfo mi2 = typeof(C).GetMethod("M2", BindingFlags.Public | BindingFlags.Static); D1 d1; // D1(C c, string s) D2 d2; // D2(string s) D3 d3; // D3()

Page 24: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 24/51

Asiminoaei Ioan

Console.WriteLine("\nAn instance method closed over C."); // Trebuie sa furnizam instanta clasei ce contine // metoda callback // In this case, the delegate and the // method must have the same list of argument types; use // delegate type D2 with instance method M1. // Delegate test = Delegate.CreateDelegate(typeof(D2), c1, mi1, false); // Because false was specified for throwOnBindFailure // in the call to CreateDelegate, the variable 'test' // contains null if the method fails to bind (for // example, if mi1 happened to represent a method of // some class other than C). // if (test != null) { d2 = (D2)test; // atribuire metoda callback // The same instance of C is used every time the // delegate is invoked. d2("Hello, World!"); d2("Hi, Mom!"); } Console.WriteLine("\nAn open instance method."); // Cream delegate fara a furniza instanta clasei // ce contine metoda callback. Instanta clasei o // vom furniza in momentul apelului metodei callback. // In this case, the delegate has one more // argument than the instance method; this argument comes // at the beginning, and represents the hidden instance // argument of the instance method. Use delegate type D1 // with instance method M1. // d1 = (D1) Delegate.CreateDelegate(typeof(D1), null, mi1); // An instance of C must be passed in each time the // delegate is invoked. // d1(c1, "Hello, World!"); d1(new C(5280), "Hi, Mom!"); Console.WriteLine("\nAn open static method.");

Page 25: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 25/51

Asiminoaei Ioan

// In this case, the delegate and the method must // have the same list of argument types; // use delegate type D2 with static method M2. // d2 = (D2) Delegate.CreateDelegate(typeof(D2), null, mi2); // No instances of C are involved, // because this is a static method. // d2("Hello, World!"); d2("Hi, Mom!"); Console.WriteLine("\nA static method closed “ + “ over the first argument (String)."); // The delegate must omit the first argument // of the method. // A string is passed as the firstArgument parameter, and // the delegate is bound to this string. // Use delegate type D3 with static method M2. // d3 = (D3) Delegate.CreateDelegate(typeof(D3), "Hello, World!", mi2); // Each time the delegate is invoked, the same string is // used. d3(); } }

Page 26: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 26/51

Asiminoaei Ioan

Creare delegates generici

Ideea este de a construi delegates generici si pe baza acestora sa definim un delegate

concret.

Studiu de caz

Un delegate ce mapeaza o functie ce are un singur parametru si returneaza void.

Observatie

Vedeti si alte situatii date mai jos ca exemplu.

Daca parametrul este diferit de la metoda la metoda putem construi urmatorul delegate

generic :

namespace GenericDelegate {

public delegate void GenericDelegate<T>(T arg); class Program {

static void Main(string[] args) {

Console.WriteLine("***** Generic Delegates *****\n"); // Specificam o metoda ce are ca parametru un string GenericDelegate<string> strTarget = new GenericDelegate<string>(StringTarget); strTarget("Some string data"); // Specificam o metoda ce are ca parametru un int GenericDelegate<int> intTarget = new MyGenericDelegate<int>(IntTarget); intTarget(9); Console.ReadLine();

} static void StringTarget(string arg) {

Console.WriteLine("arg in uppercase is: {0}", arg.ToUpper());

} static void IntTarget(int arg) {

Console.WriteLine("++arg is: {0}", ++arg); } }

}

Page 27: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 27/51

Asiminoaei Ioan

Mai multe exemple:

namespace DelegateAsincronAndGeneric {

public delegate void ActiuneDelegate<T>(T value);

public delegate T DelegateT<T>(T t); public delegate U DelegateTU<T, U>(T t); class CreateDelegate { public ActiuneDelegate<string> md; public DelegateT<string> dt; public DelegateTU<string, int> udt; public int MIntStr(string str) { return str.Length; } public string MetodaGenericDelegate(string str) { return "Modificat " + str; } public void Metoda(string str) { Console.WriteLine("CreateDelegate.Metoda {0}", str); } // nu e necesar sa punem in ctor // E numai in scop demonstrativ // public CreateDelegate(string str) { md = this.Metoda; dt = this.MetodaGenericDelegate; udt = this.MIntStr; } } }

In clasa de test putem scrie:

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

Page 28: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 28/51

Asiminoaei Ioan

namespace DelegateAsincronAndGeneric { class Program { static void Main(string[] args) { CreateDelegate cd = new CreateDelegate("Info"); // // Schimbam metoda callback pt ActiuneDelegate //

cd.md = (str) => { Console.WriteLine("Delegate Lambda: " +str); };

cd.md("Iasi"); // // Pentru DelegateTU atasam metoda MIntStr // Este metoda a instantei deci avem nevoie de // instanta tipului unde este definita metoda

Program p = new Program();

cd.udt = p.MIntStr; // // Pentru DelegateT metoda este cea furnizata in clasa // CreateDelegate si atasata in ctor // Console.WriteLine(

cd.dt("Vaslui") + " Length = " + cd.udt("Vaslui"));

} public int MIntStr(string str) { return str.Length + 20; } } }

si un delegate cu doi parametri generici:

public delegate DelegateEventHandler<T,U>(T sender, U eventArgs) ;

Page 29: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 29/51

Asiminoaei Ioan

Simulare delegates generici fara a folosi generic

Putem face acest lucru prin a crea un delegate ce mapeaza o functie ce are un parametru

de tip Object. In acest caz exista boxing si unboxing.

public delegate void NonGenericDelegate(object arg);

class Program {

static void Main(string[] args) {

... NonGenericDelegate d =

new NonGenericDelegate(MyTarget); d("More string data"); NonGenericDelegate d2 = MyTarget; d2(9); // Penalizare boxing. Console.ReadLine();

} // Trebuie sa facem conversie la tipul pe care il asteptam static void MyTarget(object arg) {

if(arg is int) {

int i = (int)arg; // Penalizare unboxing. Console.WriteLine("++arg is: {0}", ++i);

} if(arg is string) {

string s = (string)arg; // Nu avem unboxing Console.WriteLine("arg in uppercase is: {0}", s.ToUpper());

} }

}

Page 30: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 30/51

Asiminoaei Ioan

Evenimente

Membrul event al unei clase permite acesteia de a notifica alte obiecte ca ceva s-a

intamplat.

Un tip ce defineste un membru event are urmatoarele capabilitati:

• capabilitatea obiectelor de a-si inregistra interesul lor pentru un evenimet;

• capabilitatea de a renunta la un eveniment (stergerea inregistrarii);

• capabilitatea obiectului ce defineste evenimentul de a mentine o lista a obiectelor

inregistrate pentru eveniment si de a le notifica acestora producerea

evenimentului.

Exemplu de declarare event :

// declarare delegate pentru gestionare eveniment click delegate void ButtonEventHandler(object source,int clickCount);

// declaram evenimentul public event ButtonEventHandler ButtonClick;

Modelul eveniment al CLR-ului este bazat pe delegates.

Exemplu

Consideram clasa Button pentru care dorim sa tratam mesajul generat de evenimentul clic

pe acesta. using System; // declarare delegate pentru gestionare eveniment click delegate void ButtonEventHandler(object source,int clickCount); class Button { // declaram evenimentul public event ButtonEventHandler ButtonClick; //Functia ce genereaza evenimentul public void Clicked(int count) { Console.WriteLine("\nInside Clicked !!!"); //Invocarea tuturor metodelor atasate pentru eveniment if (ButtonClick != null) ButtonClick(this,count); } }

Page 31: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 31/51

Asiminoaei Ioan

// In clasa Dialog se foloseste tipul Button public class Dialog { public Dialog() { Button b = new Button(); // Adaugam metoda pentru tratatre eveniment b. ButtonClick += new ButtonEventHandler( OnButtonAction); //Generare eveniment b.Clicked(1); b.ButtonClick += new ButtonEventHandler(OnButtonAction); b.Clicked(1); //Eliminare metoda ce trateaza evenimentul b.ButtonClick -= new ButtonEventHandler(onButtonAction); b.Clicked(1); b.ButtonClick -= new ButtonEventHandler(onButtonAction); b.Clicked(1); } // Clasa de test static void Main() { new Dialog(); } // Functia (metoda) pentru tratarea evenimentului public void onButtonAction(object source,int clickCount) { Console.WriteLine("Inside Event Handler !!!"); } }

Page 32: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 32/51

Asiminoaei Ioan

Definirea evenimentelor cu MulticastDelegates

Pattern-ul Publish / Subscribe (Event)

Clasa din FCL este MulticastDelegates.

O instanta a acestei clase reprezinta un delegate ce are mai multe elemente in lista de

invocare.

Compilatorul poate deriva din aceasta clasa, dar noi in cod nu putem face explicit acest

lucru. La fel si pentru clasa Delegate.

CLR furnizeaza doua metode speciale: BeginInvoke si EndInvoke folosite in apelul

asincron.

Observatie

Cand este invocat un delegate de acest tip (multicast), delegates din lista de invocare sunt

apelati in mod sincron in ordinea in care apar in lista. Daca apare o eroare in timpul

executiei listei de delegates se genereaza o exceptie.

Aplicatiile Windows au nevoie sa proceseze evenimente in mod asincron. Evenimentele

genereaza mesaje, iar mesajele au atasate functii ce le trateaza.

Modelul delegate multicast are la baza pattern-ul Publish/Subscribe, in care o clasa

publica un eveniment pe care-l poate genera, si un alt numar de clase subscriu pentru

acest eveniment.

Cand evenimentul a fost generat, runtime-ul are grija sa notifice producerea

evenimentului fiecarei clase ce asteapta acel eveniment.

Metoda apelata ca rezultat al producerii unui eveniment este definita de un delegate.

Cand folosim delegate in acest mod, trebuie sa respectam urmatoarele reguli:

1. Delegate trebuie definit ca avand doi parametri.

2. Argumentele reprezinta totdeauna doua obiecte: obiectul ce a generat

evenimentul, si un obiect de tip EventArgs sau derivat din EventArgs.

3. Al doilea parametru trebuie sa fie derivat din clasa EventArgs.

Page 33: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 33/51

Asiminoaei Ioan

Descriere pattern Publish / Subscribe sau pattern Event

Modelul logic al patern-ului observer implica doua entitati : Observer si Subiect.

Observer : responsabil pentru « afisarea » datelor catre utilizator.

Subiect : reprezinta modelul problemei. Cand apare o modificare in Subiect, Observer-ul

observa aceasta modificare si executa actiunea « programata ».

Modelul fizic

Observer :

Observer-ul isi exprima interesul fata de Subiect pentru anumite notificari, deci acesta se

inregistreaza (Register / Attach) la Subiect cu o anumita cerinta.

Observer-ul trebuie sa aiba si posibilitatea renuntarii de a fi notificat pentru o anumita

cerinta – (Unregister / Detach).

Observer-ul instiinteaza Subiect despre metoda ce va trebui apelata cand apare

evenimentul monitorizat (OnNotify).

Subiect :

Inregistreaza / elimina observerii interesati de un anumit eveniment ; uzual metodele

Register / Attach, Unregister / Detach).

Notifica observer despre aparitia evenimentului (Notify).

.NET furnizeaza urmatoarele interfete pentru acest pattern :

1. Interfata IObserver<T> public interface IObserver<in T>

Interfata IObserver<T> reprezinta clasa ce primeste notificari. T reprezinta clasa ce

furnizeaza informatia de notificare. Furnizorul informatiei este dat de clasa ce

implementeaza interfata IObservable<T>.

Interfata IObserver<T> defineste urmatoarele metode pe care observerul trebuie sa le

implementze :

• Metoda OnNext, ce este apelata de “provider” pentru a furniza informatii catre

observer.

• Metoda OnError, apelata de “provider” pentru a indica ca informatia nu este

disponibila, au aparut anumite erori.

• Metoda OnCompleted, apelata de provider pentru a semnala ca a terminat

trimiterea notificarilor la observeri.

Page 34: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 34/51

Asiminoaei Ioan

public class Observer : IObserver<Tip_clasa_struct> { public void OnNext(Tip_clasa_struct value) { } public void OnError(Exception error) { } public void OnCompleted() { } }

2. Interfata IObservable<T> : furnizeaza informatia de notificare

public interface IObservable<out T>

T trebuie sa fie acelasi in IObserver si IObservable.

Provider-ul trebuie sa implementeze o singura metoda, Subscribe ce indica faptul ca un

observer doreste sa fie notificat. Apelantul acestei metode trebuie sa paseze o instanta a

observerului.

Exemplu (MSDN): public enum LocationStatus { Started = 1, EnRoute = 2, Finished = 3 }; public struct Location { public readonly decimal Latitude; public readonly decimal Longitude; public readonly DateTime DateAndTime; public readonly LocationStatus Status; public Location(decimal lat, decimal lon, DateTime dateAndTime, LocationStatus status) { this.Latitude = lat; this.Longitude = lon; this.DateAndTime = dateAndTime; this.Status = status; } }

public class LocationSimulator : IObservable<Location> { List<IObserver<Location>> observers = new List<IObserver<Location>>(); Location _location, _lastLocation, _startLocation;

Page 35: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 35/51

Asiminoaei Ioan

public static LocationSimulator SetStartingLocation() { return new LocationSimulator(42.2857m, -83.7213m, LocationStatus.Started); } private LocationSimulator(decimal latitude, decimal longitude, LocationStatus status) { _location = new Location(latitude, longitude, DateTime.UtcNow, status); _lastLocation = _location; if (status == LocationStatus.Started) _startLocation = _location; } public Location Location { get { return this._location; } } public Location GetCurrentLocation() { Random rnd = new Random(); decimal newLat = _location.Latitude + rnd.Next(-1, 2); decimal newLong = _location.Longitude + rnd.Next(-1, 2); // Assume arrival if the difference in latitude is 3. _lastLocation = _location; LocationStatus status = Math.Abs(_startLocation.Latitude – newLat) >= 3 ? LocationStatus.Finished : LocationStatus.EnRoute; _location = new Location(_location.Latitude + rnd.Next(-1, 2), _location.Longitude + rnd.Next(-1, 2), DateTime.UtcNow, status); if (! _location.Equals(_lastLocation)) { // Notify observers. foreach (IObserver<Location> observer in observers) { observer.OnNext(this.Location); // Assume that we've arrived at location of // Latitude has changed by 4. if (_location.Status == LocationStatus.Finished) observer.OnCompleted(); } } return this.Location; } public IDisposable Subscribe(IObserver<Location> observer) { observers.Add(observer); // Announce current location to new observer. observer.OnNext(this.Location); return observer as IDisposable; } }

Page 36: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 36/51

Asiminoaei Ioan

public class LocationDisplay : IObserver<Location> { public void OnNext(Location value) { Console.WriteLine("{3}At {0}, Latitude = {1:N4}, Longitude = {2:N4}", value.DateAndTime, value.Latitude, value.Longitude, value.Status == LocationStatus.Started ? "Starting " : ""); } public void OnError(Exception error) { Console.WriteLine("Unable to determine the current location."); } public void OnCompleted() { Console.WriteLine("Finished tracking the current location."); } }

public class Example { public static void Main() { LocationSimulator simulator = LocationSimulator.SetStartingLocation(); // Subscribe with class that implements IObserver<Location> IDisposable d = simulator.Subscribe(new LocationDisplay()); Location loc; do { loc = simulator.GetCurrentLocation(); Thread.Sleep(2500); } while (loc.Status != LocationStatus.Finished); } }

Page 37: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 37/51

Asiminoaei Ioan

Pattern Observer folosind delegates

Exemplu:

public class Info {

// delegate pentru eveniment public delegate void InfoDelegate(object obj); // event ce foloseste delegate InfoDelegate public event InfoDelegate InfoChanged; // data membru object _obiect; public object SetInfo { set

{ _obiect = value; // genereaza eveniment InfoChanged(_obiect); }

} } public class InfoDisplay { public void InfoChanged(object obj)

{ Console.WriteLine(“Info changed”); }

} public class Test { public static void Main()

{ InfoDisplay infodisplay = new InfoDisplay();

Info info = new Info(); // inregistrare metoda callback pentru event

Info.InfoDelegate del = new Info.InfoDelegate(InfoDisplay.InfoChanged); info.InfoChanged += del; // schimbare stare in Info info.SetInfo = "changed"; // unregister info.InfoChanged -= del;} }

Page 38: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 38/51

Asiminoaei Ioan

Pattern Publish / Subscribe sau Event - implementare

Schema generala a cestui pattern este data in urmatorul cod (partial MSDN).

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace EventPattern { public class Stoc { // declar delegate pt eveniment public delegate void AskPriceChangedHandler(object sender,

AskPriceChangedEventArgs e); // declar event public event AskPriceChangedHandler AskPriceChanged; // data membru object _askPrice; // proprietate public object AskPrice { set { _askPrice = value; // generare event OnAskPriceChanged(); } } // metoda ce genereaza evenimentul protected void OnAskPriceChanged() { AskPriceChanged(this,

new AskPriceChangedEventArgs(_askPrice)); } } // clasa Stoc // parametrii evenimentului public class AskPriceChangedEventArgs : EventArgs { private object _askPrice; // ctor public AskPriceChangedEventArgs(object askPrice) { _askPrice = askPrice; } public object AskPrice { get {

Page 39: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 39/51

Asiminoaei Ioan

return _askPrice; } } } // AskPriceChangedEventArgs }

iar clasa de test poate fi urmatoarea:

class MainStoc { static void Main(string[] args) { Stoc s = new Stoc(); s.AskPriceChanged +=new Stoc.AskPriceChangedHandler(s_AskPriceChanged); s.AskPrice = 100; } static void s_AskPriceChanged(object sender, AskPriceChangedEventArgs e) { Console.WriteLine("Stoc display: {0}", e.AskPrice); //throw new NotImplementedException(); } }

Exemplu din Inside C# Second Edition – Tom Archer

Observati diferenta la constructori.

Consideram urmatorul exemplu. Dorim sa proiectam o aplicatie pentru e-mail.

Cand soseste un mesaj, utilizatorul doreste ca acesta sa fie redirectionat (forward) catre

un fax sau un pager.

Construim urmatoarele tipuri:

MailManager, ce primeste mesajele e-mail. MailManager va expune un eveniment numit

MailMsg.

Alte tipuri (Fax, Pager) trebuie sa-si manifeste interesul fata de acest eveniment.

Cand se primeste un e-mail, MailManager va produce evenimentul, distribuind mesajul

catre clasele ce s-au inregistrat pentru acest mesaj.

Fiecare obiect proceseaza mesajul dupa cum doreste.

Page 40: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 40/51

Asiminoaei Ioan

Proiectarea unui tip ce expune un eveniment

Pattern-ul recomandat de Microsoft pentru definirea unui eveniment este urmatorul :

Etapa 0 : Definire tip ce va contine event. (class MailManager).

Etapa 1 : Definirea unui tip imbricat, derivat din EventArgs, tip ce va contine

informatia ce va fi pasata obiectelor interesate de acest eveniment public class MailMsgEventArgs : EventArgs Etapa 2 : Definim tipul delegate ce ne va da prototipul metodei callback pe care apelatii vor

trebui sa o implementeze

public delegate void MailMsgEventHandler(

Object sender, MailMsgEventArgs args);

Etapa 3: Declararea datei membru event

public event MailMsgEventHandler MailMsg;

Etapa 4: Definirea metodei responsabila cu notificarea clientilor despre aparitia

evenimentului

protected virtual void OnMailMsg(MailMsgEventArgs e)

Etapa 5: Definirea metodei ce identifica daca evenimentul a aparut sau nu:

public void SimulateArrivingMsg( String from, String to, String subject, String body)

Exemplu: class MailManager {

// Tipul MailMsgEventArgs este definit in interiorul tipului // MailManager

public class MailMsgEventArgs : EventArgs {

public readonly String from, to, subject, body; // 1. Parametrul evenimentului public MailMsgEventArgs(

String from, String to, String subject, String body)

{ this.from = from;

Page 41: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 41/51

Asiminoaei Ioan

this.to = to; this.subject = subject; this.body = body; }

}

// 2. Tipul delegate – prototipul pentru callback // Metoda trebuie implementata de clienti public delegate void MailMsgEventHandler(

Object sender, MailMsgEventArgs args); // 3. Evenimentul public event MailMsgEventHandler MailMsg; // 4. Metoda responsabila pentru notificarea obiectelor // inregistrate pentru acest eveniment protected virtual void OnMailMsg(MailMsgEventArgs e) {

if (MailMsg != null) {

MailMsg(this, e); }

}

// 5. Metoda este apelata cand apare un mesaj e-mail public void SimulateArrivingMsg(String from, String to,

String subject, String body) {

// Construim parametrul evenimentului MailMsgEventArgs e = new MailMsgEventArgs(from, to, subject, body); // Notificam clientul ca a aparut un e-mail OnMailMsg(e);

} }

Codul critic se gaseste in clasa MailManager.

Dezvoltatorul trebuie sa defineasca urmatoarele articole:

1. Sa defineasca un tip ce va mentine informatii aditionale ce ar trebui trimise celor ce

asteapata notificarea evenimentului. Tipurile ce mentin informatia despre un eveniment

sunt derivate din System.EventArgs, si numele tipului ar trebui sa se termine cu

EventArgs. In exemplul nostru, tipul MailMsgEventArgs contine campuri ce idetifica cine

a trimis mesajul (from), cine primeste mesajul (to), subiectul mesajului (subject) si corpul

mesajului (body).

Page 42: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 42/51

Asiminoaei Ioan

EventArgs este definita in FCL astfel: [Serializable] public class EventArgs {

public static readonly EventArgs Empty = new EventArgs(); public EventArgs() { }

}

Acesta serveste ca un tip de baza din care alte tipuri pot deriva.

Exista si evenimente care nu au informatii aditionale de transmis (clic pe un buton).

Cand definim un eveniment ce nu are informatii aditionale de transmis putem folosi

EventArgs.Empty in loc de a construi un nou obiect EventArgs.

2. Definim un tip delegate, specificand prototipul metodei ce va fi apelata cand se

genereaza evenimentul. Prin conventie numele delegate se termina cu EventHandler.

Prototipul trebuie sa returneze void si sa aiba doi parametri. Primul parametru este un

Object ce se refera la la obiectul ce a trimis notificarea, iar al doilea parametru este un

tip derivat din EventArgs ce contine informatii aditionale despre notificare.

Prototipul pentru EventHandler este urmatorul: public delegate void EventHandler(Object sender, EventArgs e);

3. Definim un eveniment, MailMsg, de tip MailMsgEventHandler, deci metoda callback

trebuie sa aiba acest prototip.

4. Definim o metoda virtuala, protected, metoda responsabila pentru notificarea

obiectelor inregistrate sa primeasca acest eveniment. Metoda OnMailMsg este apelata

cand un nou mesaj soseste.

Aceasta metoda primeste un obiect MailMsgEventArgs initializat ce contine informatii

aditionale despre eveniment.

Aceasta metoda verifica daca exista cineva interesat de acest eveniment pentru a da

drumul evenimentului.

Un tip ce foloseste MailManager ca tip de baza poate suprascrie metoda OnMailMsg.

5. Definim o metoda ce transforma intrarea in evenimentul dorit.

In exemplul nostru metoda SimulatingArrivingMsg este apelata pentru a indica ca un

mesaj nou a sosit in MailManager.

6. Sa examinam indeaproape ce inseamna sa definim un event MailMsg.

public event MailMsgEventHandler MailMsg;

Compilatorul C# transforma aceasta linie de cod in: // 1. Referinta la inceputul listei de delegates

Page 43: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 43/51

Asiminoaei Ioan

private MailMsgEventHandler MailMsg = null; // 2. A PUBLIC add_* method // Allows objects to register interest in the event. [MethodImplAttribute(MethodImplOptions.Synchronized)] public void add_MailMsg(MailMsgEventHandler handler) {

MailMsg = (MailMsgEventHandler)Delegate.Combine( MailMsg, handler);

} // 3. A PUBLIC remove_* method // Allows objects to unregister interest in the event. [MethodImplAttribute(MethodImplOptions.Synchronized)] public void remove_MailMsg(MailMsgEventHandler handler) {

MailMsg = (MailMsgEventHandler) Delegate.Remove(MailMsg, handler);

}

Cand un obiect este interesat de eveniment, acest camp referentiaza o instanta a delegate

MailMsgEventHandler.

Fiecare instanta delegate MailMsgEventHandler are un pointer la un alt delegate

MailMsgEventHandler sau la null pentru a marca sfarsitul listei.

Page 44: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 44/51

Asiminoaei Ioan

Proiectarea unui tip ce asteapta pentru un eveniment

Exemplu class Fax {

// Pass the MailManager object to the constructor. public Fax(MailManager mm) {

// Indicam metoda ce va fi apelata cand soseste un e-mail mm.MailMsg+= new MailManager.MailMsgEventHandler(FaxMsg);

} // Aceasta este metoda pe care MailManager o va apela pentru // a notifica obiectul Fax ca a sosit un nou e-mail. private void FaxMsg(

Object sender, MailManager.MailMsgEventArgs e) {

// ‘sender’ identifica MailManager Console.WriteLine("Faxing mail message:"); Console.WriteLine( " To: {0}\n From: {1}\n Subject: {2}\n Body: {3}\n", e.from, e.to, e.subject, e.body);

} public void Unregister(MailManager mm) {

// Construct an instance of the MailMsgEventHandler // delegate that refers to the FaxMsg callback method. MailManager.MailMsgEventHandler callback = new MailManager.MailMsgEventHandler(FaxMsg); // Unregister with MailManager’s MailMsg event. mm.MailMsg -= callback;

} }

Cand aplicatia de e-mail se initializeaza, va construi mai intai un obiect MailManager si

va salva referinta la acest obiect intr-o variabila.

In continuare se construieste un obiect de tip Fax, pasindu-i referinta la obiectul

MailManager.

In ctor Fax se construieste un nou obiect delegate MailManager.MailMsgEventHandler

care este un wrapper pentru metoda FaxMsg din Fax ce are acelasi prototip ca

MailMsgEventHandler (altfel codul nu se compileaza).

In continuare obiectul Fax se inregistreaza pentru evenimentul MailMsg din

mailManager :

mm.MailMsg += new MailManager.MailMsgEventHandler(FaxMsg);

Page 45: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 45/51

Asiminoaei Ioan

Compilatorul C# va transforma operatorul += in urmatoarea linie de cod pentru a adauga

interesul obiectului pentru eveniment : mm.add_MailMsg(new MailManager.MailMsgEventHandler(FaxMsg));

Aceasta metoda o putem apela si explicit.

Cand MailManager produce evenimentul, obiectul Fax va apela metoda FaxMsg ce

primeste o referinta la un obiect MailManager si o referinta la MailMsgEventArgs.

Referinta la MailManager poate fi folosita pentru a accesa campuri sau metode din

MailManager.

Din obiectul MailMsgEventArgs, metoda FaxMsg are acces la toate caracteristicile

mesajului.

Page 46: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 46/51

Asiminoaei Ioan

Delegates asincroni

Apelul asincron al delegates presupune crearea de catre framework a unui fir de lucru din

ThreadPool. Din acest motiv apelul nu este blocant.

Este posibil ca metoda apelata sa genereze date si sa le returneze. In acest caz exista doua

posibilitati oferite de infrastructura .NET :

� apelantul asteapta explicit aceste date – apel metoda EndInvoke ;

� apelantul este instiintat de apelat ca executia s-a terminat .

Clasa System.MulticastDelegates contine printre altele si metodele IAsyncResult BeginInvoke(...,

AsyncCallback asc, object stateObject);

EndInvoke(..., IAsyncResult);

folosite in apelul asincron al delegates-lor.

Observam ca aceste metode returneaza sau au ca parametru un tip IAsyncResult, care

e definit ca o interfata.

• IAsyncResult reprezinta statusul unei operatii asincrone.

• IAsyncResult este implementata de clase ce contin metode ce pot opera in mod

asincron.

• IAsyncResult este tipul returnat de o metoda ce initiaza o operatie asincrona si

este un parametru al metodei ce verifica terminarea operatiei asincrone (in mod

normal metode ce incep cu Begin... si End...).

• Un obiect de tip IAsyncResult este pasat metodelor invocate de delegates

AsyncCallback cand o operatie asincrona s-a terminat de executat.

• Un obiect ce suporta interfata IAsyncResult memoreaza informatie de stare

pentru o operatie asincrona si furnizeaza un obiect de sincronizare ce permite

firelor sa fie semnalate cand operatia s-a terminat.

Clasa AsyncResult este implementarea interfetei IAsyncResult ce este returnata de

metoda BeginInvoke cand folosim un delegate pentru a apela o metoda in mod

asincron.

Page 47: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 47/51

Asiminoaei Ioan

public interface IAsyncResult { // Furnizeaza un obiect definit de utilizator

// sau contine informatii despre o operatie asincrona

object AsyncState { get; }

// Returneaza un WaitHandle folosit pentru a astepta // terminarea unei operatii asincrone. // Valoarea returnata poate fi folosita pentru // a executa operatii WaitOne, WaitAny sau WaitAll

WaitHandle AsyncWaitHandle { get; }

// Returneaza o valoare ce indica daca operatia

// asincrona s-a terminat in mod sincron

bool CompletedSynchronously { get; } // Returneaza o valoare ce indica daca operatia

// asincrona a fost terminata bool IsCompleted { get; }

}

Clasa AsyncResult

Incapsuleaza rezultatele unei operatiuni asincrone pe un delegate.

Namespace: System.Runtime.Remoting.Messaging

Assembly: mscorlib (in mscorlib.dll)

[ComVisibleAttribute(true)] public class AsyncResult : IAsyncResult, IMessageSink

Observatie

IAsyncResult returnat de metoda BeginInvoke poate fi convertit (cast) la

AsyncResult. AsyncResult are proprietatea AsyncDelegate ce mentine obiectul

delegate pe care a fost facut apelul asincron.

Metoda BeginInvoke este folosita pentru a initia un apel asincron. Are aceeasi

parametri ca metoda pe care dorim sa o executam asincron, plus alti doi parametri ce

specifica metoda ce se va apela cand se termina BeginInvoke si un obiect ce transmite

informatii aditionale.

EndInvoke (metoda blocanta) este folosita pentru a regasi rezultatele unui apel asincron.

Poate fi apelata dupa apelul lui BeginInvoke.

Page 48: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 48/51

Asiminoaei Ioan

Dupa ce am apelat BeginInvoke putem:

� Sa executam alt cod si apoi sa apelam EndInvoke pentru a obtine rezultatul.

� Sa obtinem un Waithandle folosind IAsyncResult.AsyncWaitHandle, si sa

folosim metoda WaitOne pentru a bloca executia pana cand WaitHandle este

semnalat, si apoi sa apelam EndInvoke.

� Sa indicam o metoda callback (in BeginInvoke), metoda ce va fi apelata cand se

termina executia lui BeginInvoke, si putem apela EndInvoke.

Exemplu

1. Instantiem un delegate ce contine metoda pe care dorim sa o rulam in paralel (in mod

obisnuit unul din delegates predefiniti Func).

2. Apelam BeginInvoke pe delegate, salvand valoarea de retur de tip IAsyncResult.

BeginInvoke returneaza imediat catre apelant, deci putem executa alt cod in continuare.

3. Cand avem nevoie de rezultat, apelam EndInvoke pe delegate, pasand ca valoare

obiectul de tip IAsyncResult, salvat anterior.

static void Main() {

// string – tipul parametrului din metoda Work // int – tipul returnat de metoda Work

Func<string, int> method = Work; IAsyncResult cookie = method.BeginInvoke ("test",

null, null); // // ... cod ce poate fi executat dupa apelul BeginInvoke // // asteptam terminarea executiei metodei Work // si preluam rezultatul int result = method.EndInvoke (cookie); Console.WriteLine ("String length is: " + result);

} static int Work (string s) {

return s.Length; }

Cazul cand penultimul parametru din BeginInvoke este completat, se indica metoda ce

va fi apelata cand s-au terminat calculele.

static void Main() {

Func<string, int> metoda = Work; method.BeginInvoke ("test", Done, metoda);

Page 49: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 49/51

Asiminoaei Ioan

// ... //

} static int Work (string s) { return s.Length; } static void Done (IAsyncResult cookie) {

// ultimul parametru din BeginInvoke este de tip delegate var target = (Func<string, int>) cookie.AsyncState; int result = target.EndInvoke (cookie); Console.WriteLine ("String length is: " + result);

}

Varianta cand obtinem delegate din AsyncResult (namespace System.Runtime.Remoting.Messaging)

Cod in Main … // delegate de forma Func<int,int,int> add = Add; IAsyncResult iasr = add.BeginInvoke(20, 30, Done, "Gata");

// alta varianta // IAsyncResult iasr = add.BeginInvoke(20, 30, // new AsyncCallback(Done),, "Gata");

Metoda Add

static int Add(int x, int y) { Console.WriteLine("\nAdd runing...\n"); return x + y; }

Metoda Done static void Done (IAsyncResult cookie) { // obtinem delegate pentru a putea apela EndInvoke AsyncResult ar = (AsyncResult)cookie; var target = (Func<int,int,int>)ar.AsyncDelegate;

int result = target.EndInvoke (cookie); // parametrul pasat metodei Done string dummy = (string)cookie.AsyncState; Console.WriteLine ("Done apelata cu {0} si “ +

« result este = {1} ", dummy, result);

Page 50: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 50/51

Asiminoaei Ioan

}

Putem sa ne imaginam urmatoarea schema pentru apelul asincron al delegates (Richard

Grimes):

Numerele din paranteze arata ordinea de executie data de framework.

Sa examinam urmatorul cod : public delegate int CalledDelegate(ref int i); public class Called { public int Time2(ref int i) { i = i * 2; return i; } }

in clasa de test scriem urmatorul cod : Console.WriteLine("\nApel asincron delegates\n"); Called c = new Called();

Apelantul (fir apelant)

Called c = new Called();

CalledDelegate d;

d = new CalledDelegate(c.time2);

IAsyncResult ar;

(1) ar = d.BeginInvoke(42, null, null);

// cod

(3) ar.AsyncWaitHandle.WaitOne();

(5) int res = d.EndInvoke();

CalledDelegate

Metoda = Called.time2;

Target = c;

Rezultat din metoda

Called

int time2(int i)

{ return i *2;}

AsyncThread

2

4

AsyncResult AsyncWaitHandle

Page 51: C5 C6 Delegates - Alexandru Ioan Cuza Universityiasimin/csharp/C5_C6...Ce e cu rosu reprezinta parametrii metodei callback. Metodele Invoke si EndInvoke returneaza void in acest caz.

Delegates

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 24.11.2014 51/51

Asiminoaei Ioan

CalledDelegate d;

// atasare metoda callback d = new CalledDelegate(c.Time2); IAsyncResult ar; int n = 42; // se creaza firul si obiectul de sincronizare // se lanseaza firul

ar = d.BeginInvoke(ref n, null, null); // cod ce se executa in paralel cu delegate asincron Console.WriteLine("cod n = {0}", n); // asteptare terminare delegate ar.AsyncWaitHandle.WaitOne(); // obtinere rezultat int res = d.EndInvoke(ref n,ar); // afisare rezultat Console.WriteLine("Rezultat : {0} si n = {1}",

res, n);

Rezultatul este (observati valoarea lui n nu e modificata inca in instructiunea) : Console.WriteLine("cod n = {0}", n); Apel asincron delegates cod n = 42 Rezultat : 84 si n = 84 Press any key to continue . . .


Recommended