Dai delegati a LINQ con C#

2,308 views

Published on

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

Published in: Education
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,308
On SlideShare
0
From Embeds
0
Number of Embeds
7
Actions
Shares
0
Downloads
136
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

Dai delegati a LINQ con C#

  1. 1. www.manuelscapolan.it LEZIONE 04
  2. 2. • 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
  3. 3. • 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
  4. 4. • 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
  5. 5. • A sua volta MulticastDelegate deriva dalla classe astratta System.Delegate: MulticastDelegate e Delegate 5 La classe MulticastDelegate mantiene una lista concatenata di oggetti delegate
  6. 6. • 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 that represents details of a static method maintained by the delegate Target If the method to be called is defined at the object level (rather than a static method), Target returns an object that represents the method maintained by the delegate. If the value returned from Target equals null, the method to be called is a static member Combine() This static method adds a method to the list maintained by the delegate. In C#, you trigger this method using the overloaded += operator as a shorthand notation GetInvocationList() This method returns an array of System.Delegate objects, each representing a particular method that may be invoked Remove() RemoveAll() These static methods remove a method (or all methods) from the delegate’s invocation list. In C#, the Remove() method can be called indirectly using the overloaded -= operator
  7. 7. • 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
  8. 8. • 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:
  9. 9. • 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
  10. 10. • 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
  11. 11. • 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>>
  12. 12. • 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
  13. 13. • La classe RealProperty Notifiche con i delegati: un esempio 13 Definizione del delegato … Proprietà immobiliare
  14. 14. • 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!
  15. 15. • 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
  16. 16. • … ed ecco la creazione degli oggetti e la definizione delle vendite Notifiche con i delegati: un esempio 16
  17. 17. • L’utilizzo dei delegati per le notifiche non permette di ottenere: – Incapsulamento dei “subscriber”: Posso assegnare direttamente un handler al delegato perdendo 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; =
  18. 18. • 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
  19. 19. • 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
  20. 20. • L’utilizzo della chiave event indica al compilatore di generare la seguente logica di incapsulamento: Eventi “under the cover” 20
  21. 21. • Ecco come cambia il metodo Sale(): Come cambia il codice? 21
  22. 22. • Ecco come cambia il metodo del subscriber: Come cambia il codice? 22 • … e la sottoscrizione all’evento:
  23. 23. • 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
  24. 24. • 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
  25. 25. • Ecco un esempio di come possiamo utilizzare Func< > e Action < >: Func< > e Action< > 25
  26. 26. 1) Realizzare una applicazione che permetta di schedulare delle attività e visualizzi come promemoria degli avvisi (progettare prima il diagramma delle classi) Esercizi 26
  27. 27. • 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
  28. 28. • In C# possiamo usare gli anonymous methods per passare un metodo come parametro Lambda Expressions 28
  29. 29. • 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:
  30. 30. 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
  31. 31. • 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
  32. 32. • 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)
  33. 33. • 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 types comparison true false
  34. 34. • 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
  35. 35. • Come posso ottenere una collezione di anonymous types? – Attraverso un array di tipi anonimi: – Attraverso un workaround: Collection & Anonymous Types 35
  36. 36. • 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
  37. 37. • LINQ è un linguaggio di interrogazione integrato nel codice C# • Un cocktail esplosivo di implicity typed local variables , extension methods , object initializers , lambda expression , e anonymous types : LINQ (Language Integrated Query) 37 1 2 3 4 5 1 2 3 4 5
  38. 38. • 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
  39. 39. • 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
  40. 40. • Tornare dei valori (Projection) con Select: Query Operators: esempi 40 Esempio 1 Esempio 2 B
  41. 41. • Ordinare i risultati con OrderBy e ThenBy, OrderByDescending e ThenByDescending: Query Operators: esempi 41 Esempio 1 Esempio 2 C
  42. 42. • Partizionare i risultati con Take e Skip: Query Operators: esempi 42 Esempio 1 Esempio 2 D
  43. 43. • Invece di scrivere: • Possiamo scrivere (SQL like): Query Expressions 43 QUERY EXPRESSIONS
  44. 44. • Vediamo come cambiano gli esempi precedenti utilizzando le query expressions: Query Expressions: esempi 44 B A
  45. 45. • Vediamo come cambiano gli esempi precedenti utilizzando le query expressions: Query Expressions: esempi 45 C D
  46. 46. Deferred query execution 46 Fino a quando non chiamo l’enumeratore la query non viene eseguita
  47. 47. • LINQ to SQL Deferred query execution 47 Solo al momento della chiamata al MoveNext() dell’enumerator viene eseguita la query TIP: Riutilizzo query con closure
  48. 48. • 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
  49. 49. • 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
  50. 50. • 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
  51. 51. 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
  52. 52. Contatti MANUEL SCAPOLAN website: www.manuelscapolan.it twitter: manuelscapolan e-mail: info@manuelscapolan.it 52

×