Post on 14-Dec-2014
description
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