5/12/2011 19:31 El Bruno

[UNITY] Trabajando con Singleton utilizando #UNITY

image47dd1de4

Buenas,

hace unos días, Jorge escribió un artículo destripando el funcionamiento de un Singleton con .Net. Luego llegó José y también aportó un poco de luz al respecto; y yo me dije a mi mismo,

¿Pero estos de que hablan? programar un Singleton a mano, están locos o qué?

Vamos que desde el Edu definió a UNITY como “ese que hace los news” pues creo que no he creado un objeto con “new” desde hace bastante tiempo. Para los que no conocen UNITY, pues en pocas palabras es un inyector de dependencias creado por el equipo de Patterns & Practices de Microsoft que ya va por su versión 2.0 y que, como a la cerveza negra, te termina gustando cuando le agarras el gustito.

Veamos un ejemplo muy pero muy simple en el que utilizaremos una clase llamada “ClaseChorra” para validar las instancias que se creen de la misma.

El modelo de Singleton está basado en el ejemplo simple que explica Jorge en su post.

   1: class ClaseChorra
   2: {
   3:     private static ClaseChorra claseChorra;
   4:     public System.Guid Id { get; set; }
   5:     public ClaseChorra()
   6:     {
   7:         Id = System.Guid.NewGuid();
   8:     }
   9:     public override string ToString()
  10:     {
  11:         return Id.ToString();
  12:     }
  13:     public static ClaseChorra GetSingletonInstance()
  14:     {
  15:         return claseChorra ?? (claseChorra = new ClaseChorra());
  16:     }
  17: }

 

Antes de seguir >> DisclaimerHoy en España es Luernes (lunes + viernes) con lo que tampoco me estoy esforzando mucho con los ejemplos, es lo que suele suceder después de una semana ardua de trabajo.

No hace no falta que explique que si creo objetos a cholón, como explica Jorge en su post, pues tendré errores de lo más variado.
Por ejemplo el siguiente código me deja una única instancia con el mismo ID para cada ejecución de la misma:
 
   1: class Program
   2: {
   3:     static void Main(string[] args)
   4:     {
   5:         var c1 = ClaseChorra.GetSingletonInstance();
   6:         var c2 = ClaseChorra.GetSingletonInstance();
   7:         c2.Id = Guid.NewGuid();
   8:         Console.WriteLine("c1: {0}", c1);
   9:         Console.WriteLine("c2: {0}", c2);
  10:         Console.ReadLine();
  11:     }
  12: }

El resultado es:

   1: c1: 34baaf27-87de-42f7-b2ad-046e35ee65fa
   2: c2: 34baaf27-87de-42f7-b2ad-046e35ee65fa

 

Pues bien, hasta aquí el ejemplo de Jorge. Pero ¿cómo lo haríamos con UNITY?. Lo ideal es leer el artículo de MSDN “Using Lifetime Managers” donde se explican diferentes opciones para trabajar con el registro de tipos y de objetos en Unity. Yo dejaré un par de ejemplos.

Por ejemplo, en la siguiente porción de código, estoy definiendo un UnityContainer para que el mismo se encargue de crear por mí los objetos que yo necesito (recuerden las palabras del Edu > “UNITY es el que hace los news"). Utilizando el container creo las instancias c1 y c2 y luego muestro los valores de la misma.

   1: static void Main(string[] args)
   2: {
   3:     var myContainer = new UnityContainer();
   4:     myContainer.RegisterType<ClaseChorra>();
   5:     var c1 = myContainer.Resolve<ClaseChorra>();
   6:     var c2 = myContainer.Resolve<ClaseChorra>();
   7:     c2.Id = Guid.NewGuid();
   8:     Console.WriteLine("c1: {0}", c1);
   9:     Console.WriteLine("c2: {0}", c2);
  10:     Console.ReadLine();
  11: }

 

El resultado son 2 instancias diferentes de la misma clase:

   1: c1: dea932a8-7ce6-4f44-aa6c-89cb04bed186
   2: c2: 011f211a-9a83-463d-81ea-566ef0dbbdab

 

Ahora bien, si yo quisiese que siempre que se cree un objeto del tipo ClaseChorra, el mismo sea la misma instancia para todos, pues simplemente le digo a UnityContainer que tipo de LifeTimeManager debe utilizar. Existen varias opciones, pero para el siguiente ejemplo utilizaremos un PerThread, que nos ayuda a tener una única instancia del objeto por thread.

   1: static void Main(string[] args)
   2: {
   3:     var myContainer = new UnityContainer();
   4:     myContainer.RegisterType<ClaseChorra>(new PerThreadLifetimeManager());
   5:     var c1 = myContainer.Resolve<ClaseChorra>();
   6:     var c2 = myContainer.Resolve<ClaseChorra>();
   7:     c2.Id = Guid.NewGuid();
   8:     Console.WriteLine("c1: {0}", c1);
   9:     Console.WriteLine("c2: {0}", c2);
  10:     Console.ReadLine();
  11: }

 

Como bien estarás suponiendo, ahora las clases c1 y c2 son la misma:

   1: c1: 84b8087b-48f5-4519-9362-b5239603ac0a
   2: c2: 84b8087b-48f5-4519-9362-b5239603ac0a

 

Así que ya sabes, o te pones a codificar todo el patrón Singleton super-sure en tu código y dejas que “UNITY haga los news por tí” Risa

 

Saludos @ Home

El Bruno

   

Fuentes:

Archivado en: ,,,
Comparte este post:

# re: [UNITY] Trabajando con Singleton utilizando #UNITY

Monday, December 5, 2011 8:36 PM by Luis Ruiz Pavón

Hola Bruno,

Yo para singleton en unity utilizo ContainerControlledLifetimeManager. Sino me equivoco y si me equivoco que me corrija alguién, creo que la diferencia frente a PerThreadLifetimeManager es que todos los hilos compartirán la misma instancia ya que PerThreadLifetimeManager es un  "per-thread singleton". Además, he leido por ahí que la implementación interna de PerThreadLifetimeManager es incorrecta y podría dar problemas.

Un saludo y buen post ;)

# re: [UNITY] Trabajando con Singleton utilizando #UNITY

Tuesday, December 6, 2011 12:07 PM by jfbonnin

Hola,

cuidado con esta implementación!

Si bien es cierto que Unity te permite gestionar tus clases Singleton, con la implementación que propones el objeto será único por thread y no por AppDomain. No es un error, pero es un comportamiento diferente, para evitarlo hay que usar el LifetimeManager que comenta Luis. Además en este caso la implementación es eager loaded y no lazy loaded.

Para ver la diferencia claramente, si utilizaras la clase singleton para gestionar una conexión a base de datos y tuvieras mil threads diferentes usando la clase, con la implementación que propones tendrías mil conexiones de base de datos abiertas, mientras que con la de Jorge o la mía solo una.

Siguiendo en la misma línea, si la clase singleton abriera la conexión a base de datos en el constructor, en tu implementación se abriría la conexión a base de datos en el momento que instancias la clase (Resolve<ClaseChorra>), mientras que en las implementaciones que proponemos Jorge y yo (la última en ambos casos), la conexión a base de datos no se abriría cuando instancias la clase, sino cuando fueras a utilizarla por primera vez por ejemplo cuando fueras a ejecutar una consulta.

Aunque las tres implementaciones son Singleton, tienen un comportamiento muy diferente. Como decía el anuncio de las ovejas churras y merinas se parecen pero no son iguales ;)

Un saludo

# re: [UNITY] Trabajando con Singleton utilizando #UNITY

Friday, December 9, 2011 8:02 PM by El Bruno

@Luis y @Jose, mira que son delicados ehhh !!!

q lo mio es de vago :D (efectivamente ya por Twitter estuvimos hablando del poder ed ContainerControlledLifetimeManager y ChuckNorris).

Con respecto al scope de utilización, pues como todo > depende. Unity te da un marco cerrado con muchas opciones ya desarrolladas, pero lo bueno sigue siendo conocer las tripas para ver como funciona .Net

Saludos y gracias por el aporte