Archivo

Archivos de junio, 2012

El Tipo Lazy en .Net 4.0

Lunes, 25 de junio de 2012

Todo buen programador necesita un poco de pereza. Algo que le lleve a intentar escribir poco, a no repetirse, a hacer las cosas cada día mejor y a no caer en tareas repetitivas. Últimamente el código “vago” también está en boca de todos, ya sean clases que no se inicializan hasta que se usan o consultas a la BBDD que no se lanzan hasta el último momento.

Tradicionalmente, cuando teníamos una dependencia con una inicialización pesada y que además no sabíamos si se iba o no a ejecutar, hacíamos algo parecido a esto:

//C#

     private Dependencia _Fdependencia;
     private Dependencia _Dependencia
     {
        get { return _Fdependencia ?? (_Fdependencia = new Dependencia()); }
        set { _Fdependencia = value; }
     }
'VB.NET
     private  _Fdependencia as Dependencia
     private Property _Dependencia as Dependencia
        get
          If IsNothing(_Fdependencia) Then _Fdependencia = New Dependencia()
          Return _Fdependencia
        End Get
        Set(value As Dependencia)
           _Fdependencia = value
        End Set
     End Property

Pero desde el lanzamiento del framework 4.0, diponemos del tipo Lazy<> que se ocupa del trabajo por nosotros. En este ejemplo la propiedad no se inicializará hasta que se use por primera vez.

 

//C#
private Lazy<Dependencia> _Dependencia { get; set; }
'VB.NET
private property  _Dependencia as Lazy(Of Dependencia)

En ocasiones no se trata de llamar simplemente a un constructor, sino que el proceso de inicialización de la dependencia puede ser más complejo, requiriendo quizá la llamada a un método:

 

//C#
private Lazy<Dependencia> _Dependencia = new Lazy<Dependencia>(InicializarDependencia);
private static Dependencia InicializarDependencia()
{

     //hacer cosas
     return new Dependencia();

}
private  _Dependencia as Lazy(Of Dependencia) = new Lazy(Of Dependencia)(AddressOf InicializarDependencia)
private shared Function  InicializarDependencia() As Dependencia 
     'hacer cosas
     return new Dependencia()
End Function

O si lo preferimos podemos usar expresiones lambda para conseguir esto mismo:

//C#
private Lazy<Dependencia> _Dependencia = new Lazy<Dependencia>(()=>
          {
           //hacer cosas
           return  new Dependencia();
          });

 

        private property _Dependencia as Lazy(Of Dependencia)  =new Lazy(Of Dependencia)(function()
                                'hacer cosas
                                 Return New Dependencia
                                 End Function)

En todos estos casos, el proceso de inicialización solo se llevará a cabo al usar la propiedad (o campo) y solo la primera vez.  Para acceder al “tipo interno” lo hacemos mediante la propiedad Value. Es decir, que si queremos llamar al método Metodo1 de _Dependencia lo que haremos es _Dependencia.Value.Metodo1.

Así mismo, el constructor de Lazy<> dispone de una sobrecarga para indicarle si queremos que sea Thread-Safe. (por defecto es true):

//C#
private Lazy<Dependencia> _Dependencia = new Lazy<Dependencia>(InicializarDependencia,false);
'VB.NET
private  _Dependencia as Lazy(Of Dependencia) = new Lazy(Of Dependencia)(lazythreadsafetymode.PublicationOnly)

También tenemos sobrecargas para indicarle el tipo de Thread-Safe que queremos que se aplique:

//C#
private Lazy<Dependencia> _Dependencia = new Lazy<Dependencia>(InicializarDependencia,LazyThreadSafetyMode.PublicationOnly);
'VB.NET
private  _Dependencia as Lazy(Of Dependencia) = new Lazy(Of Dependencia)(lazythreadsafetymode.PublicationOnly)

Pronto veremos como hacer casar todo esto con conceptos como inversión de control, mientras, como ejemplo de uso, os recomiendo este enlace de John Skeet sobre del patrón Singleton que finaliza en una implementación usando Lazy<> John Skeet Singleton.

.Net