C#

WP7 : HttpWebRequest e la cache interna

Forse non tutti sanno che la classe HttpWebRequest utilizza una propria cache interna per tutte le richieste che via via vengono eseguite durante il suo utilizzo.

Accade che, eseguendo una richiesta sempre al medesimo URL, l’oggetto HttpWebRequest istanziato non esegue effettivamente la richiesta (l’ho rilevato mediante Wireshark) ma bensì ritorna immediatamente il contenuto della richiesta fatta in precedenza allo stesso URL. Questo comportamento è, appunto, dovuto alla cache interna di cui la classe è dotata.

Su Windows Phone 7, non esiste la possibilità di modificare l’utilizzo della cache attraverso le cache policies come accade nel .Net Framework ma è necessario sopperire a questa mancanza attraverso un workaround.

string requestUrl = String.Format(url + "&{0}", DateTime.Now.Ticks);
HttpWebRequest request = HttpWebRequest.CreateHttp(requestUrl);
request.BeginGetResponse(new AsyncCallback(HandleResponse), request);

Attraverso il codice precedente, si evince che il workaround consiste nell’aggiungere un parametro casuale nella query string dell’URL desiderato, in modo da avere di volta in volta un URL risultante diverso e forzare la richiesta. In questo caso, la casualità è determinata dai ticks del sistema ma potrebbe essere utilizzata anche legata alla generazione di un Guid. Tipicamente, questo parametro sarà ignorato dal web server ma servirà dal lato del device per “simulare” la richiesta ad un URL differente.

Sicuramente la soluzione non appare molto elegante ma a quanto pare è l’unica possibile…nell’attesa di piacevoli smentite !

Codice Nativo vs Gestito : performance

Affrontando un problema lavorativo riguardo le perfomance grafiche su un target device con processore ARM e Windows CE 6.0 R3 e facendo delle ricerche di approfondimento in rete, mi sono imbattuto in un interessantissimo articolo di Chris Tacke dell’OpenNETCF Communty intitolato “Native vs. Managed Code : GDI Performance”.

L’articolo, attraverso un’applicazione di test, dimostra quanto il codice nativo non possa essere considerato in assoluto molto più veloce del codice gestito ma soltanto per una percentuale relativa che però può talvolta variare da piattaforma a piattaforma. In particolare, il test viene eseguito utilizzando le GDI di Windows.

Un ulteriore interessante risultato è che l’utilizzo di metodi del .Net Compact Framework che fungono da wrapper di corrispondenti metodi nativi (vedi ad esempio Graphics.FillRectangleche è wrapper dell’API FillRect) riducono le performance rispetto all’invocazione diretta delle API di sistema attraverso le P/Invoke. E’ ovvio che il wrapper al suo interno eseguirà sempre una P/Invoke ma aggiunge un carico di lavoro in più, probabilmente legato a dei check che vengono eseguiti prima della chiamata nativa (vedi anche il marshalling dei parametri).

Swap di due variabili senza la variabile di appoggio ? Si può !

Una delle prime funzioni (escludendo il solito Main() che produce il famosissimo “Hello World”) che si scrive quando ci si avvicina al mondo della programmazione, è quella che ci permette lo swap (scambio) di valori tra due variabili. Tipicamente si è portati a scrivere del codice di questo tipo …

private void Swap(ref int a, ref int b)
{
    if (a != b)
    {
        int tmp;

        tmp = a;
        a = b;
        b = tmp;
    }
}

… ossia siamo portati ad utilizzare una terza variabile (tmp) di appoggio.

Ebbene, tale variabile si può assolutamente evitare, riscrivendo la funzione nel modo seguente …

private void Swap(ref int a, ref int b)
{
    if (a != b)
    {
        a ^= b;
        b ^= a;
        a ^= b;
    }
}

… ed utilizzando solo ed esclusivamente le proprietà dell’operatore logico XOR (commutativa, associativa identità).

Nullable.Equals(object) … comportamento “strano” che ha una spiegazione !

Ieri, in ufficio con alcuni miei colleghi, mi sono imbattuto in un comportamento alquanto strano del metodo Equals(object) della struct Nullable<T>.

Consideriamo il seguente frammento di codice :

short? x = 1;
bool b = x.Equals(1);

Secondo voi….quanto vale la variabile b ? Ebbene….magicamente false !

A questo punto consideriamo il seguente frammento di codice :

short? x = 1;
// caso 1
bool b = x.Equals(1);
// caso 2
b = x.Equals((short)1);
// caso 3
short y = 1;
b = x.Equals(y);

Il “caso 1” è ovviamente quello appena visto e ritorna “stranamente” b uguale a false. Il “caso 2” e “caso 3” si comportano correttamente fornendo un valore true.

Cambiamo il “caso 1” nel modo seguente :

int? x = 1;
bool b = x.Equals(1);

In questo caso, abbiamo semplicemente modificato la dichiarazione del nullable type dashort? a int? ed il valore di b diventa “magicamente” true !

Ecco che a questo punto, dotandomi di Reflector ho cominciato ad indagare sull’implementazione del metodo Equals(object) della struct Nullable<T> che riporto di seguito.

public override bool Equals(object other)
{
    if (!this.HasValue)
    {
        return (other == null);
    }
    if (other == null)
    {
        return false;
    }
    return this.value.Equals(other);
}

Dopo aver eseguito un paio di controlli preliminari sul fatto che la struct abbia un valore e che l’oggetto passato per il confronto non sia null, viene invocato il metodo Equals(object) del tipo T del campo value (interno alla struct Nullable<T>).

Considerando il caso in cui avevamo la dichiarazione short?, ossia Nullable<short>, il metodo che viene invocato sarà ovviamente Int16.Equals(object) la cui implementazione è la seguente :

public override bool Equals(object obj)
{
    return ((obj is short) && (this == ((short) obj)));
}

L’utilizzo dell’operatore is, per la verifica del tipo del parametro, svela l’arcano !

Come sappiamo, tutti i numeric literals (il numero “1” nel nostro caso) sono trattati implicitamente come Int32, per cui la chiamata x.Equals(1) (dove x è di tipo short?) restituisce “correttamente” false, in quanto obj non sarà short ma int !

In tutti gli altri casi, dichiarando esplicitamente una variabile di tipo short (si veda short y = 1) oppure eseguendo il cast esplicito a short del numeric literal (si veda x.Equals((short)1)), forziamo il tipo (coincidente con short? x) ed il confronto ritorna un valore corretto.

Questo spiega anche il perchè del fatto che modificando la dichiarazione da short? x a int? x, otteniamo un valore corretto per x.Equals(1)….in quanto il numeri literal “1” come già detto è implicitamente un Int32 !

In conclusione…..attenzione all’uso del metodo Equals(object) e dei numeric literals nei confronti !!

Da byte[] a String con il .Net Micro Framework

Spesso, dato un array di byte con codifica UTF8, si rende necessaria la relativa conversione in una stringa. Purtroppo, il .Net Micro Framework non mette a disposizione il metodoEncoding.UTF8.GetString(byte[] bytes) utile per questo scopo.

Il metodo più veloce per ottenere il medesimo risultato è il seguente :

byte[] bytes;
...
...
string s = new String(Encoding.UTF8.GetChars(bytes));

E’, in pratica, necessario ricavere prima l’array di char corrispondenti e poi instanziare un oggetto String inizializzandolo con tale array.

WPF Dispatcher.CheckAccess() vs Windows Forms Control.InvokeRequired

Coloro che utilizzano quotidianamente le Windows Forms conosceranno il significato della property InvokeRequired nell’ambito della classe Windows.Forms.Control. Sappiamo infatti che i controlli di una Windows Forms sono legati ad uno specifico thread (generalmente il main thread) e non sono thread safe. Per questo motivo, se intendiamo invocare un qualsiasi metodo su un controllo oppure modificare una sua property (es. modificare il testo di una label o di una textbox) da un thread differente, è necessario invocare uno dei metodi che permettono di eseguire il marshal nel thread giusto. Questi ultimi sono : Invoke() per l’invocazione sincrona, BeginInvoke() e EndInvoke() per un’invocazione asincrona.

La property InvokeRequired ci permette di capire se è necessario eseguire questa operazione di marshal in un altro thread o meno. Per questo motivo, quando bisogna intervenire tipicamente sulla UI, all’interno del nostro metodo adottiamo un codice di questo tipo :

if (this.myControl.InvokeRequired)
{
    // accesso indiretto attraverso Invoke() o BeginInvoke()
    this.myControl.Invoke(.....);
}
else
{
    // accesso diretto a myControl
    this.myControl.SomeMethod();
    this.myControl.SomeProperty = value;
}

Ma esiste in WPF una controparte della InvokeRequired ?

In WPF, ogni controllo ha la property Dispatcher sulla quale è possibile invocare i medesimi metodi Invoke() e BeginInvoke() per eseguire il marshal nel thread giusto. Sempre Dispatcher fornisce la controparte della InvokeRequired, ossia il metodo CheckAccess() che ritorna true se l’invocazione avviene già nel thread giusto. Per questo motivo il codice suddetto diventa :

if (this.myControl.Dispatcher.CheckAccess())
{
    // accesso diretto a myControl
    this.myControl.SomeMethod();
    this.myControl.SomeProperty = value;
}
else
{
    // accesso indiretto attraverso Invoke() o BeginInvoke()
    this.myControl.Dispatcher.Invoke(.....);
}

E’ importante sottolineare che se in Visual Studio provate a farvi aiutare dall’Intellisense, il metodo CheckAccess() non vi verrà mostrato ma se lo scrivete senza alcun aiuto e compilate, tutto funzionerà correttamente. La sua invisibilità è dovuta alla sua dichiarazione :

[EditorBrowsable(EditorBrowsableState.Never)]
public bool CheckAccess();

Il gate per salire a bordo del Kinect : la classe Runtime

Tra tutte le classi messe a disposizione dal Kinect SDK, quella sicuramente più importante è la classe Runtime. Attraverso quest’ultima è possibile gestire tutti i sottosistemi, quali la video camera, il sensore di profondità ed il riconoscitore della figura umana. Di seguito riporto il relativo class diagram :

6153.Runtime-Class_56547733

Inizializzazione e deinizializzazione

Per poter utilizzare il Kinect, la prima cosa da fare è istanziare la classe Runtime.

nui = new Runtime();
Oltre al costruttore di default, senza alcun parametro, è previsto un suo overload che ha in ingresso un index che rappresenta l’identificativo del Kinect da inizializzare nel caso in cui al PC ve ne fosse collegato più di uno. Tale indice è inoltre accessibile successivamente attraverso la property InstanceIndex di sola lettura.
Successivamente, è necessario eseguirne l’inizializzazione, in modo che vengano allocate tutte le risorse unmanaged che sono necessarie per utilizzare i sottosistemi del dispositivo stesso. Per fare ciò, è necessario invocare il metodo Initialize().
nui.Initialize(RuntimeOptions.UseColor | RuntimeOptions.UseDepth);
Tale metodo prevede in ingresso un parametro di tipo RuntimeOptions, ossia un enumerativo attraverso il quale specificare quali sensori vogliamo utilizzare. Ovviamente, i valori possibili possono essere messi in OR tra loro in modo da utilizzare più sensori contemporaneamente. Più precisamente, sono i seguenti :
  • UseDepthAndPlayerIndex : utilizzo del sensore di profondità con riconoscimento del giocatore (ciascuna giocatore viene individuato attraverso un index diverso);
  • UseColor : utilizzo della video camera;
  • UseSkeletalTracking : riconoscimento della figura umana di ciascun giocatore;
  • UseDepth : utilizzo del sensore di profondità;
Una volta inizializzato ed utilizzato, l’istanza della Runtime va deinizializzata attraverso l’utilizzo del metodo Uninitialize() per poter permettere la deallocazione di tutte le risorse unmanaged.
nui.Uninitialize();
Gli stream, lo skeleton e la video camera
La classe Runtime dispone di alcune proprietà attraverso le quali è possibile accedere a tutte le funzionalità del Kinect.
In primo luogo, vi sono i due seguenti stream :
  • VideoStream : rappresenta lo stream della video camera, fornendo allo sviluppatore i fotogrammi ripresi da quest’ultima;
  • DepthStream : rappresenta lo stream del sensore di profondità, in cui ciascun pixel non esprime un punto di un’immagine (in termini RGB, come nel caso del VideoStream) ma fornisce l’informazione della distanza di quel punto rispetto al Kinect;

Entrambe le property rappresentano un riferimento alla classe ImageStream.

Per poter utilizzare tali stream, è necessario la loro apertura invocando su ciascuno di essi il relativo metodo Open() della classe ImageStream. Tale metodo prevede i seguenti parametri :

  • streamType : di tipo ImageStreamType che permette di dichiarare il tipo di stream al quale siamo interessati (Invalid, Depth o Video);
  • poolSize : dimensione del buffer (espresso in numero di frame) che il runtime dovrà utilizzare. Tipico valore è 2;
  • resolution : di tipo ImageResolution che indica la risoluzione da adottare per lo stream;
  • image : di tipo ImageType che indica il tipo di contenuto nell’immagine. Alcuni possibili valori sono ad esempio Depth per indicare un’immagine che contiene informazioni sulla distanza, Color per indicare un’immagine ripresa dalla video camera in formato RGB oppure ColorYuv per indicare un’immagine ripresa dalla video camera in formato YUV;
nui.VideoStream.Open(ImageStreamType.Video, 2,
ImageResolution.Resolution640x480, ImageType.Color);
nui.DepthStream.Open(ImageStreamType.Depth, 2,
ImageResolution.Resolution640x480, ImageType.Depth);

Per accedere al motore per il riconoscimento della figura umana, è disponibile la propertySkeletonEngine che rappresenta un riferimento alla classe SkeletonEngine. Infine, attraverso la property NuiCamera si ottiene un riferimento alla classe Camera, con la quale poter accedere alla video camera e modificarne per esempio l’inclinazione.

Intercettazione delle frame : gli eventi

Per evitare un utilizzo in modalità polling del Kinect, la classe Runtime mette a disposizione alcuni eventi che vengono sollevati quando sono disponibili nuove frame dalla video camera, dal sensore di profondità e dal riconoscitore della figura umana.

nui.VideoFrameReady += new EventHandler<ImageFrameReadyEventArgs>(nui_VideoFrameReady);
nui.DepthFrameReady += new EventHandler<ImageFrameReadyEventArgs>(nui_DepthFrameReady);
nui.SkeletonFrameReady += new EventHandler<SkeletonFrameReadyEventArgs>(nui_SkeletonFrameReady);

Essi rappresentano :

  • VideoFrameReady : sollevato quando è disponibile, nel buffer, una frame dello stream video (VideoStream);
  • DepthFrameReady : sollevato quando è disponibile, nel buffer, una frame dello stream di profondità (DepthStream);
  • SkeletonFrameReady : sollevato quando è disponibile un’immagine della figura umana rilevata dallo skeleton engine;