Ir al contenido principal

Programación asíncrona con async/await en .Net

Introducción A partir de la versión 4.5 de .Net framework se ha simplificado de forma considerable la forma en que podemos trabajar con código asíncrono. Con los anteriores frameworks, si queríamos contar con los beneficios de una programación asíncrona nos veíamos obligados a lidiar con una gran complejidad en nuestro código. Esto nos hacía evitar su uso en lo posible a pesar de perder esta importante característica. Stephen Cleary , un MVP especializado en concurrencia define la programación asíncrona como: Una forma de concurrencia que utiliza futuros o "callbacks" para evitar hilos innecesarios. La programación moderna con async y await nos abstrae de la utilización de "callbacks" y nos permite utilizar futuros (Tasks) que se encargarán de notificar al llamante cuando el método asíncrono se complete. async y await Las palabras async y await son las palabras clave que .Net ha introducido en el lenguaje para que podamos implementar métodos asíncronos co...

La importancia del encapsulamiento. Parte 3. Descriptores de acceso. Controlando la forma de acceder al estado.

Descriptores de acceso. Controlando la forma de acceder al estado.

Que una clase permita leer un valor a otra clase que lo requiera no quiere decir que lo pueda modificar. Y si una clase debe poder modificarlo no significa tampoco que lo pueda hacer de forma directa, sino que quizás debería utilizar descriptores de acceso (assessors), también llamados getters and setters o propiedades en .Net.

Usar propiedades es una buena práctica incluso cuando el acceso es directo, es decir, aunque lo único que hagamos sea devolver un valor en el get o asignar un valor en el set. Quién sabe si en un futuro vamos a necesitar un descriptor de acceso con implementación. En este caso sólo tendríamos que implementar la lógica en el get o en el set sin alterar la compatibilidad binaria. Para explicarlo mejor vamos a ver un ejemplo simple del uso de un descriptor de acceso.

Manos a la obra

Imaginemos que tenemos el campo precio que nos guarda un valor de una cantidad de dinero. Si optamos por hacerla público el campo daremos acceso desde el exterior directamente al valor (estado interno del objeto), tanto de lectura como de escritura.
Haciendo esto estamos definiendo para el mundo exterior una interfaz de acceso directo a nuestro valor, es decir, nos hemos comprometido a brindar este acceso para siempre (siempre que queramos respetar la compatibilidad binaria). En caso de que queramos aplicar una lógica de acceso a este valor proporcionando un descriptor de acceso, tendríamos que cambiar la interfaz y por consiguiente tendríamos de cambiar todos los clientes que usan nuestra clase y recompilar de nuevo sus ensamblados.

Encapsulando el campo

Para encapsular la variable la hacemos privada e implementamos una propiedad cuyo get y set establecen la lógica de acceso a este valor. A la variable privada también se le conoce con el nombre de variable de respaldo.
Desde Net 3.0 podemos utilizar una sintaxis mucho más cómoda para este tipo de propiedades que no tienen lógica en sus accesos. Se trata de las propiedades auto-implementadas. El compilador se encargará de crear el campo de “respaldo” de forma transparente para nosotros:

¿Y todo esto para qué?

Ahora imaginemos que debido a un cambio en los criterios de diseño se establece una validación en la que si se intenta escribir una cantidad que sobrepasa un cierto valor debemos lanzar una excepción. Además, si el precio es negativo debemos guardar un 0.

Al tener una propiedad podemos fácilmente agregar esta lógica:
Es decir, se trata de separar el “respaldo” de:
  • la forma en que permitimos modificarla (set) y/o
  • la forma en que servimos el valor al llamante (get)

Accesos restringidos

¿Por qué tener el mismo nivel de visibilidad para la lectura que para la escritura?

Tenemos varias formas de romper esta simetría. No tenemos por qué implementar los dos accesos de una propiedad. Por ejemplo, la siguiente propiedad es de sólo lectura:
Y la siguiente de sólo escritura:
También tenemos los accesos con distinto nivel de lectura y escritura. Por ejemplo, la siguiente propiedad tiene un get y un set, pero el set está limitado por el modificador protected, lo que restringe su acceso sólo para la propia clase y sus extensiones. Desde otras clases se comportará como una propiedad de sólo lectura.
A parte de todo esto, también existen algunas otras razones más para decantarse por propiedades antes de utilizar campos. No voy a entrar a analizar cada una de ellas pero las dejo aquí por si alguien todavía no ve razones suficientes:
  • La reflexión es mucho más simple usando propiedades que campos. Así que si piensas trabajar con reflexión implementa mejor propiedades;
  • No puedes enlazar (Databind) contra campos. Sólo funcionan con propiedades;
  • Puedes implementar inicialización diferida (lazy initialization).

¿Cuándo tiene sentido usar campos públicos?

Hasta el propio framework de .Net utiliza en algunas ocasiones campos públicos en lugar de propiedades. Si sabemos seguro que un valor nunca va a tener una lógica de acceso podemos permitir su acceso directo. Tal es el caso de los campos declarados como <code>const</code> o <code>readonly</code>, como por ejemplo el campo <code>string.Empty</code> del Framework o el campo <code>Math.PI</code>. No tiene mucho sentido aplicarle una lógica a su acceso de lectura. Y al ser constantes de sólo lectura nunca va a existir tampoco una lógica de acceso de escritura.

>> Ir a Parte 4. Encapsular constructores.
<< Volver a Parte 2. Un ejemplo de encapsulamiento en la vida real.

Comentarios

Entradas populares de este blog

La importancia del encapsulamiento. Parte 1. Introducción.

Introducción En programación orientada a objetos el término encapsulamiento es utilizado indistintamente para describir dos conceptos diferentes pero a la vez relacionados entre sí: Como mecanismo de restricción del acceso a componentes de un objeto; Como construcción del lenguaje para facilitar el “empaquetado” del estado y el comportamiento. En este post el significado al que se hace referencia es al primero de ellos. La visibilidad o accesibilidad es el primer paradigma que nos encontramos al empezar a escribir nuestro código. Cuando comenzamos a escribir una clase, interfaz, enumerado o estructura, lo primero que hacemos es establecer su modificador de acceso, y si no lo hacemos, se establecerá el modificador por defecto. Lo mismo ocurre cuando empezamos a escribir cada uno de sus miembros: variables de estado (campos) y métodos: lo primero de todo es escribir su modificador de acceso. A menudo me encuentro con código sin tener en cuenta este aspecto: código demasiado “ab...

La importancia del encapsulamiento. Parte 2. Un ejemplo de encapsulamiento en la vida real.

Un ejemplo de encapsulamiento en la vida real Supongamos un taller de carpintería que fabrica muebles a medida. Por una parte tendríamos el propio taller, que sería la clase a encapsular. Por otra los clientes, que serían nuestros usuarios y representarían las clases que USAN la clase taller. Y por otra parte podríamos pensar en talleres filiales que representarían una especialización del taller matriz, es decir, clases que extienden al taller de carpintería y por lo tanto SON talleres. El taller cuenta con funcionalidades puestas al servicio de los clientes como la elaboración de presupuestos, consulta de catálogos, selección de tipo de madera, selección de color, etc. También cuenta con funcionalidades propias del taller como cortar, lijar, pintar, barnizar, ensamblar mueble, etc. Para la elaboración de los presupuestos el taller matriz cuenta con una tarifa de precios que sólo los talleres pueden acceder para poder elaborar los presupuestos. Esta tarifa la fija el taller mat...

Programación asíncrona con async/await en .Net

Introducción A partir de la versión 4.5 de .Net framework se ha simplificado de forma considerable la forma en que podemos trabajar con código asíncrono. Con los anteriores frameworks, si queríamos contar con los beneficios de una programación asíncrona nos veíamos obligados a lidiar con una gran complejidad en nuestro código. Esto nos hacía evitar su uso en lo posible a pesar de perder esta importante característica. Stephen Cleary , un MVP especializado en concurrencia define la programación asíncrona como: Una forma de concurrencia que utiliza futuros o "callbacks" para evitar hilos innecesarios. La programación moderna con async y await nos abstrae de la utilización de "callbacks" y nos permite utilizar futuros (Tasks) que se encargarán de notificar al llamante cuando el método asíncrono se complete. async y await Las palabras async y await son las palabras clave que .Net ha introducido en el lenguaje para que podamos implementar métodos asíncronos co...