Dai delegati a LINQ con C#

Preview:

DESCRIPTION

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

Citation preview

www.manuelscapolan.it

LEZIONE 04

• 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

• 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

• 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

• A sua volta MulticastDelegate deriva dalla

classe astratta System.Delegate:

MulticastDelegate e Delegate

5

La classe MulticastDelegatemantiene una lista concatenata di oggetti delegate

• 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

• 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

• 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:

• 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

• 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

• 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>>

• 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

• La classe RealProperty

Notifiche con i delegati: un esempio

13

Definizione del delegato …

Proprietà immobiliare

• 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!

• 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

• … ed ecco la creazione degli oggetti e la

definizione delle vendite

Notifiche con i delegati: un esempio

16

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

=

• 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

• 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

• L’utilizzo della chiave event indica al

compilatore di generare la seguente logica

di incapsulamento:

Eventi “under the cover”

20

• Ecco come cambia il metodo Sale():

Come cambia il codice?

21

• Ecco come cambia il metodo del subscriber:

Come cambia il codice?

22

• … e la sottoscrizione all’evento:

• 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

• 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

• Ecco un esempio di come possiamo utilizzare

Func< > e Action < >:

Func< > e Action< >

25

1) Realizzare una applicazione che

permetta di schedulare delle attività e

visualizzi come promemoria degli avvisi

(progettare prima il diagramma delle

classi)

Esercizi

26

• 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

• In C# possiamo usare gli anonymous methods

per passare un metodo come parametro

Lambda Expressions

28

• 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:

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

• 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

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

• 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

• 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

• Come posso ottenere una collezione di

anonymous types?– Attraverso un array di tipi anonimi:

– Attraverso un workaround:

Collection & Anonymous Types

35

• 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

• 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

• 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

• 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

• Tornare dei valori (Projection) con Select:

Query Operators: esempi

40

Esempio 1

Esempio 2

B

• Ordinare i risultati con OrderBy e ThenBy,

OrderByDescending e ThenByDescending:

Query Operators: esempi

41

Esempio 1

Esempio 2

C

• Partizionare i risultati con Take e Skip:

Query Operators: esempi

42

Esempio 1

Esempio 2

D

• Invece di scrivere:

• Possiamo scrivere (SQL like):

Query Expressions

43

QUERY EXPRESSIONS

• Vediamo come cambiano gli esempi

precedenti utilizzando le query expressions:

Query Expressions: esempi

44

B

A

• Vediamo come cambiano gli esempi

precedenti utilizzando le query expressions:

Query Expressions: esempi

45

C

D

Deferred query execution

46

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

• LINQ to SQL

Deferred query execution

47

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

TIP: Riutilizzo querycon closure

• 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

• 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

• 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

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

Contatti MANUEL SCAPOLAN

website: www.manuelscapolan.it

twitter: manuelscapolan

e-mail: info@manuelscapolan.it

52

Recommended