So perfettamente che i contenuti di questo post sono un pò "fuori tempo massimo", ma sono altrettanto consapevole che quanto esporrò servirà a qualcun'altro che, come me, non sempre ha tutte le sue app compilate e testate con le ultime versioni di Android.

Premessa

Una delle app di cui curo lo sviluppo ha un funzionalità grazie alla quale alla pressione di un tasto viene eseguita un'elaborazione che al termine crea una mail bell'è pronta da spedire corredata di un allegato pdf che rappresenta i risultati.

Nulla di particolarmente strano: su come generare questo pdf ho già scritto su questa blog, e per creare la mail nonchè associargli il file ho usato lo straconosciuto e utilizzato Messaging di Xamarin.Plugins.

Tutto ha sempre funzionato in modo egregio e senza grossi problemi.... in modo sano.... per usare un gergo da ciovane......

Ora occorre dire che la app di cui sto parlando permette di inserire degli ordini di merce da parte degli agenti della rete vendita, che quindi vengono elaborati e riversati nel software gestionale del commettente: per tale motivo l'ambito di utilizzo è molto professionale e in tale contesto si è più interessati al fatto che la logica di funzionamento sia corretta e affidabile, un pò meno all'aspetto grafico e alle funzionalità supplettive.

Per questo motivo pur avendo lavorato molto su questo progetto per la  preparazione dei pacchetti di installazione per Android colpevolmente non avevo mai prestato eccessiva attenzione alle versioni da utilizzare dell'sdk per la compilazione e il target, e quindi in generale al valore assunto dai campi minSdkVersion, targetSdkVersion, compileSdkVersion in visual studio. La parte piu importante erano gli esiti degli unit test a corredo !

In questa terzaparte si continua ad esporre l’utilizzo del Lazy in ambiti multithread.

Quanto visto nella parte precedente cioè l'utilizzo della classe Lazy senza usare costrutti particolariespone come anche a fronte di più thread tutto funziona correttamente e senza intoppi.

Possono però esistere casi reali in cui si rende necessario avere maggiore possibilità di configurarne il comportamento.

Per esempio l’inizializzatore della classe T, o anche il codice a contorno, può avere al suo interno dei lock o altro, che possono non andare d’accordo con i lock presenti all’interno della classe Lazy, e questa coesistenza può provocare deadlock.

In altre parole come detto l’oggetto Lazy è thread-safe, e quindi per esempio affinché il codice dell’inizializzatore della classe T sia tale vengono usati giocoforza all’interno del framework qualche sorta di lock: questo non solo introduce penalità di perfomance ma può portare (anche se in rari casi) a deadlock che possono occorrere sopratutto a fronte della presenza di altri lock posti nel codice utilizzatore scritto da noi.

Un altro caso può essere legato al fatto che pur essendo in ambiente multithread non siamo interessati al fatto che la classe Lazy sia thread-safe poiché si desidera gestire questo aspetto nel codice consumatore.

In altri termini si desidera delegare la gestione dell’accesso concorrente all’inizializzatore nonché alle proprietà Value e IsValueCreated a codice scritto esternamente da noi, questo con l’ovvio intento di spremere al massimo le perfomance.

Ecco la seconda parte della piccola serie dedicata all'oggetto Lazy<T>. Nel. post precedente ho inziato a esporre i rudimenti iniziali relativi alla classe.

Ora occorre anche ragionare su cosa succede in ambienti multi-thread quando si richiama la proprietà value da Lazy.

Al rientro dalla ferie mi sono trovato a gestire un problema particolarmente rognoso che riguardava tra le altre cose l'utilizzo imporprio della classe Lazy.

Siccome in realtà non conoscevo in modo approfondito questa classe, ho dovuto studiarla e ho verificato come in realtà questa possa essere utile in diversi contesti.

Ho anche ritenuto l’argomento abbastanza interessante e per questo ho pensato di scriverne qualcosa.Spero possa interessare anche Voi.

Iniziamo con il dire a cosa serve: lo scopo del Lazy è quello di gestire in modo efficace un tipo di variabile T molto “pesante” e impegnativa, generalmente rappresentato da una classe (anche se può essere un qualsiasi tipo reference o value).

Con il termine pesante mi riferisco a una classe che gestisce al suo interno molti dati e/o la cui procedura di attivazione è molto onerosa.

In pratica Lazy permette di ottenere l’inizializzazione differita: quindi il tipo T specificato non sarà mai instanziato, e quindi occuperà risorse, sino a quando non verrà utilizzato almeno una volta.

L’utilizzo pratico è relativamente semplice: nella dichiarazione dell'oggetto Lazy si sostituisce a T il nome della classe, e quindi quando occorre un'istanza della classe T si utilizza la proprietà value offerta da Lazy.

Certo, è possibile assolutamente scrivere per nostro conto la logica che permetta di instanziare un oggetto solo quando e se necessario, ma il .Net ci permette di avere questa possibilità che in realtà ci esemplifica non poco il lavoro.