Archive for March 17, 2009

Usings y Object Initializers == Problemas!

Revisando mis links diarios me topo con esta noticia del famoso Ayende (alias de Oren Eini) acerca del uso de Objects Initializers en using statements, explico un poco de que se trata:

Como ustedes recuerdan, objetos que obedecen a la Dispose Pattern, como por ejemplo los DataReaders en ADO.net, mantienen un patron de “destrucción” con instrucciones de liberación de recursos o instrucciones de destrucción del objeto, en otras palabras, que hacer cuando el objeto ya no es necesario (no implica que deterministicamente destruimos al objeto, eso es otrotema):

// Hacemos lo que queremos con el objeto repository
var repositorio = new UserRepository();
repositorio.Dispose();

Bien, de igual manera el compilador de C# 3.0 nos ofrece la opción de inicializadores de objeto, imaginemos que el objeto repositorio pueda tener un parámetro opcional con la información del “nombre” del repositorio (nuevamente un ejemplo silly):

// forma C# 2.0
var repositorio = new UserRepository();
repositorio.Name = "Mi repo";

// forma C# 3.0 con object initializers
var repositorio = new UserRepository() { Name = "Mi repo" };

Internamente el compilador agrega la siguiente línea con un setter a la propiedad, interesante no?.

Bien, como recordaran, la Disposable Pattern es tan común que hay una forma de “resumirla” o un shortcut en la framework:

using (var repositorio = new UserRepository()) {
    // Hago lo que quiera con el objeto
}

Si el objeto generara una excepción DENTRO del bloque de igual manera se correría Dispose, eso hace más segura nuestra implementación.

Bien, que tal si mezclamos ambas?:

using (var repo = new UserRepository() { Name = SimpleClass.GetName() }) {
// Blah
}
// PROBLEMA!!! lo "equivalente" generado
var repo = new UserRepository();
repo.Name = SimpleClass.GetName();
using (repo) {
// Blah
}

Aunque mi ejemplo es realmente trivial y hasta “tonto” podemos observar claramente el problema, si el inicializador “repo.Name = ’blah’” fallara, NUNCA entraríamos al using, por lo tanto no se correría Dispose(), o sea, que recursos no se liberarían como nosotros esperaramos.

Tengo entendido que esto es “by design” (realmente no se porqué), y que el compilador de Mono (el MCS) lo genera de la manera “ideal”. Esperemos que para C# 4.0 compiler esto sea resuelto, mientras tanto, eviten object initializers en declaraciones de sentencias using.

Hasta la próxima!

UPDATE:

Para contestar uno de los comentarios: si, si definimos tu "conexión" de la manera:

using (var con = new SqlConnection() { MyProperty = int.Parse("error") }) {
// Buh! nunca entro aqui! (ni corro dispose!)
}

En ese caso se genera una instancia con nombre "impronunciable" y se usa el setter, para luego entrar al bloque using. Eso involucra que cuando falle el setter de la propiedad tu objeto nunca entrará al bloque using, para evitar eso deberiamos cambiar el código para que luzca algo asi:

using(var con = new SqlConnection()) {
    con.MyProperty = int.Parse("error");
}

La última sentencia funcionará como esperamos, se creará una excepción, pero debido a que la excepción se generó dentro del bloque se correrá exitosamente el Dispose del objeto SqlConnection.

Libro gratuito de la Entity Framework

Aunque no soy un “usuario” que digamos de la Entity Framework, es interesante ver como va creciendo. Uno de los principales problemas de un “early adopter” es la falta de información al respecto y el no saber por donde comenzar. Alguien podrá decirme “Internet” pero el recopilar la información lleva algo de tiempo y no mantiene coherencia la mayor parte del tiempo.

Afortunadamente siempre hay más de alguna alma piadosa que nos trae joyas y las da de forma gratuita, tal es el caso de Zeeshan Hirani, quien ha creado un libro de aprendizaje de la Entity Framework y lo ha liberado para que de forma gratuita (si, leyo bien, gratuita) puedan bajarlo.

Les dejo con el link Entity Framework Free Book