Inicialización rápida de objetos en C# 3.0 y VB.Net 9.0

Manos de afanoso desarrollador trabajandoComo ya venimos comentando hace tiempo, la nueva versión de ambos lenguajes viene repleta de novedades y mejoras pensadas para hacernos la vida más fácil y, por tanto, aumentar la productividad de los desarrolladoradores. Bueno, no sé si fue así o en realidad es que simplemente eran necesarias para Linq y por eso fueron incluidas ;-), pero el caso es que a partir de las versiones 3.0 y 9.0 de C# y VB.NET respectivamente, tenemos a nuestra disposición interesantísimas herramientas que deberíamos conocer para sacar el máximo provecho a nuestro tiempo.

En esta ocasión vamos a centrarnos en los inicializadores de objetos, una nueva característica destinada, entre otras cosas, a ahorrarnos tiempo a la hora de establecer los valores iniciales de los objetos que creemos desde código.

Y es que, hasta ahora, podíamos utilizar dos patrones básicos de inicialización de propiedades al instanciar una clase:


  • que fuera la clase la que realizara esta tarea, ofreciendo al usuario de la misma constructores con distintas sobrecargas cuyos parámetros corresponden con las propiedades a inicializar.
    // Constructor de la clase Persona:
    public Persona(string nombre, string apellidos, int edad, …)
    {
    this.Nombre = nombre;
    this.Apellidos = apellidos;
    this.Edad = edad;

    }
    // Uso:
    Persona p = new Persona(«Juan», «López», 32, …);
     
  • o bien dejar esta responsabilidad al usuario, permitiéndole el acceso directo a propiedades o campos del objeto creado.
    // Uso:
    Persona p = new Persona();
    p.Nombre = «Juan»;
    p.Apellidos = «López»;
    p.Edad = 32;

     

Cualquiera de las dos formas anteriores, así como de opciones intermedias que combinen ambas ideas, tiene sus ventajas e inconvenientes, pero son igualmente tediosas. Si hablamos de clases con un gran número de propiedades, la cantidad de líneas de código necesarias para realizar una inicialización son realmente importantes.

Los inicializadores de objetos permiten, en C# y VB.Net, realizar esta tarea de forma más simple, simplemente indicando en la llamada al constructor el valor de las propiedades o campos que deseemos establecer:

// C#:
Persona p = new Persona { Nombre=»Juan», Apellidos=»López», Edad=32 };


‘ VB.NET:
Dim p = New Persona With {.Nombre=»Luis», .Apellidos=»López», .Edad=32 }


Los ejemplos anteriores son válidos para clases que admitan constructores sin parámetros, pero, ¿qué ocurre con los demás? Imaginando que el constructor de la clase Persona recibe obligatoriamente dos parámetros, su nombre y apellidos, podríamos instanciar así:

// C#:
Persona p = new Persona («Luis», «López») { Edad = 32 };


‘ VB.NET:
Dim p = New Persona («Luis», «López») With { .Edad = 32 }

Aunque es obvio, es importante tener en cuenta que las inicializaciones (la porción de código entre llaves «{» y «}») se ejecutan después del constructor:



// C#:
Persona p = new Persona («Juan», «Pérez») { Nombre=»Luis» };
Console.WriteLine(p.Nombre); // Escribe «Luis»

‘ VB.NET:
Dim p = New Persona («Juan», «Pérez») With { .Nombre=»Luis» }
Console.WriteLine(p.Nombre); ‘ Escribe «Luis»


Y un último apunte: ¿cómo inicializaríamos propiedades de objetos que a su vez sean objetos que también queremos inicializar? Suponiendo que en nuestra clase Persona hemos incluido una propiedad llamada Domicilio que de tipo Localizacion, podríamos inicializar el bloque completo así:

// C#:
// Se han cortado las líneas para facilitar la lectura
Persona p = new Persona()
{
    Nombre = «Juan»,
    Apellidos = «López»,
    Edad = 55,
    Domicilio = new Localizacion
    {
        Direccion = «Callejas, 34»,
        Localidad = «Sevilla»,
        Provincia = «Sevilla»
    }
};

‘ VB.NET:
‘ Se han cortado las líneas para facilitar la lectura
Dim p = New Persona() With { _
  .Nombre = «Juan», _
  .Apellidos = «López», _
  .Edad = 55, _
  .Domicilio = New Localizacion With { _
    .Direccion = «Callejas, 23», _
    .Localidad = «Sevilla», _
    .Provincia = «Sevilla» _
    } _
  }
 
En fin, que de nuevo tenemos ante nosotros una característica de estos lenguajes que resulta interesante por sí misma, aunque toda su potencia y utilidad podremos percibirla cuando profundicemos en otras novedades, como los tipos anónimos y Linq… aunque eso será otra historia.

Publicado en: http://www.variablenotfound.com/.

6 comentarios sobre “Inicialización rápida de objetos en C# 3.0 y VB.Net 9.0”

  1. Pues no le veo la ventaja por ningún lado.
    El ahorro es «nombreDeLaInstancia.» que con el intellisense es más que rápido. La diferencia es que lo escribes en horizontal en vez de en vertical.

    Si son muchas propiedades las que hay que dar valor, ¿lo vas a hacer así? ¿No te parece realmente «inmantenible»?

    Un saludo,

  2. J,

    – El ahorro es «nombreInstancia.» multiplicado por N, la cantidad de miembros a inicializar.

    – No veo que ese código se haga inmantenible cuando sean muchas propiedades… De hecho me parece mucho más claro que si se llamara a un constructor con muchos parámetros, donde podría no quedar claro qué valor se asocia a qué parametro (estoy hablando de C#). Y tan claro y mantenible como si se usara un constructor sin argumentos y luego «nombreInstancia.nombrePropiedad = valorInicial;» para cada una de las propiedades.

    Saludos – Octavio

  3. Holas.

    Coincido con Octavio en sus apreciaciones. Al final, como todo, decidirse por el uso de inicializadores en los casos «normales» será cuestión de preferencias del desarrollador, pero no creo que este método introduzca problemas de mantenibilidad en el código, a la vez que nos aporta una forma muy cómoda y ágil para inicializar objetos.

    De todas formas, como comentaba en el post, la potencia y utilidad de esta característica es más apreciable al usar tipos anónimos, linq o, por ejemplo, para utilizar interfaces fluidos.

    Saludos.

  4. Hola, Ovtavio,

    – El ahorro es de teclear «n» «o» «m» «TAB» «punto» (te aseguro que con un poco de práctica se puede hacer realmente rápido 😉 Es cierto N veces.

    – Dices que no es inmantenible. Es decir que «para muchas propiedades» te parece una opción buena. ¿Más de 6? Supongo que tendrás monitor extendido o una especial predilección por el scroll horizontal frente al vertical 😉 o que cortarás la línea (que no es precisamente corta)…

    Supongo que José tiene razón en que esto tiene más sentido en «tipos anónimos, linq…», porque para lo demás… Sinceramente no veo que aporte gran cosa. Otra opción para hacer algo que se podía hacer antes tardando lo mismo o poco más o menos…

    Saludos.

  5. J, yo usaría la escritura horizontal cuando son un par de miembros o tres a inicializar; en otros casos lo escribiría para abajo, como siempre. La «horizontalidad» es una opción, no una obligación, por lo que el problema de mantenibilidad que ves no sería tal. Y como comenta Octavio, este código es mucho más legible que usar parámetros en el constructor, y al menos igual de legible que inicializar miembro a miembro después de instanciar.

    Que si ahorramos tiempo o no teclear… está claro que sí. ¿Mucho, poco…? Todo lo que se puede; lamentablemente no es demasiado, pero bueno, a los que llevamos ya muchos kilómetros de código recorrido cualquier alivio para las muñecas bueno será. Es como utilizar i++ ó i=i+1: no se ahorra casi nada, pero a casi todos nos gusta más la primera forma.

    Y efectivamente, coincido en que antes se podía hacer lo mismo tardando prácticamente el mismo tiempo. Si te fijas, esto ocurre con casi todo: propiedades automáticas, métodos de extensión, inferencia de tipos, incluso las lambda…  Sin embargo, todas estas novedades forman parte de la evolución del lenguaje y debemos prestarles atención para sacar el máximo provecho a nuestra herramienta de trabajo. Y más aún cuando sirven de base para otras funciones avanzadas (y aquí aparece de nuevo Linq!).

    Saludos.

    PD: Y gracias por vuestros comentarios, es magnífico conocer otros puntos de vista y opiniones.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *