52
www.manuelscapolan.it LEZIONE 04

Dai delegati a LINQ con C#

Embed Size (px)

DESCRIPTION

Un percorso dai delegate fino a LINQ passando per eventi, anonymous methods e lambda expressions.

Citation preview

Page 1: Dai delegati a LINQ con C#

www.manuelscapolan.it

LEZIONE 04

Page 2: Dai delegati a LINQ con C#

• Un delegato è un tipo che permette di

incapsulare un metodo per poterlo poi

richiamare a run-time

• I delegati assomigliano molto ai puntatori a

funzione del C++ (usati per le callback) con

in più la caratteristica di essere type-safe,

ovvero di poter definire:

– Indirizzo del metodo da invocare

– Parametri di input del metodo (se definiti)

– Valore di ritorno (se presente)

Callback e delegati

2

Page 3: Dai delegati a LINQ con C#

• Per dichiarare un delegato in C# si utilizza la

parola chiave delegate

• Il nome del delegato non è determinante, è

importante invece definire la firma del

metodo al quale verrà fatto puntare

(il metodo potrà essere anche statico)

Dichiarare un delegato

3

Page 4: Dai delegati a LINQ con C#

• In realtà quando definiamo un delegato il

compilatore genera per noi una classe sealed

che eredita da System.MulticastDelegate

Delegati “under the cover”

4

Chiama il metodo “puntato” dal delegato

Page 5: Dai delegati a LINQ con C#

• A sua volta MulticastDelegate deriva dalla

classe astratta System.Delegate:

MulticastDelegate e Delegate

5

La classe MulticastDelegatemantiene una lista concatenata di oggetti delegate

Page 6: Dai delegati a LINQ con C#

• Ecco quindi alcuni membri che troviamo

“gratis” nei nostri delegati:

Membri di System.Delegate

6

Tipo Caratteristiche

Method This property returns a System.Reflection.MethodInfo object thatrepresents details of a static method maintained by the delegate

Target If the method to be called is defined at the object level (rather than astatic method), Target returns an object that represents the methodmaintained by the delegate. If the value returned from Target equalsnull, the method to be called is a static member

Combine() This static method adds a method to the list maintained by thedelegate. In C#, you trigger this method using the overloaded +=operator as a shorthand notation

GetInvocationList() This method returns an array of System.Delegate objects, eachrepresenting a particular method that may be invoked

Remove()RemoveAll()

These static methods remove a method (or all methods) from thedelegate’s invocation list. In C#, the Remove() method can be calledindirectly using the overloaded -= operator

Page 7: Dai delegati a LINQ con C#

• Vediamo un esempio di come possiamo

utilizzare un delegato:

Come utilizzare un delegato

7

Questi metodi soddisfano la firma definita nel delegato

In questo momento chiamo il metodo attraverso il delegato

Metodo statico, ma posso utilizzare anche metodi di istanza

Associo il metodo al delegato

1

2

3

4

Page 8: Dai delegati a LINQ con C#

• In C# 2.0 posso assegnare ad un delegato

direttamente il nome del metodo da dover

chiamare, quindi:

“Delegate inference”

8

invece di:

posso scrivere:

Quando assegno il nome di un metodo al delegato, il compilatore

prima deduce il tipo di delegato, poi verifica che ci sia un metodo

con quel nome e quella firma e infine crea un nuovo delegato del

tipo dedotto come wrapper di quel metodo.

NOTA:

Page 9: Dai delegati a LINQ con C#

• Attraverso i delegati posso passare un

metodo come parametro di un altro metodo:

Passare un metodo come parametro

9

Il metodo accetta come parametro un delegato

Metodi che soddisfano la firma definita dal delegato

Il metodo viene passato attraverso il delegato

Chiamata del metodo

Page 10: Dai delegati a LINQ con C#

• L’utilizzo dei delegati con il pattern observer

ci consente di realizzare facilmente sistemi di

“publish-subscribe”

• Ma vediamo il pattern observer nel dettaglio:

Delegati + pattern observer

10

Page 11: Dai delegati a LINQ con C#

• Software per la gestione di un’asta di beni

immobiliari

Notifiche con i delegati: un esempio

11

Auction

+ Delta : int

+ Open()+ Sale()- Close(property : RealProperty,

higherBidder : Bidder)

Properties

Participants

RealProperty

+ OnSalePriceChange : SalePriceChangeHandler+ Code : int+ Description : string+ StartingPrice : int+ SalePrice : int

+ SalePriceChangeHandler(code : int , price : int) : Tuple<bool, Bidder>+ Sale(delta : int) : Tuple<RealProperty, Bidder>

Bidder

+ FullName : string

+ OnSalePriceChanged(code : int,proposal : int) : Tuple<bool, Bidder>

Bid

+ PropertyCode : int+ MaxProposal : int

Bids

<<delegate>>SalePriceChangeHandler

<<implements>>

Page 12: Dai delegati a LINQ con C#

• La classe Auction

Notifiche con i delegati: un esempio

12

Registro i metodi per la notifica ai partecipanti della vendita di un bene immobiliare

Chiamo la vendita del bene, nell’implementazione verranno chiamati i partecipanti registrati. Il metodo ritorna il compratore, ovvero il partecipante che ha fatto l’offerta più alta

Asta

Page 13: Dai delegati a LINQ con C#

• La classe RealProperty

Notifiche con i delegati: un esempio

13

Definizione del delegato …

Proprietà immobiliare

Page 14: Dai delegati a LINQ con C#

• Il metodo Sale()

Notifiche con i delegati: un esempio

14

Quando ho un solo compratore viene tornato al chiamante per visualizzare la chiusura dell’asta per quel bene

Attraverso GetInvocationList() chiamo tutti gli handler registrati, se il valore di ritorno indica offerta accettata il partecipante viene aggiunto alla lista dei possibili compratori

Non posso chiamare direttamente il delegato, ovvero _OnSalePriceChangeHandler(Code, actualPrice) perché otterrei in risposta solo il valore di ritorno dell’ultimo handler!

Page 15: Dai delegati a LINQ con C#

• La classe Bidder e la classe Bid

Notifiche con i delegati: un esempio

15

Metodo che soddisfa la firma definita dal delegato

Racchiude l’offerta massima del partecipante all’asta per un determinato bene

Se il prezzo attuale di vendita è ancora inferiore alla massima offerta per quel bene, viene fatta una proposta …

Offerta di acquistoCompratore

Page 16: Dai delegati a LINQ con C#

• … ed ecco la creazione degli oggetti e la

definizione delle vendite

Notifiche con i delegati: un esempio

16

Page 17: Dai delegati a LINQ con C#

• L’utilizzo dei delegati per le notifiche non

permette di ottenere:

– Incapsulamento dei “subscriber”:Posso assegnare direttamente un handler al delegatoperdendo tutti gli altri handler che si erano

precedentemente iscritti

– Incapsulamento del “publish”:Posso chiamare direttamente la procedura che notifica i

subscriber

Notifiche con i delegati

17

i += 5;

i = 5;

=

Page 18: Dai delegati a LINQ con C#

• Per risolvere le problematiche viste con i

delegati C# introduce il concetto di eventi

• Un evento fornisce una implementazione del

sistema “publish-subscriber” con un maggior

controllo e più sicurezza per lo sviluppatore

• Possiamo fare tutto questo definendo un

nuovo membro di tipo evento con la parola

chiave event

Eventi

18

Assegno un elenco vuoto di delegati per evitare di controllare se ci sono listener prima di sollevare l’evento

Page 19: Dai delegati a LINQ con C#

• Caratteristiche di un evento:

Definire un evento

19

Dichiarazione evento

Definizione delegato per i subscriber

Classe per il passaggio di informazioni sull’evento da e verso i subscriber

Page 20: Dai delegati a LINQ con C#

• L’utilizzo della chiave event indica al

compilatore di generare la seguente logica

di incapsulamento:

Eventi “under the cover”

20

Page 21: Dai delegati a LINQ con C#

• Ecco come cambia il metodo Sale():

Come cambia il codice?

21

Page 22: Dai delegati a LINQ con C#

• Ecco come cambia il metodo del subscriber:

Come cambia il codice?

22

• … e la sottoscrizione all’evento:

Page 23: Dai delegati a LINQ con C#

• Se la firma del delegato differisce soltanto

per il tipo dei suoi parametri possiamo usare i

generics, come nell’esempio seguente:

Delegati generici

23

Definizione di un delegato generico

Type Inference

Page 24: Dai delegati a LINQ con C#

• Il framework .NET 3.5 definisce una serie di

delegati generici pronti all’uso:

– Possiamo usare System.Func quando abbiamo

bisogno di un delegato con valore di ritorno

– Quando invece vogliamo un delegato senza

valore di ritorno utilizziamo System.Action

Func< > e Action< >

24

Page 25: Dai delegati a LINQ con C#

• Ecco un esempio di come possiamo utilizzare

Func< > e Action < >:

Func< > e Action< >

25

Page 26: Dai delegati a LINQ con C#

1) Realizzare una applicazione che

permetta di schedulare delle attività e

visualizzi come promemoria degli avvisi

(progettare prima il diagramma delle

classi)

Esercizi

26

Page 27: Dai delegati a LINQ con C#

• Molte volte il metodo puntato da un

delegato non viene mai chiamato in altre

parti del programma

• Dal C# 2.0 abbiamo la possibilità di definire

come delegati dei metodi senza nome (detti

appunto anonymous methods):

Anonymous Methods

27

Posso omettere il valore di ritorno

Page 28: Dai delegati a LINQ con C#

• In C# possiamo usare gli anonymous methods

per passare un metodo come parametro

Lambda Expressions

28

Page 29: Dai delegati a LINQ con C#

• Con le lambda expressions otteniamo lo stesso

risultato con una sintassi più concisa:

Lambda Expressions

29

Closure in C#

Si legge “goes to”

Se la lambda expression ha un corpo { } si parla di statement lambda altrimenti si parla di expression lambda

NOTA:

Page 30: Dai delegati a LINQ con C#

2) Realizzare l’algoritmo BubbleSort in modo che

sia applicabile a diversi tipi di dati (es. int e

string, ma anche la nostra classe Book …)

3) Passare all’algoritmo il

metodo di confronto

Esercizi

30

4) Utilizzare le lambda

expression per definire il

metodo di confronto

direttamente nella

chiamata dell’algoritmo

Page 31: Dai delegati a LINQ con C#

• A volte dobbiamo definire delle classi solo

perché quelle che abbiamo non espongono

tutte le informazioni di cui abbiamo bisogno

• Gli anonymous types, introdotti con il C# 3.0

ci permettono di dichiarare e inizializzare un

tipo senza che ad esso sia associata una

definizione di classe

Anonymous Types

31

Non conoscendo a priori il tipo, devo assegnare il valore ad una variabile var , si occuperà il compilatore a creare al volo un tipo e di specializzare quindi i successivi utilizzi della variabile locale

Page 32: Dai delegati a LINQ con C#

• Gli anonymous types sono tipi anonimi per

noi, ma non per il compilatore …

Anonymous Types

32

Codice IL generato dalla compilazione del nostro esempio (ispezionato tramite Reflector)

Page 33: Dai delegati a LINQ con C#

• Il compilatore deduce il tipo di un anonymous

types dalla sua dichiarazione/inizializzazione

• Due anonymous type con la stessa struttura per il

compilatore sono dello stesso tipo

Anonymous Types

33

Anonymous typescomparison

true

false

Page 34: Dai delegati a LINQ con C#

• Introdotti con C# 3.0 i collection initializers

ci permettono di inizializzare una collezione

direttamente durante la creazione di una

istanza

• Il compilatore si occuperà di chiamare il

metodo Add() per aggiungere gli elementi

alla collezione

Collection Initializers

34

Page 35: Dai delegati a LINQ con C#

• Come posso ottenere una collezione di

anonymous types?– Attraverso un array di tipi anonimi:

– Attraverso un workaround:

Collection & Anonymous Types

35

Page 36: Dai delegati a LINQ con C#

• Per essere utilizzata come una collezione una

classe deve almeno implementare

l’interfaccia IEnumerable<T>

• In C# 3.0 implementare l’interfaccia

IEnumerable<T> significa anche avere in

omaggio una serie di extension methods

davvero molto interessanti …

IEnumerable<T>

36

Page 37: Dai delegati a LINQ con C#

• LINQ è un linguaggio di interrogazione integrato

nel codice C#

• Un cocktail esplosivo di implicity typed local

variables , extension methods , object

initializers , lambda expression , e anonymoustypes :

LINQ (Language Integrated Query)

37

1 2

3 4

5

1

2

3

4

5

Page 38: Dai delegati a LINQ con C#

• Gli extension methods che rendono possibili le

interrogazioni LINQ sono detti query operators:

Query Operators

38

Tipo Extension Methods (Query operators)

Filtering OfType, Where

Projection Select, SelectMany

Partitioning Skip, SkipWhile, Take, TakeWhile

Join GroupJoin, Join

Concatenation Concat

Ordering OrderBy, OrderByDescending, Reverse, ThenBy, ThenByDescending

Grouping GroupBy, ToLookup

Set Distinct, Except, Intersect, Union

Conversion AsEnumerable, AsQueryable, Cast, ToArray, ToDictionary, ToList

Equality SequenceEqual

Element ElementAt, ElementAtOrDefault, First, FirstOrDefault, Last, LastOrDefault, Single, SingleOrDefault

Generation DefaultIfEmpty, Empty, Range, Repeat

Quantifiers All, Any, Contains

Aggregation Aggregate, Average, Count, LongCount, Max, Min, Sum

Page 39: Dai delegati a LINQ con C#

• Vediamo con degli esempi come interrogare

una collezione in memoria (LINQ to Objects):

• Filtrare con Where:

Query Operators: esempi

39NOTA: I nomi utilizzati sono stati generati e non si riferiscono in alcun modo a fatti o persone esistenti

A

Page 40: Dai delegati a LINQ con C#

• Tornare dei valori (Projection) con Select:

Query Operators: esempi

40

Esempio 1

Esempio 2

B

Page 41: Dai delegati a LINQ con C#

• Ordinare i risultati con OrderBy e ThenBy,

OrderByDescending e ThenByDescending:

Query Operators: esempi

41

Esempio 1

Esempio 2

C

Page 42: Dai delegati a LINQ con C#

• Partizionare i risultati con Take e Skip:

Query Operators: esempi

42

Esempio 1

Esempio 2

D

Page 43: Dai delegati a LINQ con C#

• Invece di scrivere:

• Possiamo scrivere (SQL like):

Query Expressions

43

QUERY EXPRESSIONS

Page 44: Dai delegati a LINQ con C#

• Vediamo come cambiano gli esempi

precedenti utilizzando le query expressions:

Query Expressions: esempi

44

B

A

Page 45: Dai delegati a LINQ con C#

• Vediamo come cambiano gli esempi

precedenti utilizzando le query expressions:

Query Expressions: esempi

45

C

D

Page 46: Dai delegati a LINQ con C#

Deferred query execution

46

Fino a quando non chiamo l’enumeratore la query non viene eseguita

Page 47: Dai delegati a LINQ con C#

• LINQ to SQL

Deferred query execution

47

Solo al momento della chiamata al MoveNext() dell’enumerator viene eseguita la query

TIP: Riutilizzo querycon closure

Page 48: Dai delegati a LINQ con C#

• Le lambda expression oltre che come

delegate possono essere utilizzate anche

come “informazioni di esecuzione”, ovvero

come expression trees

Expression Trees

48

1

2

1

2

Page 49: Dai delegati a LINQ con C#

• Gli expression trees sono in realtà la chiave per

applicare LINQ a qualsiasi sorgente dati

• L’interfaccia IQueryable<T> è in grado di

ricevere un expression tree ispezionarlo e

decidere cosa eseguire in base al provider LINQ

• Il provider si occupa del parsing dell’expression

tree e di generare il codice da eseguire

• Nel caso di LINQ to SQL per esempio viene

generato codice SQL eseguibile direttamente

su un database relazionale!

• Altri provider: LINQ to XML, LINQ to DataSet, …

IQueryable<T> e LINQ providers

49

Page 50: Dai delegati a LINQ con C#

• Se la collection da interrogare non implementa

IEnumerable<T> (ma solo IEnumerable):

– Utilizzare il metodo Cast< >Se ci sono elementi incompatibili con il tipo richiesto viene

sollevata una InvalidCastException

– Utilizzare il metodo OfType< >Ritorna della collezione solo gli elementi del tipo specificato

Querying non-generic collections

50

Page 51: Dai delegati a LINQ con C#

5) Compilare un elenco di libri con titolo,

data di uscita, ISBN, autori, tipo (es.

giallo o romanzo) e numero di pagine

6) Scrivere una query LINQ che estragga

un elenco in ordine di data di uscita

con titolo del libro e numero di

pagine per i libri di un determinato

autore

7) Scrivere una query LINQ che torni i file

di una directory per estensione

Esercizi

51

Page 52: Dai delegati a LINQ con C#

Contatti MANUEL SCAPOLAN

website: www.manuelscapolan.it

twitter: manuelscapolan

e-mail: [email protected]

52