martedì 30 novembre 2010

Windows Phone 7 Developer Tools – Primo progetto VB

Notizia di ieri l’uscita dei Developer Tools per Windows Phone 7 dedicati agli sviluppatori VB in versione RTW.

Vediamo un brevissimo post su come creare un primo progetto.

Innanzitutto i tools sono installabili da chi possiede una versione compteta di Visual Studio dalla professional in su.

Una volta installati, i tools diventano uno dei tanti progetti presenti nella maschera di creazione di un progetto:

image

Come per la versione C#, abbiamo a disposizione 5 tipologie di progetto:

  • Windows Phone Application : è il template di progetto vuoto che prevede una window iniziale con pochissimi controlli;
  • Windows Phone Databound Application : è il template per le applicazioni di visualizzazione dei dati basate su una lista;
  • Windows Phone Class Library : è il progetto per la realizzazione di un assembly contenente le nostre classi per WP7;
  • Windows Phone Panorama Application : è il template di progetto per le applicazioni basate sul controllo panorama;
  • Windows Phone Pivot Application : è il template di progetto per le applicazioni basate sul controllo pivot.

Selezionato il progetto, Visual Studio crea, come di consueto, tutti i file necessari.

Il progetto generato è del tutto uguale a quello del cugino C# con l’ovvia differenza che il code behind delle windows XAML scritto in VB.

A questo punto il solo freno è la fantasia e sta a noi trovare nuove idee per implementare applicazioni di successo.

Le applicazioni scritte con i developer tools per VB.NET si possono sottomettere al marketplace come accade come le usuali applicazioni per WP7 scritte in C#.

 

domenica 28 novembre 2010

Facciamo lampeggiale l’overlay icon di IE9

IE9 introduce il concetto di “pinned site” (post) con il quale gli sviluppatori possono far sembrare le proprie web application delle applicazioni desktop.

Il fatto che un sito sia “pinnabile” è fornito “di serie” con IE9 cioè qualsiasi sito è agganciabile alla task bar di Windows.

Oltre a questa funzionalità, abbiamo modo di interagire, in un certo qual modo, con l’icona presente nella task bar di Windows grazie a dei metodi Javascript della classe window.external.

In particolare il metodo msSiteModeSetIconOverlay permette di visualizzare una overlay icon (cioè una iconetta in sovraimpressione) sull’icona del sito posizionata nella task bar. Questo ci permette di attrarre l’attenzione dei nostri utenti per segnalare l’accadimento di qualcosa.

L’istruzione:

  1. window.external.msSiteModeSetIconOverlay('/images/red.ico', 'Icona in sovraimpressione!!');

ci permette di visualizzare, al di sopra dell’icona del nostro sito “pinned”, l’icona red.ico.

L’istruzione ha l’effetto desiderato se la pagina da cui è stata invocata è stata aperta utilizzando l’icona della task bar e le icone della task bar siano nel formato “grande”.

In caso positivo otteniamo una cosa del genere:

image

Possiamo utilizzare qualsiasi formato di icona poichè ci pensa IE9 ad ridimensionare opportunamente l’icona da noi utilizzata.

Inoltre possiamo utilizzare il metodo più volte ottenendo sovraimpressioni multiple.

Infine, possimao rimuovere l’icona (o le icone) visualizzate utilizzando il metodo msSiteModeClearIconOverlay. Questo metodo, a prescindere da quante icone abbiamo visualizzato, riporta la situazione alla sola visualizzazione dell’icona del sito (la favicon.ico, tanto per intenderci).

L’idea che può venirci in mente è quella di far lampeggiare l’icona utilizzando alternativamente i due comandi e l’istruzione Javascript  setInterval per ripetere il tutto un certo numero di volte:

  1. function blinkOverlayIcon(numberOfBlinks, blinkInterval, icona) {
  2.     if (window.external.msIsSiteMode) {
  3.         if (numberOfBlinks >= 0) {
  4.             try {
  5.                 if (numberOfBlinks % 2 == 0) {
  6.                     window.external.msSiteModeSetIconOverlay(icona, "");
  7.                 } else {
  8.                     window.external.msSiteModeClearIconOverlay();
  9.                 }
  10.             } catch (e) {
  11.  
  12.             }
  13.             numberOfBlinks--;
  14.             var func = "blinkOverlayIcon(" + numberOfBlinks + "," + blinkInterval + ",'" + icona + "')"
  15.             setTimeout(func, blinkInterval);
  16.  
  17.         } else {
  18.             clearTimeout();
  19.             try {
  20.                 window.external.msSiteModeClearIconOverlay();
  21.             } catch (e) {
  22.             }
  23.         }
  24.     }
  25. }

In pratica il bottone:

  1. <input type="button" name="name" value="Lampeggia" onclick="javascript:blinkOverlayIcon(20,500,'/images/red.ico');" />

Permette di ripetere 20 volte la funzione (per un totale di 10 lampeggi) con un intervallo di mezzo secondo ciascuna.

Ulteriore possibilità è quella di alternare due o più icone in modo da ottenere effetti sempre più complessi. In particolare per alternare due immagini possiamo utilizzare questa funzione

  1. function alternateOverlayIcon(numberOfBlinks, blinkInterval, icona1, icona2) {
  2.     if (window.external.msIsSiteMode) {
  3.         if (numberOfBlinks >= 0) {
  4.             try {
  5.                 var icona = '';
  6.                 if (numberOfBlinks % 2 == 0) {
  7.                     icona = icona1;
  8.                 } else {
  9.                     icona = icona2;
  10.                 }
  11.                 window.external.msSiteModeClearIconOverlay();
  12.                 window.external.msSiteModeSetIconOverlay(icona, "");
  13.             } catch (e) {
  14.  
  15.             }
  16.             numberOfBlinks--;
  17.             var func = "alternateOverlayIcon(" + numberOfBlinks + "," + blinkInterval + ",'" + icona1 + "','" + icona2 + "')"
  18.             setTimeout(func, blinkInterval);
  19.  
  20.         } else {
  21.             clearTimeout();
  22.             try {
  23.                 window.external.msSiteModeClearIconOverlay();
  24.             } catch (e) {
  25.             }
  26.         }
  27.     }
  28. }

In questo caso, il bottone:

  1. <input type="button" name="name" value="Alterna" onclick="javascript:alternateOverlayIcon(20,250,'/images/red.ico', '/images/yellow.ico');" />

alterna le icone rossa e gialla per 20 volte, ciascuna della durata di 250 millisecondi.

Evidentemente unico freno è la fantasia e, al limite, possiamo pensare di eseguire una vera e propria animazione alternando tutti i frame della stessa.

Un limite è che, poichè IE9 esegue di suo un effetto fade sulla visualizzazione dell’icona di overlay, il tempo tra una visualizzazione e l’altra non può essere piccolo a piacere.

 

sabato 27 novembre 2010

Articolo su ioProgrammo di Dicembre

E’ in edicola il numero di dicembre di ioProgrammo.

4-157g

All’interno di questo numero potete trovare un mio articolo dal titolo:

Personalizza l'IDE di Microsoft per velocizzare l'analisi del tuo codice sorgente

 

venerdì 26 novembre 2010

Windows Azure Discover Event (Parte 2)

L’evento è terminato e la sensazione è stata di un evento decisamente utile.

Uscito dalla sede Microsoft, mi sono reso conto di saperne un pochino di più e, questo, a mio modo di vedere, rende un evento utile.

Un ringraziamento a Roberto Brunetti e Mario Fontana che hanno tenuto delle sessioni ottime, chiare e chiarificatrici.

Ho avuto il piacere di conoscere Roberto di persona dopo tanti eventi in cui l’ho visto sul “palco” e la sensazione è quella di una persona ottima nonchè di uno speaker d’eccezione (ma quello lo sapevo).

Ancora una volta torno a dire che chi non è venuto si è perso una buonissima occasione per fare formazione!!!!

 

Windows Azure Discover Event (Parte 1)

Evento dedicato a Windows Azure a Roma.

Nella mattinata, Mario Fontana, ha cercato di fare chiarezza su cosa è il Cloud e cosa nonè.

E, debbo dire, c’è pienamente riuscito!!

Tarda mattinata dedicata al pricing delle sottoscrizioni per Windows Azure che aveva poco di tecnico ma ha chiarito anche questo punto oscuro.

Nel pomeriggio tocca a Roberto Brunetti che andrà sul pratico e ……. ci sarà da divertirsi!!!

A più trdi per il resoconto!!!

Stay tuned!! Occhiolino

 

giovedì 25 novembre 2010

Rilasciati due update per IE9 Beta

Il seguente post annuncia il rilascio di due update per IE9 beta:

Updates for Internet Explorer 9 Beta - IEBlog - Site Home - MSDN Blogs

Gli update sono distribuiti via Windows Update, quindi gli utenti ( a meno che non abbiano Windows Update disabilitato) dovrebbero vederseli arrivare “a casa” direttamente!!

 

Tag di Technorati: ,,

venerdì 19 novembre 2010

Sfogliare il Marketplace di WP7 da Web

Il marketplace di WP7 è consultabile tramite il software Zune Client oppure direttamente dai dispositivi WP7 che dispongono dell’hub apposito.

Chi non ha installato lo Zune Client o non ha il telefonino non è in grado di vedere cosa c’è a disposizione. Per ovviare a questo si può utilizzare il sito http://www.marketplacebrowser.com/ che consente di ricercare le applicazioni presenti nel marketplace senza avere client installati sul proprio pc.

image

Ovviamente l’acquisto si esegue con lo Zune Client ma se dobbiamo solamente capire se c’è l’Applicazione con la A maiuscola, il sito è perfetto.

Pubblicata Acronimi per WP7 sul Marketplace

Da ieri sera è disponibile la mia applicazione Acronimi per conoscere il significato di migliaia di acronimi.

Screenshot02Screenshot01Screenshot04

L’applicazione è scaricabile dal marketplace:

wp7_300x50_blue

Prossimamente uscirà un aggiornamento alla lista degli Acronimi presenti nell’applicazione.

Se ne trovate di mancanti (e ce ne sono sicuramente) segnalatemeli e li inserirò nelle prossime versioni.

 

Tag di Technorati: ,,,

giovedì 18 novembre 2010

DataURI e le immagini dinamiche in ASP.NET

In questo post vorrei proporvi un modo per creare immagini dinamiche  (in maniera analoga a quanto già proposto in questo post) all’interno delle nostre pagine ASPX utilizzando il DataURI.

Partiamo dal definire cosa è il DataURI.

Il DataURI (o più esattamente lo schema data URI), la cui definizione esatta è rintracciabile seguendo il link,  rappresenta un modo per includere all’interno delle nostre pagine web delle risorse (ad esempio grafiche, ma non solo).

Lo schema data URI compare già nelle specifiche dell’HTML 4.01.

I vantaggi di utilizzare lo schema data URI sono i seguenti:

  • le risorse incorporate nella pagina non richiedono differenti chiamate al server come accadrebbe se le risorse fossero indicate con un normale URL. Si ha quindi un risparmi nel numero di richieste e si elimina il traffico dell’header delle stesse;
  • per files di piccole dimensioni si ha un guadagno di tempo, poichè, generalmente, l’avvio della comunicazione TCP è lento;
  • nelle comunicazioni HTTPS, il browser, di solito, richiede che tutti gli elementi della pagina siano scaricati in connessione sicura (pena la comunicazione all’utente che ci sono elementi non “sicuri”) e l’HTTPS aggiunge un ulteriore overhead alla trasmissione;
  • i messaggi email possono, in questo modo contanere immagini senza che queste appaiano come degli allegati;
  • se il browser ha un numero basso di connessioni simultanee, si ha un vantaggio di tempo.

Lo schema data URI, però, ha anche degli svantaggi:

  • le risorse incorporate come data URI non sono cachate come le comuni risorse (ad esempio immagini) referenziate con un comune URL;
  • alcuni browser ancora in circolazione (ad esempio IE7 con circa il 27% della distribuzione sul mercato a luglio 2010) non lo supportano;
  • alcuni browser hanno una limitazione sulla lunghezza massima del data URI (ad esempio IE8 ha una limitazione a 32KB);
  • l’encoding del data URI (in base 64) è mediamente 1/3 più largo dell’equivalente encoding binario;
  • i software che si occupano di controllare la sicurezza dei siti lavorano male sui dati contanuti nello schema data URI.

Il formato di una risorsa espressa secondo lo schema data URI è il seguente:

data:[<MIME-type>][;charset=<encoding>][;base64],<data>

Se non si indica il base64, si intende che i dati sono espressi in ASCII.

Ad esempio, un’immagine in HTML è espressa nel seguente modo:

  1. <img src="data:image/png;base64,
  2.         iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABGdBTUEAALGP
  3.         C/xhBQAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9YGARc5KB0XV+IA
  4.         AAAddEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIFRoZSBHSU1Q72QlbgAAAF1J
  5.         REFUGNO9zL0NglAAxPEfdLTs4BZM4DIO4C7OwQg2JoQ9LE1exdlYvBBeZ7jq
  6.         ch9//q1uH4TLzw4d6+ErXMMcXuHWxId3KOETnnXXV6MJpcq2MLaI97CER3N0
  7.         vr4MkhoXe0rZigAAAABJRU5ErkJggg==" alt="Red dot" />

Lo schema data URI può essere utilizzato anche all’interno di un CSS (per i browser che lo supportano) o per includere del JavaScript.

Capito cosa è lo schema data URI vediamo come possiamo utilizzarlo  nelle nostre pagine ASPX.

Innanzitutto vediamo cosa si ottiene in termini di richieste e dati trasferiti quando includiamo delle immagini tramite data URI e in maniera classica.

Per fare questo realizziamo due pagine all’interno delle quali visualizzeremo le immagini contenute in una cartella nelle due modalità.

Il code behind della pagina che utilizza la tecnica standard è la seguente:

  1. Imports System.IO
  2.  
  3. Public Class MultiImageStandard
  4.     Inherits System.Web.UI.Page
  5.  
  6.     Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
  7.         If Not IsPostBack Then
  8.             CreateImages(10)
  9.         End If
  10.     End Sub
  11.  
  12.     Private Sub CreateImages(ByVal numImages As Integer)
  13.         Dim imagePath = Server.MapPath("/images")
  14.         Dim imageRep = New ImageRepository()
  15.         Dim imageFiles = imageRep.GetAllImages(imagePath)
  16.         For Each imageFile In imageFiles
  17.             Dim image = New Image()
  18.             Dim fi = New FileInfo(imageFile)
  19.             image.ImageUrl = String.Format("/images/{0}", fi.Name)
  20.             Me.Controls.Add(image)
  21.         Next
  22.     End Sub
  23. End Class

La classe ImageRepository enumera le immagini presenti nella cartella.

In sostanza creiamo un oggetto Image (web control) per ogni immagine ed impostiamo il sui ImageUrl. Il risultato ottenuto è il seguente:

image

Utilizzando IE9 e la developer toolbar (tasto F12) possiamo osservare il numero di chiamate eseguite verso il server per recuperare la pagina e le 12 immagini visualizzate.

Il code behind della pagina che utilizza lo schema data URI è il seguente:

  1. Public Class MultiImageDataUri
  2.     Inherits System.Web.UI.Page
  3.  
  4.     Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
  5.         If Not IsPostBack Then
  6.             CreateImages(10)
  7.         End If
  8.  
  9.     End Sub
  10.  
  11.     Private Sub CreateImages(ByVal numImages As Integer)
  12.         Dim imagePath = Server.MapPath("/images")
  13.         Dim imageRep = New ImageRepository()
  14.         Dim imageFiles = imageRep.GetAllImages(imagePath)
  15.         For Each imageFile In imageFiles
  16.             Dim image = New Image()
  17.             image.ImageUrl = CreateDataUri(imageFile)
  18.             Me.Controls.Add(Image)
  19.         Next
  20.     End Sub
  21.  
  22.     Private Function CreateDataUri(ByVal imagePath As String) As String
  23.         Dim image = New Drawing.Bitmap(imagePath)
  24.         Dim base64String As String
  25.         Using ms As New IO.MemoryStream
  26.             image.Save(ms, image.RawFormat)
  27.             base64String = Convert.ToBase64String(ms.ToArray())
  28.         End Using
  29.         Return String.Format("data:image/png;base64,{0}", base64String)
  30.     End Function
  31.  
  32. End Class

In questo caso, per ogni immagine da visualizzare, craiamo un oggetto Bitmap, ne ricaviamo la sua rappresentazione come array di Byte e, quindi, lo encodiamo in base64.

Il risultato, in questo caso, è il seguente:

image

Osserviamo una sola connessione per recuperare l’intera pagina.

Un altro utilizzo dello schema data URI può essere quello di visualizzare delle immagini dinamiche.

Supponiamo di voler fare in modo che data un’immagine venga applicata su di essa una scritta di watermark (esattamente come già avevamo fatto nel post).

Per realizzare tutto ciò è sufficiente creare un immagine bitmap a partire dall’immagine su cui applicare il watermark, recuperare il suo contesto grafico, disegnare il watermark su di essa e, infine encodarla in base64.

In sostanza possiamo scrivere:

  1. Imports System.Drawing
  2.  
  3. Public Class DynamicImage
  4.     Inherits System.Web.UI.Page
  5.  
  6.     Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
  7.         If Not IsPostBack Then
  8.             CreateImage("/images/BigImage/DominicanRepublic_DE-DE1561561743.jpg", "CodeTailor", Image1)
  9.         End If
  10.     End Sub
  11.  
  12.     Private Sub CreateImage(ByVal imagePath As String,
  13.                             ByVal watermark As String,
  14.                             ByVal imageControl As System.Web.UI.WebControls.Image)
  15.  
  16.         Dim imageFullPath = HttpContext.Current.Server.MapPath(imagePath)
  17.         Dim image As New Bitmap(imageFullPath)
  18.         Dim gr = Graphics.FromImage(image)
  19.         Dim watermarkFont = New Font(FontFamily.GenericMonospace, _
  20.             10, FontStyle.Regular, GraphicsUnit.Pixel)
  21.         Dim textSize = gr.MeasureString(watermark, watermarkFont)
  22.         Dim x = 0
  23.         While x < image.Width
  24.             Dim y = 0
  25.             While y < image.Height
  26.                 gr.DrawString(watermark, watermarkFont, Brushes.White, x, y)
  27.                 y = CInt(y + (3 / 2 * textSize.Height))
  28.             End While
  29.             x = CInt(x + (3 / 2 * textSize.Width))
  30.         End While
  31.         Dim base64String As String
  32.         Using ms As New IO.MemoryStream
  33.             image.Save(ms, image.RawFormat)
  34.             base64String = Convert.ToBase64String(ms.ToArray())
  35.         End Using
  36.         imageControl.ImageUrl = String.Format("data:image/png;base64,{0}", base64String)
  37.     End Sub
  38. End Class

Il risultato che otteniamo è il seguente:

image



mercoledì 17 novembre 2010

IE9 Platform Preview 7 disponibile

Altro rilascio di una platform preview di IE9 con miglioramenti lato Javascript (“Chakra” cresce sempre di più).

Il post originale con l’annuncio è il seguente:

HTML5, and Real World Site Performance: Seventh IE9 Platform Preview Available for Developers - IEBlog - Site Home - MSDN Blogs

Vorrei solo portare alla vostra attenzione questi due grafici:

SunSpiderResultsPPB6

Dean_PPB7

Il primo è il risultato del SunSpider JavaScript eseguito sulla IE9 Platform Preview 6 mentre il secondo è quello eseguito sulla Platform Preview 7: la differenza si vede!!!

Per chi ne vuole sapere di più sul SunSpider JavaScript può seguire il link.

Il download della Preview 7 si può eseguire dal seguente link.

 

martedì 9 novembre 2010

Announcing the ASP.NET MVC 3 Release Candidate - ScottGu's Blog

Scott Guthrie ha annunciato il rilascio della Release Candidate di ASP.NET MVC3.

Maggiori info nel post:

Announcing the ASP.NET MVC 3 Release Candidate - ScottGu's Blog

Il download dall’indirizzo:

http://www.microsoft.com/downloads/en/details.aspx?FamilyID=a920ccee-1397-4feb-824a-2dfefee47d54&displaylang=en

 

Tag di Technorati: ,

VB for Dummies: Tipi anonimi e la parola chiave Key

I tipi anonimi (anonymous types) sono stati introdotti con il framework 3.5.

Sostanzialmente si tratta di oggetti istanziati “al volo” senza definirle esplicitamente il tipo a cui appartengono con il costrutto Class…End Class.

Tutti gli esempi riportati in questo post sono stati testati e realizzati con Visual Studio 2010 e .NET Framework 4.0. La maggior parte di quello che diremo sarà, in ogni caso, valido anche per il framework 3.5.

Un esempio di anonymous type è il seguente:

  1. Dim obj1 = New With {.Username = "verdi.giuseppe",
  2.                      .Cognome = "Verdi",
  3.                      .Nome = "Giuseppe"}

Otteniamo un oggetto che contiene tre proprietà (Username, Cognome e Nome) di tipo stringa ma non è un’istanza di una classe ben precisa:

image

In realtà, il compilatore costruisce per noi una classe che non vediamo e che viene utilizzata ogni qual volta istanziamo un anonymous type dello stesso tipo (cioè un oggetto che ha tre proprietà Username, Cognome e Nome).

Per verificare quello che abbiamo detto, scriviamo il seguente codice:

  1. Sub Main()
  2.     Dim obj1 = New With {.Username = "verdi.giuseppe",
  3.                          .Cognome = "Verdi",
  4.                          .Nome = "Giuseppe"}
  5.  
  6.     Dim obj2 = New With {.Username = "bianchi.carlo",
  7.                          .Cognome = "Bianchi",
  8.                          .Nome = "Carlo"}
  9. End Sub

compiliamolo e apriamo il codice generato tramite Reflector:

image

Come possiamo vedere dalla precedente immagine, il compilatore crea, per noi, una classe (chiamata VB$AnonymousType_0, ma potrebbe chiamarsi in qualsiasi modo) che descrive esattamente l’anonymous type da noi creato.

Analizzando questa classe:

image

osserviamo che è marcata come classe generata dal compilatore (attributo CompilerGenerated).

Il compilatore è in grado di capire che, pur avendo noi utilizzato due anonymous type distinti (obj1 e obj2), questi in realtà sono rappresentabili con la medesima classe e, perciò, non crea due classi distinte ma riutilizza la stessa.

Altra cosa che ci salta all’occhio è che la classe “anonima” è generata come generics (i tipi generici saranno oggetto di un altro post in futuro). Questo ci fa dedurre che il compilatore potrebbe essere in grado di riutilizzare la medesima classe anche per quei tipi anonimi che hanno proprietà con stesso nome ma tipo differente.

Proviamo a scrivere:

  1. Dim obj3 = New With {.Username = 7,
  2.                      .Cognome = "Bianchi",
  3.                      .Nome = "Carlo"}

Se compiliamo il progetto ed apriamo l’assembly generato, possiamo osservare che non viene creata un’altra classe “anonima” ma viene riutilizzata (come giustamente dovrebbe accadere) la precedente.

image

I tipi anonimi derivano, come possiamo vedere anche in una delle figure precedenti, dalla classe Object e non ridefiniscono i metodi GetHashCode e Equals.

Il metodo GetHashCode permette di ottenere un intero che identifica l’oggetto. Purtroppo l’implementazione di base (quella della classe object) non garantisce che i valori restituiti siano univoci per oggetti diversi. Questo inficia, di fatto, le operazioni di confronto che utilizzano l’hash.

In maniera analoga l’implementazione di base del metodo Equals, per i reference types (come di fatto sono i tipi anonimi), supporta l’uguaglianza dei riferimenti. Questa significa che due istanze differenti tipi anonimi esattamente uguali per contenuti sono differenti per il metodo Equals di Object.

  1. Public Sub TestObjectEquals()
  2.     Dim obj1 = New With {.Username = "verdi.giuseppe",
  3.                          .Cognome = "Verdi",
  4.                          .Nome = "Giuseppe"}
  5.     Dim obj2 = New With {.Username = "verdi.giuseppe",
  6.                          .Cognome = "Verdi",
  7.                          .Nome = "Giuseppe"}
  8.  
  9.     Dim eq = obj1.Equals(obj2) ' FALSE
  10. End Sub

In una classe da noi realizzata possiamo implementare l’override del metodo Equals ma in un tipo anonimo che si fa?

In questo caso interviene la parola chiave Key. Questa permette di definire, in un tipo anonimo, quelle proprietà che sono considerate come “chiavi” per l’oggetto.

Un esempio potrebbe essere:

  1. Dim obj1 = New With {Key .Username = "verdi.giuseppe",
  2.                      .Cognome = "Verdi",
  3.                      .Nome = "Giuseppe"}

Utilizzare la parola chiave Key produce alcuni risultati interessanti:

  1. la proprietà “marcata” con la Key è in sola lettura;
  2. il metodo GetHashCode utilizza la proprietà per il calcolo;
  3. il metodo Equals viene ridefinito dal compilatore basandosi sulla proprietà stessa.

Compiliamo la definizione di prima e otteniamo:

image

Rispetto al precedente caso abbiamo che la classe implementa l’interfaccia IEquatable, i metodi Equals e GetHashCode e la proprietà Username è, effettivamente, di sola lettura.

Se analizziamo l’implementazione del metodo Equals otteniamo:

  1. <DebuggerNonUserCode> _
  2. Public Function Equals(ByVal val As VB$AnonymousType_0(Of T0, T1, T2)) As Boolean
  3.         Implements IEquatable(Of VB$AnonymousType_0(Of T0, T1, T2)).Equals
  4.     If (val Is Nothing) Then
  5.         Return False
  6.     End If
  7.     Dim e_ As VB$AnonymousType_0(Of T0, T1, T2) = val
  8.     If (Me.$Username Is Nothing) Then
  9.         If (Not e_.$Username Is Nothing) Then
  10.             Return False
  11.         End If
  12.     ElseIf (e_.$Username Is Nothing) Then
  13.         Return False
  14.     End If
  15.     If (((Not Me.$Username Is Nothing) AndAlso
  16.             (Not e_.$Username Is Nothing)) AndAlso
  17.             Not Me.$Username.Equals(e_.$Username)) Then
  18.         Return False
  19.     End If
  20.     e_ = Nothing
  21.     Return True
  22. End Function

Il metodo, effettivamente, utilizza Username come chiave per verificare che due oggetti istanza del tipo anonimo siano o meno uguali.

Grazie alla parola chiave Key possiamo scrivere:

  1. Public Sub TestObjectEquals()
  2.     Dim obj1 = New With {Key .Username = "verdi.giuseppe",
  3.                          .Cognome = "Bianchi",
  4.                          .Nome = "Carlo"}
  5.     Dim obj2 = New With {Key .Username = "verdi.giuseppe",
  6.                          .Cognome = "Verdi",
  7.                          .Nome = "Giuseppe"}
  8.  
  9.     Dim eq = obj1.Equals(obj2) ' True
  10. End Sub

Ovviamente la parola Key può essere applicata a più proprietà contemporaneamente:

  1. Dim obj1 = New With {Key .Username = "verdi.giuseppe",
  2.                      Key .Cognome = "Verdi",
  3.                      Key .Nome = "Giuseppe"}

Il compilatore, di conseguenza, ridefinirà GetHashCode e Equals in modo da utilizzare tutte e tre le proprietà (definite, a questo punto, come di sola lettura).

I tipi anonimi, dunque, possono rappresentare un ottimo strumento da utilizzare, all’interno dei nostri metodi per mantanere dati locali che debbono subire confronti o finire in strutture dove l’hash è fondamentale. Non sono assolutamente da utilizzare per lo scambio dei dati in cui è opportuno costruire una nostra classe “vecchio stampo”.

giovedì 4 novembre 2010

Gli enumeratori e Visual Basic

Una delle novità presentate alla PDC2010 riguarda le specifiche di linguaggio per Visual Basic che permettono di implementare gli iteratori.

Per chi sviluppa in C#, gli iteratori sono presenti fin dalla versione 2.0 del Framework mentre per gli sviluppatori VB tali oggetti non esistevano.

Partiamo con la definizione di iteratore: un iteratore è oggetto che permette di scandire il contenuto di una lista.

La parola chiave che si utilizza per definire il “ritorno” di uno degli oggetti della lista è yield che viene anteposta all’istanza da restuire. L’insieme degli yield deve essere posto all’interno di un metodo (di tipo function) che restituisca IEnumerator, IEnumerator(Of T), IEnumerable o IEnumerable(Of T).

Facciamo subito un esempio molto semplice: vogliamo creare un iteratore che dia la possibilità di iterare sui primi 5 numeri interi:

  1. Sub Main()
  2.     For Each intero In Get5Numeri()
  3.         Console.WriteLine(intero)
  4.     Next
  5. End Sub
  6.  
  7. Private Iterator Function Get5Numeri() As IEnumerable(Of Integer)
  8.     Yield 1
  9.     Yield 2
  10.     Yield 3
  11.     Yield 4
  12.     Yield 5
  13. End Function

Se proviamo ad eseguire passo passo il codice scritto in precedenza possiamo osservare che:

  • il For Each richiama l’iteratore Get5Numeri ma non entra all’interno del metodo;
  • ogni volta che si esegue una iterazione del ciclo possiamo osservare che il punto di esecuzione passa da uno yield al successivo:

Flusso di esecuzione

La parola chiave yield, quindi, viene richiamata ogni volta che l’iteratore “fa un passo avanti”.

Ovviamente, possiamo utilizzare la parola chiave yield in un contesto dinamico come, ad esempio, questo iteratore per la tabellina del due:

  1. Sub Main()
  2.     For Each intero In MultipliDiDue(10)
  3.         Console.WriteLine(intero)
  4.     Next
  5. End Sub
  6.  
  7. Private Iterator Function MultipliDiDue(ByVal n As Integer) As IEnumerable(Of Integer)
  8.     For index = 0 To n
  9.         Yield 2 * index
  10.     Next
  11. End Function

L’utilizzo degli iteratori ci permette di realizzare classi liste in maniera molto semplice ed efficiente.

Supponiamo di voler descrivere una classe di alunni e di fornire delle funzionalità che ci permettono di scorrere tutti gli alunni presenti in essa e, magari, tutti i maschi e tutte le femmine.

Utilizzando gli iteratori possiamo scrivere:

  1. Public Class Classe
  2.     Implements IEnumerable
  3.  
  4.     Private _Alunni As New List(Of Alunno)
  5.  
  6.     Public Iterator Function GetEnumerator() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator
  7.         For Each alunno In _Alunni
  8.             Yield alunno
  9.         Next
  10.     End Function
  11.  
  12.     Private Iterator Function AlunniPerSesso(ByVal sesso As Sesso) As IEnumerable
  13.         For Each alunno In _Alunni
  14.             If alunno.Sesso = sesso Then
  15.                 Yield alunno
  16.             End If
  17.         Next
  18.     End Function
  19.  
  20.     Public ReadOnly Property Maschi As IEnumerable
  21.         Get
  22.             Return AlunniPerSesso(Sesso.Maschio)
  23.         End Get
  24.     End Property
  25.  
  26.     Public ReadOnly Property Femmine As IEnumerable
  27.         Get
  28.             Return AlunniPerSesso(Sesso.Femmina)
  29.         End Get
  30.     End Property
  31.  
  32.     Public Sub AggiungiAlunno(ByVal nome As String)
  33.         _Alunni.Add(New Alunno() With {.Nome = nome, .Sesso = Sesso.Maschio})
  34.     End Sub
  35.  
  36.     Public Sub AggiungiAlunna(ByVal nome As String)
  37.         _Alunni.Add(New Alunno() With {.Nome = nome, .Sesso = Sesso.Femmina})
  38.     End Sub
  39. End Class
  40.  
  41. Public Class Alunno
  42.     Property Nome As String
  43.     Property Sesso As Sesso
  44. End Class
  45.  
  46. Public Enum Sesso
  47.     Maschio
  48.     Femmina
  49. End Enum

Con questa classe possiamo scrivere:

  1. Sub Main()
  2.     Dim terzaC = New ClasseSenzaIteratore()
  3.     terzaC.AggiungiAlunno("Marco")
  4.     terzaC.AggiungiAlunno("Filippo")
  5.     terzaC.AggiungiAlunna("Marta")
  6.     terzaC.AggiungiAlunna("Sara")
  7.     terzaC.AggiungiAlunno("Antonio")
  8.     terzaC.AggiungiAlunna("Carmela")
  9.  
  10.     For Each alunno As Alunno In terzaC
  11.         Console.WriteLine(alunno.Nome)
  12.     Next
  13.     Console.WriteLine()
  14.     For Each alunno As Alunno In terzaC.Maschi
  15.         Console.WriteLine(alunno.Nome)
  16.     Next
  17.     Console.WriteLine()
  18.     For Each alunno As Alunno In terzaC.Femmine
  19.         Console.WriteLine(alunno.Nome)
  20.     Next
  21.  
  22.     Console.ReadLine()
  23. End Sub

Ovviamente una classe analoga sarebbe realizabile anche senza gli iteratori ma dovremmo ricorrere ad artifizi come creare liste di appoggio e sfruttare l’iteratore delle stesse:

  1. Public Class ClasseSenzaIteratore
  2.     Implements IEnumerable
  3.  
  4.     Private _Alunni As New List(Of Alunno)
  5.  
  6.     Public Function GetEnumerator() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator
  7.         Return _Alunni.GetEnumerator()
  8.     End Function
  9.  
  10.     Private Function AlunniPerSesso(ByVal sesso As Sesso) As IEnumerable
  11.         Dim tmpList = From a In _Alunni
  12.                       Where a.Sesso = sesso
  13.                       Select a
  14.  
  15.         Return tmpList
  16.     End Function
  17.  
  18.     Public ReadOnly Property Maschi As IEnumerable
  19.         Get
  20.             Return AlunniPerSesso(Sesso.Maschio)
  21.         End Get
  22.     End Property
  23.  
  24.     Public ReadOnly Property Femmine As IEnumerable
  25.         Get
  26.             Return AlunniPerSesso(Sesso.Femmina)
  27.         End Get
  28.     End Property
  29.  
  30.     Public Sub AggiungiAlunno(ByVal nome As String)
  31.         _Alunni.Add(New Alunno() With {.Nome = nome, .Sesso = Sesso.Maschio})
  32.     End Sub
  33.  
  34.     Public Sub AggiungiAlunna(ByVal nome As String)
  35.         _Alunni.Add(New Alunno() With {.Nome = nome, .Sesso = Sesso.Femmina})
  36.     End Sub
  37.  
  38. End Class

Il codice è meno pulito e, abbiamo la necessità di liste d’appoggio.

Un metodo che implementa IEnumerable può anche non essere direttamente marcato con la parola chiave Iterator, purchè restituisca il risultato di un metodo marcato con Iterator:

  1. Private Function GetNumeri(ByVal min As Integer, ByVal max As Integer) As IEnumerable
  2.     If min < 0 Then Throw New Exception("Min < 0")
  3.     If min > max Then Throw New Exception("Min > max")
  4.  
  5.     Dim GetNumeriAlVolo = Iterator Function() As IEnumerable
  6.                               For index = min To max
  7.                                   Yield index
  8.                               Next
  9.                           End Function
  10.  
  11.     Return GetNumeriAlVolo()
  12. End Function

In questo caso, utilizziamo addirittura un anonymous iterator.

Le potenzialità del linguaggio, quindi, aumentano a dismisura in termini di efficienza, compattezza del codice e manutenibilità.

Per poter utilizzare Iterator e Yield nel proprio codice è necessario scaricare ed installare Async CTP al cui interno, oltre che il framework Async, troviamo la definizione delle nuove parole chiave.

E’ possibile scaricare Async CTP al seguente link, mentre la home page di Async CTP è raggiungibile al seguente link.

Ovviamente le nuove features sono disponibili per Visual Studio 2010 e framework 4.0.

 

Tag di Technorati: ,,,