Saltar al contenido

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript... y lo que venga ;)

17 años online

el blog de José M. Aguilar

Inicio El autor Contactar

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web
ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript...

¡Microsoft MVP!
lunes, 22 de octubre de 2007
Como en otros lenguajes y plataformas, .Net permite la creación de enumeraciones de campos de bits, así como su tratamiento de forma muy sencilla e intuitiva para el desarrollador.

A diferencia de las enumeraciones normales, cuyos elementos son habitualmente excluyentes, las de campos de bits permiten la combinación de ellos, permitiendo su utilización en escenarios algo más complejos que los primeros. Fijaos en los siguientes ejemplos.

Si pretendemos almacenar el estado de las luces de un semáforo, donde sólo uno de los elementos está activo, posiblemente optaríamos por crear una enumeración como la siguiente, de lo más tradicional:

public enum EstadoSemaforo
{
Rojo, Amarillo, Verde
}
 
En cambio, si deseásemos almacenar el estado de las lucecillas del teclado de nuestro PC (BloqMays, BloqNum y BloqDespl), tenemos un total de 8 combinaciones de estados distintos (desde el "todas apagadas" hasta "todas encendidas"), lo cual ya se convierte en incómodo para utilizar una enumeración tradicional de selección única. Y es aquí donde saltan a la palestra los campos de bits, permitiéndonos hacer cosas como esta:

[Flags]
public enum LedStatus
{
BloqMays=1,
BloqNum=2,
BloqDespl=4,
All=BloqMays | BlogNum | BloqDespl,
None = 0
}

Vamos a explicarlo paso a paso. En primer lugar, nos encontramos con el atributo [Flag], que indica a .NET que la enumeración es de este tipo y que debe permitir la combinación de elementos como veremos un poco más adelante.

A continuación se define la enumeración como siempre, aunque estamos forzando a que cada elemento de interés se asocie a un valor potencia de 2, que corresponderá con el valor decimal de su representación binaria. De esta forma, cuando combinemos elementos, su suma lógica nos dará valores únicos que permitirán determinar cuáles de ellos se están uniendo. El siguiente cuadro quizás ayude a entender esto mejor:

Como podemos ver, a cada elemento de la enumeración se asigna un bit en el interior de un byte (o conjunto de bytes); así, BloqMays está asignado al bit 0 (con un valor en decimal de 2^0=1), BloqNum al bit 1 (con valor 2^1=2), etc.

De esta forma, cuando estén activas las luces del bloqueo de mayúsculas (BloqMays) y el del desplazamiento (BloqDespl), estarán a uno los bits 0 y 2, mientras que el bit 1 estará a cero, resultando el número "101" cuyo valor será cinco.

Siguiendo con el ejemplo, tenemos un elemento ("All") que se define como combinación de los anteriores. Esto puede ser util para facilitar las comparaciones con combinaciones muy frecuentes o cuya agrupación tenga un sentido especial, como podría ser un elemento del tipo SuperUsuario en una enumeración de tipos de usuario de un gestor de contenidos:

public enum TipoDeUsuario
{
Anonimo = 0,
Registrado = 1,
Gestor = 2,
SuperUsuario = Registrado | Gestor;
}
 
Volvemos ahora a algo que antes dejamos un poco a medias... ¿para qué el atributo [Flags] que adorna la enumeración? ¿No podemos hacer prácticamente lo mismo sin él, simplemente usando valores potencia de dos en las enumeraciones? Y la respuesta es sí, exactamente lo mismo. La única diferencia que he encontrado es que el método ToString() es capaz de mostrar la combinación de valores, es decir:

LedStatus leds = LedStatus.BloqMays | LedStatus.BloqNum
Console.WriteLine(leds);
 
Si hemos utilizado el atributo [Flags] por consola podremos ver el texto "BloqMays, BloqNum". Si no lo usamos, sólo aparecerá "3", el valor numérico de la combinación de ambos elementos. Supongo que alguna diferencia más habrá, pero como digo, no la he encontrado.

Por último, comentar que existen varias ventajas a la hora de decidirse a utilizar este tipo de enumeraciones. Sin duda, se trata de una forma realmente compacta de almacenar información de estado o indicadores combinables. Eso, aunque hoy en día cada vez tiene menos importancia, era hace tiempo motivo más que suficiente para propiciar su uso en programación ligada al bajo nivel, como en C o ensamblador, donde además existe mucha facilidad para el tratamiento de bits.

También es ventajosa su versatilidad a la hora de tratar los valores. Con conocimientos básicos de aritmética binaria podemos hacer cosas como alternar entre activo e inactivo (operador ~ o Xor), activar varios elementos de golpe (usando máscaras OR) o desactivarlos (máscaras AND), realizar desplazamientos laterales binarios a derecha o izquierda (L ó RShifts), etc.

Sin embargo, el uso de estas enumeraciones presenta varios inconvenientes también relacionados con su naturaleza binaria. Citar, por ejemplo, que la asignación hay que realizarla mediante operadores de combinación lógicos de bit para no alterar el estado de otros indicadores, es decir:


// la siguiente instrucción activa el
// BloqMays, pero desactiva todos los demás

estado = LedStatus.BloqMays;

// las siguientes instrucciones
// activan el bit 0 (BlockMays)
// dejando intactos los demás leds:

estado = estado | LedStatus.BloqMays;
estado |= LedStatus.BloqMays;
 
De la misma forma, no podemos realizar comparaciones utilizando los operadores de igualdad, puesto que sólo evaluarán a cierto sin los dos operandos son estrictamente idénticos:

if(estado==LedStatus.BloqMays)
// sólo se cumple si está
// activo únicamente BloqMays
 
Las comparaciones deben realizarse utilizando de nuevo operadores de aritmética binaria, concretamente el AND lógico, de la siguiente forma:

if ( (estado & LedStatus.BloqMays) != 0)
// se cumple cuando el BloqMays
// está activo, independientemente del resto
 

Publicado en: www.variablenotfound.com.
jueves, 18 de octubre de 2007
Si hace unos días Jeffrey Palermo recogía en su blog la presentación del futuro ASP.Net MVC Framework, es ahora el propio Scott Guthrie, uno de los padres de la criatura, el que hace una pequeña introducción en su bitácora sobre esta tecnología que se avecina.

Aunque en el post de hace unos días donde me hacía eco de la presentación ya recogí alguna de las características principales, no está de más visitar el blog de Scott para conocer, de primera mano, por dónde van los tiros. Además comenta que las próximas semanas seguirá publicando artículos explicando cómo funciona el framework, habrá que estar atentos a su página.

Por último, decir que hay una traducción al español del post original en Thinking in .net, de la mano de Juan María Laó.
miércoles, 17 de octubre de 2007
Hace unos días publiqué un post donde comentaba lo que sin duda era mi descubrimiento del mes: la posibilidad de codificar constantes de cadena multilíneas en C# al más puro estilo Heredoc de PHP y otros lenguajes.

Al día siguiente en la oficina pude observar que, como sospechaba, no era una característica muy conocida (aunque todo el mundo sabía que la arroba @ se utilizaba para introducir fácilmente caracteres extraños en los strings) y que su utilidad era enorme a la hora de asignar sentencias SQL largas, porciones de scripts en código, HTML, etc. La legibilidad que aporta al código es increíble.

Sin embargo, hay un detalle importante que olvidé comentar en el post: para concatenar cadenas definidas de esta manera hay que utilizar la arroba en cada una de las subcadenas constantes.

Para que quede más claro, ahí va un ejemplo en C# donde se pretende incluir el valor de la variable "pattern" en una sentencia SQL:

string sql =
@"SELECT product_name,
product_details,
total_rows
FROM (
SELECT product_name,
product_details,
total_rows,
rownum row_counter
FROM (
SELECT product_name,
product_details,
count(*) OVER () total_rows
FROM products
WHERE product_name
like '%" + pattern + @"%'
ORDER BY product_name
)
)
WHERE row_counter between v_start_row and v_end_row;";
 
Y sí, sé que el ejemplo no es muy correcto desde el punto de vista de la construcción de la sentencia SQL (ojo a la inyección SQL), pero creo que ilustra perfectamente la forma de incluir un contenido variable en el interior de una cadena de este tipo.
martes, 16 de octubre de 2007
Desde este mismo momento, y gracias a la gentil invitación del amigo Rodrigo Corral, estoy publicando en Geeks.ms, una selecta comunidad de desarrolladores orientada a la programación con y para tecnologías de Microsoft. La compañía no puede ser mejor: un grupo de auténticos maestros, MVPs, MCP ó MCT como El Guille, Jorge Serrano, el mismo Rodrigo, Sergio Tarrillo, El Bruno, y un larguísimo etcétera (que no se ofenda nadie, en algún momento hay que acabar la lista ;-)).

Por mi parte, seguiré con lo mismo que vengo haciendo desde hace ya año y medio en Variable Not Found: escribir sobre lo que más me gusta, el mundo del desarrollo de software. La diferencia es que ahora llegará a más lectores. :-)

De momento, hasta que descubra otra forma más apropiada, realizaré crossposting artesano (vamos, copiar y pegar) de las entradas de VariableNotFound.com hacia mi dirección en Geeks, http://geeks.ms/blogs/jmaguilar.

Nos vemos también por allí.
miércoles, 10 de octubre de 2007
Siempre he envidiado a los desarrolladores PHP, Ruby o a las figuras del shell-scripting por poder utilizar heredoc para representar cadenas de caracteres de longitud considerable.

Por si no te habías encontrado antes con este término, heredoc es una forma de escribir cadenas literales de forma directa, sin preocuparse de caracteres de control, secuencias de escape o saltos de línea de forma manual. Simplemente se indica en el comienzo la marca que permitirá identificar su final y el resultado será el conjunto de caracteres contenidos entre el inicio y la marca, todo incluido.

De hecho, Heredoc es una abreviatura de "Here document", que viene a ser algo así como "documento a continuación".

Un ejemplo para enviar al navegador del cliente una porción de código script correctamente formateado sería el que se muestra a continuación. Se puede distinguir la marca de comienzo (<<<) seguida de la etiqueta que se usará para determinar su finalización (EOT); a continuación va el contenido del literal y, por último, la marca asignada al comienzo (EOT):

<?php
echo <<<EOT
function AddCss()
{
var l=document.createElement('link');
l.setAttribute('type','text/css');
l.setAttribute('rel','stylesheet');
l.setAttribute('href','styles.css');
document.getElementsByTagName('head')[0].appendChild(l);
};
EOT;
?>


Sin embargo, y aquí va la buena noticia, resulta que en C# podemos realizar algo bastante parecido precediendo la cadena por el carácter "@" (arroba), de la siguiente forma:

string script =
@"function AddCss()
{
var l=document.createElement('link');
l.setAttribute('type','text/css');
l.setAttribute('rel','stylesheet');
l.setAttribute('href','styles.css');
l.setAttribute('media','screen');
document.getElementsByTagName('head')[0].appendChild(l);
}";
Response.Write(script);


Su principal ventaja es la capacidad de representar texto estructurado como Javascript, CSS, (X)HTML, XML o SQL de forma muy directa, ya véis el ejemplo anterior. Nada de "trocear" la cadena en líneas e ir concatenando, ni de introducir caracteres de escape para saltos de línea o tabulaciones. Todo un gustazo.

Por citar algún inconveniente, la cadena siempre debe acabar en dobles comillas; por tanto, si queremos usar este carácter debemos introducirlo doblemente (por ejemplo ""hola"" en vez de "hola"). Tampoco se realiza sustitución de variables en su interior (como ocurre, por ejemplo, en PHP), por lo que hay que usar los operadores de concatenación.

Aunque un poco menos, sigo envidiando a los Heredockers.