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 ;)

18 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!
Mostrando entradas con la etiqueta c#. Mostrar todas las entradas
Mostrando entradas con la etiqueta c#. Mostrar todas las entradas
domingo, 4 de mayo de 2008
Me he encontrado en el blog de Fresh Logic Studios con un post donde describen una técnica interesante para obtener descripciones textuales de los elementos de una enumeración. De hecho, ya la había visto hace tiempo en I know the answer como una aplicación de los métodos de extensión para mejorar una solución que aportaba en un post anterior.

Como sabemos, si desde una aplicación queremos obtener una descripción comprensible de un elemento de una enumeración, normalmente no podemos realizar una conversión directa (elemento.ToString()) del mismo, pues obtenemos los nombres de los identificadores usados a nivel de código. La solución habitual, hasta la llegada de C# 3.0 consistía en incluir dentro de alguna clase de utilidad un conversor estático que recibiera como parámetro en elemento de la enumeración y retornara un string, algo así como:
        
public static string EstadoProyecto2String(EstadoProyecto e)
{
switch (e)
{
case EstadoProyecto.PendienteDeAceptacion:
return "Pendiente de aceptación";
case EstadoProyecto.EnRealizacion:
return "En realización";
case EstadoProyecto.Finalizado:
return "Finalizado";
default:
throw
new ArgumentOutOfRangeException("Error: " + e);
}
}
 
Este método, sin embargo, presenta algunos inconvenientes. En primer lugar, dado el tipado fuerte del parámetro de entrada del método, es necesario crear una función similar para cada enumeración sobre la que queramos realizar la operación.

También puede resultar peligroso separar la definición de la enumeración del método que transforma sus elementos a cadena de caracteres, puesto que puede perderse la sincronización entre ambos cuando, por ejemplo, se introduzca un nuevo elemento en ella y no se actualice el método con la descripción asociada.

La solución, que como he comentado me pareció muy interesante, consiste en decorar cada elemento de la enumeración con un atributo que describa al mismo, e implementar un método de extensión sobre la clase base System.Enum para obtener estos valores. Veamos cómo.

Ah, una cosa más. Aunque los ejemplos están escritos en C#, se puede conseguir exactamente el mismo resultado en VB.NET simplemente realizando las correspondientes adaptaciones sintácticas. Podrás encontrarlo al final del post.

1. Declaración de la enumeración

Vamos a usar el atributo System.ComponentModel.DescriptionAttribute, aunque podríamos usar cualquier otro que nos interese, o incluso crear nuestro propio atributo personalizado. El código de definición de la enumeración sería así:

using System.ComponentModel;

public enum EstadoProyecto
{
[Description("Pendiente de aceptación")] PendienteDeAceptacion,
[Description("En realización")] EnRealizacion,
[Description("Finalizado")] Finalizado,
[Description("Facturado y cerrado")] FacturadoYCerrado
}
 

2. Implementación del método de extensión

Ahora vamos a crear el método de extensión (¿qué son los métodos de extensión?) que se aplicará a todas las enumeraciones.

Fijaos que el parámetro de entrada del método está precedido por la palabra reservada this y el tipo es System.Enum, por lo que será aplicable a cualquier enumeración.

using System;
using System.ComponentModel;
using System.Reflection;

public static class Utils
{
public static string GetDescription(this Enum e)
{
FieldInfo field = e.GetType().GetField(e.ToString());
if (field != null)
{
object[] attribs =
field.GetCustomAttributes(typeof(DescriptionAttribute), false);

if (attribs.Length > 0)
return (attribs[0] as DescriptionAttribute).Description;
}
return e.ToString();
}
}
 

Y voila! A partir de este momento tendremos a nuestra disposición el método GetDescription(), que nos devolverá el texto asociado al elemento de la enumeración; si éste no existe, es decir, si no se ha decorado el elemento con el atributo apropiado, nos devolverá el identificador utilizado.

De esta forma eliminamos de un plumazo los dos inconvenientes citados anteriormente: la separación entre la definición de la enumeración y los textos descriptivos, y la necesidad de crear un conversor a texto por cada enumeración que usemos en nuestra aplicación.

Y por cierto, el equivalente en VB.NET completo sería:

Imports System.ComponentModel
Imports System.Reflection
Imports System.Runtime.CompilerServices

Module Module1
Public Enum EstadoProyecto
<Description("Pendiente de aceptación")> PendienteDeAceptacion
<Description("En realización")> EnRealizacion
<Description("Finalizado")> Finalizado
<Description("Facturado y cerrado")> FacturadoYCerrado
End Enum

<Extension()> _
Public Function GetDescription(ByVal e As System.Enum) As String
Dim field As FieldInfo = e.GetType().GetField(e.ToString())
If Not (field Is Nothing) Then
Dim attribs() As Object = _
field.GetCustomAttributes(GetType(DescriptionAttribute), False)
If attribs.Length > 0 Then
Return CType(attribs(0), DescriptionAttribute).Description
End If
End If
Return e.ToString()
End Function
End Module
 


Publicado en: www.variablenotfound.com.
domingo, 27 de abril de 2008
Días atrás hablaba de las formas de inicialización de objetos que nos proporcionaban las últimas versiones de C# y VB.Net, que permitían asignar valores a miembros de instancia de forma muy compacta, legible y cómoda.

C# 3.0 nos trae otra sorpresa, también relacionada con el establecimiento de valores iniciales de elementos: los inicializadores de colecciones. Aunque esta característica también estaba prevista para VB.Net 9.0, al final fue desplazada a futuras versiones por problemas de tiempo.

Para inicializar una colección, hasta ahora era necesario en primer lugar crear la clase correspondiente para, a continuación, realizar sucesivas invocaciones al método Add() con cada uno de los elementos a añadir:
 List<string> ls = new List<string>();
ls.Add("Uno");
ls.Add("Dos");
ls.Add("Tres");
 
C# 3.0 permite una alternativa mucho más elegante y rápida de codificar, simplemente se introducen los elementos a añadir a la colección entre llaves (como se hacía con los inicializadores de arrays o los nuevos inicializadores de objetos), separados por comas, como en el siguiente ejemplo:
 List<string> ls = 
new List<string>() { "Uno", "Dos", "Tres" };
 
Si desensamblamos el ejecutable resultante, podremos ver que es el compilador el que ha añadido por nosotros los Add() de cada uno de los elementos después de instanciar la colección:

newobj instance void class
[mscorlib]System.Collections.Generic.List`1<string>::.ctor()
stloc.s '<>g__initLocal0'
ldloc.s '<>g__initLocal0'
ldstr "Uno"
callvirt instance void class
[mscorlib]System.Collections.Generic.List`1<string>::Add(!0)
nop
ldloc.s '<>g__initLocal0'
ldstr "Dos"
callvirt instance void class
[mscorlib]System.Collections.Generic.List`1<string>::Add(!0)
nop
ldloc.s '<>g__initLocal0'
ldstr "Tres"
callvirt instance void class
[mscorlib]System.Collections.Generic.List`1<string>::Add(!0)
nop
 
Uniendo esto ahora con los inicializadores de objetos que ya tratamos un post anterior, fijaos en la potencia del resultado:
 List<Persona> lp = new List<Persona>
{
new Persona { Nombre="Juan", Edad=34 },
new Persona { Nombre="Luis", Edad=53 },
new Persona { Nombre="José", Edad=23 }
};
 
Efectivamente, cada elemento es una nueva instancia de la clase Persona, con las propiedades que nos interesan inicializadas de forma directa. De hacerlo con los métodos tradicionales, para conseguir el mismo resultado deberíamos utilizar muuuchas más líneas de código.

Otro ejemplo que demuestra aún más la potencia de esta característica:
 var nums = new SortedList
{
{ 34, "Treinta y cuatro" },
{ 12, "Doce" },
{ 3, "Tres" }
};
foreach (var e in nums)
Console.WriteLine(e.Key + " " + e.Value);
 
En el código anterior podemos ver, primero, el uso de variables locales de tipo implícito, para ahorrarnos tener que escribir más de la cuenta. En segundo lugar, se muestra cómo se inicializa una colección cuyo método Add() requiere dos parámetros. En el caso de un SortedList<TKey, TValue>, su método Add() requiere la clave de ordenación y el valor del elemento.

(Obviamente, el resultado de la ejecución del código anterior será la lista ordenada por su valor numérico (Key))

En conclusión, se trata de otra de las innumerables ventajas que nos ofrece la nueva versión de C# destinadas a evitarnos pulsaciones innecesarias, y a la que seguro le daremos uso.

Publicado en: www.variablenotfound.com.
martes, 15 de abril de 2008
¡Sorpresa!Hace unos días comentaba que el uso de métodos parciales puede causar algunos problemas en la ejecución de nuestras aplicaciones que podríamos calificar, cuanto menos, de "incómodos".

Recordemos que una parte de una clase parcial puede declarar un método y utilizarlo (invocarlo) dentro de su código; si el método está implementado en otro fragmento de la clase, se ejecutará como siempre, pero si no ha sido implementado, el compilador eliminará tanto la declaración del método como las llamadas que se hagan al mismo.

Sin embargo esta eliminación pueden causar efectos no deseados difíciles de detectar.

Veámoslo con un ejemplo. Supongamos una clase parcial como la siguiente, que representa a una variable de tipo entero que puede ser incrementada o decrementada a través de métodos:
 public partial class Variable
{
partial void Log(string msg);
private int i = 0;

public void Inc()
{
i++;
Log("Incremento. I: " + i);
}

public void Dec()
{
Log("Decremento. I: " + (--i));
}

public int Value
{
get { return i; }
}
}
 
Creamos ahora un código que utiliza esta clase de forma muy simple: crea una variable, la incrementa dos veces, la decrementa una vez y muestra el resultado:
 Variable v = new Variable();
v.Inc();
v.Inc();
v.Dec();
Console.WriteLine(v.Value);
 
Obviamente, tras la ejecución de este código la pantalla mostrará por consola un "1", ¿no? Claro, el resultado de realizar dos incrementos y un decremento sobre el cero.

Pues no necesariamente. De hecho, es imposible conocer, a la vista del código mostrado hasta ahora, cuál será el resultado mostrado por consola al finalizar la ejecución. Dependiendo de la existencia de la implementación del método parcial Log(), declarado e invocado en la clase Variable anterior, puede ocurrir:
  • Si existe otra porción de la misma clase (otra partial class Variable) donde se implemente el método, se ejecutará éste. El valor mostrado por consola, salvo que desde esta implementación se modificara el valor del campo privado, sería "1".

  • Si no existe una implementación del método Log() en la clase, el compilador eliminará todas las llamadas al mismo. Pero si observáis, esto incluye el decremento del valor interno, que estaba en el interior de la llamada como un autodecremento:
    Log("Decremento. I: " + (--i));
    Por tanto, en este caso, el compilador eliminará tanto la llamada a Log() como la operación que se realiza en el interior. Obviamente, el resultado de ejecución de la prueba anterior sería "2".

    Lo mismo ocurriría si el resultado a mostrar fuera el valor de retorno de una llamada a otra función: esta no se ejecutaría, lo cual puede ser grave si en ella se realiza una operación importante, como por ejemplo:
    public function InicializaValores()
    {
    Log("Elementos reestablecidos: " + reseteaElementos() );
    }
     
Conclusión: usad los métodos parciales siempre con precaución, pues podemos introducir errores muy difíciles de detectar y corregir, sobre todo por falta aparente de relación entre causa y efecto.

Por ejemplo, imaginad que el ejemplo anterior contiene una implementación de Log(); la aplicación funcionaría correctamente. Sin embargo, si pasado un tiempo se decide eliminar esta implementación (por ejemplo, porque ya no es necesario registrar las operaciones realizadas), la operación de decremento (Dec()) dejaría de funcionar.

Aunque, eso sí, no es nada que no se pueda solucionar con un buen juego de pruebas...

Publicado en: http://www.variablenotfound.com/.
domingo, 13 de abril de 2008
Piezas de puzzleUna vez visto el concepto de las clases parciales, ya es posible profundizar en los métodos parciales, una característica aparecida en las nuevas versiones de los lenguajes estrella de Microsoft, C# y VB.Net.

Estos métodos, declarados en el contexto de una clase parcial, permiten comunicar de forma segura los distintos fragmentos de dicha clase. De forma similar a los eventos, permiten que un código incluya una llamada a una función que puede (o no) haber sido implementada por un código cliente, aunque en este caso obligatoriamente la implementación se encontrará en uno de los fragmentos de la misma clase desde donde se realiza la llamada.

En la práctica significa que una clase parcial puede declarar un método y utilizarlo (invocarlo) dentro de su código; si el método está implementado en otro fragmento de la clase, se ejecutará como siempre, pero si no ha sido implementado, el código correspondiente a la llamada será eliminado en tiempo compilación para optimizar el resultado... ¡sí, eliminado!

Por ejemplo, el siguiente código muestra una declaración de un método parcial en el interior de una clase, y su utilización desde dentro de uno de sus métodos:
 // C#
public partial class Ejemplo
{

// El método parcial se declara
// sin implementación...

partial void Log(string msg);


public void RealizarAlgo()
{
hacerAlgoComplejo();
Log("¡Ojo!"); // Usamos el método
// parcial declarado antes

}

[...] // Otros métodos y propiedades

}

' VB.NET
Partial Public Class Ejemplo

' El método parcial se declara, sin
' implementar nada en el cuerpo

Partial Private Sub Log(ByVal msg As String)
End Sub


Public Sub RealizarAlgo()
HacerAlgoComplejo()
Log("¡Ojo!") ' Usamos el método parcial
End Sub

[...] ' Otros métodos y propiedades
End Class
 
Y esta la parte realmente curiosa. Cuando el compilador detecta la invocación del método parcial Log(), buscará en todos los fragmentos de la clase a ver si existe una implementación del mismo. Si no existe, eliminará del ensamblado resultante la llamada a dichos métodos, es decir, actuará como si éstas no existieran en el código fuente.

En caso afirmativo, es decir, si existen implementaciones como las del siguiente ejemplo, todo se ejecutará conforme a lo previsto:
 // C#
public partial class Variable
{
partial void Log(string msg)
{
Console.WriteLine(msg);
}
}

' VB.Net
Partial Public Class Variable
Private Sub Log(ByVal msg As String)
Console.WriteLine(msg)
End Sub
End Class
 
Antes comentaba que los métodos parciales son, en cierto sentido, similares a los eventos, pues conceptualmente permiten lo mismo: pasar el control a un código cliente en un momento dado, en el caso de que éste exista. De hecho, hay muchos desarrolladores que lo consideran como un sustituto ligero a los eventos, pues permite prácticamente lo mismo pero se implementan de forma más sencilla.

Existen, sin embargo, algunas diferencias entre ambos modelos, como:
  • Los métodos parciales se implementan en la propia clase, mientras que los eventos pueden ser consumidos también desde cualquier otra
  • El enlace, o la suscripción, a eventos es dinámica, se realiza en tiempo de ejecución, es necesario incluir código para ello; los métodos parciales, sin embargo, se vinculan en tiempo de compilación
  • Los eventos permiten múltiples suscripciones, es decir, asociarles más de un código cliente
  • Los eventos pueden presentar cualquier visibilidad (pública, privada...), mientras que los métodos parciales son obligatoriamente privados.
También puede verse como algo parecido a la herencia en una jerarquía de clases. Una clase puede incluir un método virtual vacío y utilizarlo en su implementación, y si una clase hija sobreescribe el mismo, ésta se ejecutará en su lugar. Pero claro, hay que tener en cuenta que el ámbito de consumo del método parcial es la misma clase donde se declara e implementa.

Por último, es conveniente citar algunas consideraciones sobre los métodos parciales:
  • Deben ser siempre privados (ya lo había comentado antes)
  • No deben devolver valores (en VB.Net serían SUB, en C# serían de tipo void)
  • Pueden ser estáticos (shared en VB)
  • Pueden usar parámetros, acceder a los miembros privados de la clase... en definitiva, actuar como un método más de la misma

En resumen, los métodos parciales forman parte del conjunto de novedades de C# y VB.Net que no son absolutamente necesarias y que a veces pueden parecer incluso diabólicas, pues facilitan la dispersión de código y dificultan la legibilidad. Además, en breve publicaré un post comentando posibles efectos laterales a tener en cuenta cuando usemos los métodos parciales en nuestros desarrollos.

Sin embargo, es innegable que los métodos parciales nos facilitan enormemente la inclusión de código de usuario en el interior de clases generadas de forma automática. Por ejemplo, el diseñador visual del modelo de datos de LinqToSQL genera los DataContext como clases parciales, en las que define un método parcial llamado OnCreated(). Si el usuario quiere incluir alguna inicialización personal al crear los DataContext, no tendrá que tocar el código generado de forma automática; simplemente creará otro fragmento de la clase parcial e implementará este método, de una forma mucho más natural y cómoda que si se tratara de un evento.

Publicado en: http://www.variablenotfound.com/.
miércoles, 2 de abril de 2008
Piezas de puzzleAunque las clases parciales aparecieron hace unos años, con la llegada de .Net 2.0 y Visual Studio 2005, vamos a hacer un breve repaso como preparación para un próximo post que trate los métodos parciales.

Las clases parciales (llamados también tipos parciales) son una característica presente en algunos lenguajes de programación, como C# y VB.Net, que permiten que la declaración de una clase se realice en varios archivos de código fuente, rompiendo así la tradicional regla "una clase, un archivo". Será tarea del compilador tomar las porciones de los distintos archivos y fundirlas en una única entidad.

En VB.Net y C#, a diferencia de otros lenguajes, es necesario indicar explícitamente que una clase es parcial, es decir, que es posible que haya otros archivos donde se continúe la declaración de la misma, usando en ambos con la palabra clave partial en la definición del tipo:
  ' VB.NET 
Public Partial Class Persona
...
End Class

// C#
public partial class Persona
{
...
}
 
En este código hemos visto cómo se declara una clase parcial en ambos lenguajes, que es prácticamente idéntica salvo por los detalles sintácticos obvios. Por ello, a partir de este momento continuaré introduciendo los ejemplos sólo en C#.

Pero antes un inciso: la única diferencia entre ambos, estrictamente hablando, es que C# obliga a que todas las apariciones de la clase estén marcadas como parciales, mientras que en VB.Net puede dejarse una de ellas (llamémosla "declaración principal") sin indicar que es parcial, y especificarlo en el resto de apariciones. En mi opinión, esta no es una práctica recomendable, por lo que aconsejaría utilizar el modificador partial siempre que la clase lo sea, e independientemente del lenguaje utilizado, pues contribuirá a la mantenibilidad del código.

El número de partes en las que se divide una clase es indiferente, el compilador tomará todas ellas y generará en el ensamblado como si fuera una clase normal.

Para comprobarlo he creado un pequeño código con dos clases exactamente iguales, salvo en su nombre. Una de ellas se denomina PersonaTotal, y está definida como siempre, en un único archivo; la otra, PersonaParcial, es parcial y la he troceado en tres archivos, como sigue:
  // *** Archivo PersonaParcial.Propiedades.cs ***
// Aquí definiremos todas las propiedades

partial class PersonaParcial
{
public string Nombre { get; set; }
public string Apellidos { get; set; }
}

// *** Archivo PersonaParcial.IEnumerable.cs ***
// Aquí implementaremos el interfaz IEnumerable

partial class PersonaParcial: IEnumerable
{
public IEnumerator GetEnumerator()
{
throw new NotImplementedException();
}
}

// *** Archivo PersonaParcial.Metodos.cs ***
// Aquí implementaremos los métodos que necesitemos

partial class PersonaParcial
{
public override string ToString()
{
return Nombre + " " + Apellidos;
}
}
 
Y efectivamente, el resultado de compilar ambas clases, según se puede observar con ILDASM es idéntico:

Clases generadas tras la compilación

A la hora de crear clases parciales es conveniente tener los siguientes aspectos en cuenta:
  • Los atributos de la clase resultante serán la combinación de los atributos definidos en cada una de las partes.
  • El tipo base de los distintos fragmentos debe ser el mismo, o aparecer sólo en una de las declaraciones parciales.
  • Si se trata de una clase genérica, los parámetros deben coincidir en todas las partes.
  • Los interfaces que implemente la clase resultante será la unión de todos los implementados por las distintas secciones.
  • De la misma forma, los miembros (métodos, propiedades, campos...) de la clase final será la unión de todos los definidos en las distintas partes.

Vale, ya hemos visto qué son y cómo se usan, pero, ¿para qué sirven? ¿cuándo es conveniente utilizarlas? Pues bien, son varios los motivos de su existencia, algunos discutibles y otros realmente interesantes.

En primer lugar, no era sencillo que varios desarrolladores trabajaran sobre una misma clase de forma concurrente. Incluso utilizando sistemas de control de versiones (como Sourcesafe o Subversion), la unidad mínima de trabajo es el archivo de código fuente, y la edición simultánea podía generar problemas a la hora de realizar fusiones de las porciones modificadas por cada usuario.

En segundo lugar, permite que clases realmente extensas puedan ser troceadas para facilitar su comprensión y mantenimiento. Igualmente, puede utilizarse para separar código en base a distintos criterios:
  • por ejemplo, separar la interfaz (los miembros visibles desde el exterior de la clase) y por otra los miembros privados a la misma
  • o bien separar las porciones que implementan interfaces, o sobreescriben miembros de clases antecesoras de los pertenecientes a la propia clase
  • o separar temas concernientes a distintos dominios o aspectos
En tercer lugar, aunque da la impresión que fue el motivo más importante para decidir su inclusión, las clases parciales permiten utilizar de forma efectiva herramientas automáticas de generación de código.

Así, es posible que un desarrollador y un generador estén introduciendo cambios sobre la misma clase sin molestarse, cada uno jugando con su propia porción de la clase; el primero puede introducir funcionalidades sin preocuparse de que una nueva generación automática de código pueda machacar su trabajo. Visual Studio y otros entornos de desarrollo hacen uso intensivo de esta capacidad, por ejemplo, en los diseñadores visuales de Windows Forms, WPF, ASP.Net e incluso el generador de modelos de LinqToSql.

Publicado en: http://www.variablenotfound.com/.
domingo, 9 de marzo de 2008
Hace unos meses hablaba sobre la posibilidad de manipular la forma en la que el framework almacena por defecto la información para obtener enumeraciones de campos de bits, algo que es muy habitual en programación a bajo nivel. Siguiendo en la misma línea, hoy voy a comentar cómo conseguir uniones en .Net, al más puro estilo C.

Una unión es muy similar a una estructura de datos (struct en C# o Structure en VB.Net), salvo en un detalle: sus componentes se almacenan sobre las mismas posiciones de memoria. O visto desde el ángulo opuesto, una unión podríamos definirla como una porción de memoria donde se guardan varias variables, habitualmente de tipos diferentes. Veamos un ejemplo clásico que nos ayudará a entender el concepto, en un lenguaje cualquiera:
union Ejemplo
{
char caracter; // suponiendo char de 8 bits
byte octeto; // un byte ocupa 8 bits
};

Si declaramos una variable x del tipo Ejemplo, estaremos reservando un espacio de 8 bits al que accederemos desde cualquiera de sus miembros, como vemos a continuación:

x.caracter = 'A';
x.octeto ++;
escribir_char (x.caracter); // mostraría 'B'
escribir_byte (x.octeto); // mostraría 66
 

Pero espera... ¿memoria?... ¿almacenamiento de variables?... ¿pero existe eso en .Net?... Pues sí, aunque lo más normal es que no nos tengamos que enfrentar nunca a ello pues el framework realiza estas tareas por nosotros, hay escenarios en los que es necesario controlar la forma en que la información es almacenada en memoria, como cuando se esté operando a bajo nivel, por ejemplo creando estructuras específicas para llamar al API de Windows, o para facilitar el acceso a posiciones concretas de la información.

Desde la versión 1.1 de la plataforma .Net, disponemos del atributo StructLayout, que nos permite indicar en estructuras y clases cómo queremos representar en memoria la información de sus miembros. Básicamente, podemos indicar que:
  • la información se almacene como el framework considere oportuno (LayoutKind.Auto)
  • que se almacene de forma secuencial, en el mismo orden en el que han sido declarados (LayoutKind.Sequential).
  • que se almacene donde le indiquemos de forma explícita (LayoutKind.Explicit). En este caso, necesitaremos especificar en cada miembro la posición exacta de memoria donde será guardado, utilizando el atributo FieldOffset.

Es este último método el que nos interesa para nuestros propósitos. Si adornamos una estructura con StructLayout(LayoutKind.Explicit) e indicamos en cada uno de sus miembros su desplazamiento (en bytes) dentro del espacio de memoria asignado a la misma, podemos conseguir uniones haciendo que todos ellos comiencen en la misma dirección.

Pasemos a vamos a verlo con un ejemplo en C#. Se trata de una unión a la que podemos acceder tratándola como un carácter unicode, o bien como un entero de 16 bits con signo. Los dos miembros, llamados Caracter y Valor están definidos sobre la misma posición de memoria (desplazamiento cero) en el interior de la estructura:
using System.Runtime.InteropServices;
using System;
namespace PruebaUniones
{
[StructLayout(LayoutKind.Explicit)]
public struct UnionTest
{
[FieldOffset(0)] public char Caracter;
[FieldOffset(0)] public short Valor;
}
class Program
{
public static void Main()
{
UnionTest ut = new UnionTest();
ut.Caracter = 'A';
ut.Valor ++;
Console.WriteLine(ut.Caracter); // Muestra "B"
Console.ReadKey();
return;
}
}
}
 
Ahora usaremos VB.NET para mostrar otro ejemplo un poco más complejo que el anterior, donde usamos una unión para descomponer una palabra de 16 bits en los dos bytes que la componen, permitiendo la manipulación de forma directa e independiente de cada una de las dos visiones del valor almacenado en memoria. Para el ejemplo utilizo una unión dentro de otra, aunque no era estrictamente necesario, para que veáis que esto es posible.

Imports System.Runtime.InteropServices

<StructLayout(LayoutKind.Explicit)> _
Public Structure Union16
<FieldOffset(0)> Dim Word As Int16
<FieldOffset(0)> Dim Bytes As Bytes
End Structure

<StructLayout(LayoutKind.Explicit)> _
Public Structure Bytes
<FieldOffset(0)> Dim Bajo As Byte
<FieldOffset(1)> Dim Alto As Byte
End Structure

Public Class Program
Public Shared Sub main()
Dim u As New Union16
u.Word = 513 ' 513 = 256*1 (Byte alto) + 1 (byte bajo)
u.Bytes.Alto += 1
Console.WriteLine("Word: " & u.Word) ' Muestra 769 (3*256+1)
Console.WriteLine("Byte alto: " & u.Bytes.Alto) ' Muestra 3
Console.WriteLine("Byte bajo: " & u.Bytes.Bajo) ' Muestra 1
Console.ReadKey()
Console.ReadKey()
End Sub
End Class
 
He encontrado un uso muy interesante para esta técnica en Xtreme .Net Talk, donde se muestra un ejemplo de cómo acceder a los componentes de color de un pixel de forma muy eficiente a través de una unión entre el valor ARGB (32 bits) y cada uno de los bytes que lo componen (alfa, rojo, verde y azul).

En cualquier caso no se recomienda el uso de uniones salvo en casos muy concretos, y siempre conociendo bien las implicaciones que puede tener en la estabilidad y mantenibilidad del sistema.

Pero bueno, ¡está bien al menos saber que existen!

Publicado en: http://www.variablenotfound.com/.
miércoles, 5 de marzo de 2008
Cuando estamos desarrollando es habitual que tengamos que comentar porciones de código para realizar pruebas. Esto resulta de lo más sencillo cuando programamos en un lenguaje de los habituales como Javascript, C#, Visual Basic o incluso (X)HTML, pues todos ellos disponen de marcadores que hacen que el compilador o intérprete ignore determinadas líneas de código... pero, ¿cómo logramos este efecto si se trata de un archivo .ASPX, donde pueden encontrarse varios de ellos a la vez?

Por ejemplo, dado el siguiente código en el interior de una página ASP.NET, ¿cuál sería la forma correcta de comentarlo?
<script>
var count = <%= borrarRegistros() %>
alert("Borrados: " + count + " registros");
</script>
 
Una primera opción podría ser utilizar la sintaxis Javascript de la siguiente forma:
<script>
/*
var count = <%= borrarRegistros() %>
alert("Borrados: " + count + " registros");
*/
</script>
 
Sin embargo, aunque podría valer en muchas ocasiones, también puede introducir unos efectos laterales considerables. Nótese que aunque el código Javascript (cliente) esté comentado, la función borrarRegistros() sería invocada en el lado del servidor, y su retorno introducido dentro del comentario. De hecho, la página enviada a cliente mostraría un código fuente similar al siguiente (imaginando que el retorno de la función fuera el valor 99):
<script>
/*
var count = 99;
alert("Borrados: " + count + " registros");
*/
</script>
 
Tampoco valdría para nada incluir todo el bloque de script dentro de un comentario HTML (<!-- y -->), por la misma razón que antes. Además, en cualquiera de estos dos casos, estaríamos enviando al cliente la información aunque sea éste el que la ignora a la hora de mostrarla o ejecutarla y, por supuesto, estaríamos ejecutando la función en servidor, lo cual podría causar otros efectos no deseados, como, en nuestro ejemplo, eliminar los registros de una base de datos.

Afortunadamente, ASP.NET dispone de un mecanismo, denominado Server Side Comments (comentarios en el lado del servidor), que permite marcar zonas y hacer que se ignore todo su contenido, sea del tipo que sea, a la hora de procesar la página:
<%-- 
<script>
var count = <%= borrarRegistros() %>
alert("Borrados: " + count + " registros");
</script>

--%>
 
En este caso ni sería ejecutada la función del servidor ni tampoco enviado a cliente el código HTML/Script incluido.

Publicado en: http://www.variablenotfound.com/.
lunes, 3 de marzo de 2008
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 sencilla, 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/.
domingo, 24 de febrero de 2008
Hace unos meses comentaba las distintas opciones para saber si una cadena está vacía en C#, y la conclusión era la recomendación del uso del método estático string.IsNullOrEmpty, sobre todo si podemos asegurar que no aparecerá el famoso bug del mismo (que al final no es para tanto, todo sea dicho).

Los métodos de extensión nos brindan la posibilidad de hacer lo mismo pero de una forma más elegante e intuitiva, impensable hasta la llegada de C# 3.0: extendiendo la clase string con un método que compruebe su contenido.

La forma de conseguirlo es bien sencilla. Declaramos en una clase estática el método de extensión sobre el tipo string:
public static class MyExtensions
{
public static bool IsNullOrEmpty(this string s)
{
return s == null || s.Length == 0;
}
}
 
Y listo, ya tenemos el nuevo método listo para ser utilizado:
string name = getCurrentUserName();
if (!name.IsNullOrEmpty())
...
 
De todas formas, hay un par de reflexiones que considero interesante comentar.

En primer lugar, fijaos en el ejemplo anterior que aunque la variable name contenga un nulo, se ejecutará la llamada a IsNullOrEmpty() sin provocar error, algo imposible si se tratara de un método de instancia. Obviamente, se debe a que en realidad se está enmascarando una llamada a un método estático al que le llegará como parámetro un null.

Como consecuencia de lo anterior, y dado que no se puede distinguir a simple vista en una llamada a un método si éste es de instancia o de extensión, es posible que un desarrollador considerara esta invocación incorrecta. Esto forma parte de los inconvenientes de los métodos de extensión que ya cité en un post anterior.

En segundo lugar, visto lo visto cabría preguntarse, ¿por qué podemos extender una clase añadiéndole nuevos métodos pero no es posible incluir otro tipo de elementos, como eventos o propiedades? En el caso anterior podría quedar más fino que IsNullOrEmpty fuera una propiedad de string, ¿no?

Sin embargo, esto no es posible de momento. Según comentó ScottGu hace tiempo, se estaba considerando añadir la posibilidad de extender las clases también con nuevas propiedades. Supongo que el hecho de no haberla incluido en esta versión se deberá a que no era necesario para LINQ, la estrella de esta entrega... ¡y para dejar algo por hacer para C# 4.0, claro! ;-)

En cualquier caso, se trata principalmente de una cuestión de estética del código. Todo lo que conseguimos con las propiedades se puede realizar a base de métodos; de hecho, las propiedades no son sino interfaces más agradables a métodos getters y setters, al más puro estilo Java, subyacentes.

Por último, todo lo dicho es válido para VB.NET 9, salvo las obvias diferencias. El código equivalente al anterior sería:
Imports System.Runtime.CompilerServices
Module MyExtensions
<Extension()> _
Public Function IsNullOrEmtpy(ByVal s As String) As String
Return (s = Nothing) OrElse (s.Length = 0)
End Function
End Module
[...]

' Forma de invocar el método:
If s.IsNullOrEmtpy() Then
[...]
 


Publicado en: http://www.variablenotfound.com/.
domingo, 3 de febrero de 2008
Código C#Los métodos de extensión son otra de las interesantes características que nos ofrecen las nuevas versiones de los lenguajes C# y VB que han sido publicados junto con la plataforma .NET v3.5 y Visual Studio 2008.

Los, en inglés, extension methods, permiten añadir métodos a clases existentes sin necesidad de utilizar el mecanismo de la herencia. Aunque dicho así parezca ser una aberración y atente directamente contra una de las principales bases de la programación orientada a objetos, y de hecho están considerados por algunos como auténticos inventos diabólicos, la cosa tampoco es tan grave siempre que se mantenga cierto control y conocimiento de causa. Y es que, como muchas otras características aparecidas recientemente en estos lenguajes, no son sino una base sobre la que sustentar frameworks como Linq, y que de paso pueden ayudarnos a ser algo más productivos.

En realidad, y siendo prácticos, los métodos de extensión no aportan grandes novedades, casi nada que no pudiéramos hacer con la versión 1.0 del framework, simplemente nos facilitan nuevas vías sintácticamente más simples de hacerlo. Por ejemplo, seguro que alguna vez habéis querido dotar una clase X con nuevas funcionalidades y no habéis podido heredar de ella por estar sellada (sealed en C# o NotInheritable en VB)... ¿Qué es lo que habéis hecho? Pues probablemente crear en otra clase un método estático con un parámetro de tipo X que realizaba las funciones deseadas en alguna clase de utilidad. ¿Lo vemos mejor con un ejemplo?

Supongamos que deseamos añadir a la clase string un método que nos retorne la cadena almacenada entre un tag (X)HTML strong. Como String no es heredable, la solución idónea sería crear una clase de utilidad donde codificar este métodos y otros similares que pudieran hacernos falta:
public static class HtmlStringUtils
{
public static function string Negrita(string s)
{
return "<strong>" + s + "</strong>";
}
public static function string Cursiva(string s) {...}
public static function string Superindice(string s) {...}
[...]
}
 
Su uso tendría que pasar necesariamente por la referencia a la clase estática y el paso del parámetro a convertir, así:

HtmlStringUtils.Negrita(currentUser.Name)
 
Esta técnica es correcta, aunque tiene un problema de visibilidad del código. Ningún desarrollador podría intuir la existencia de la clase HtmlStringUtils de forma natural; tampoco sería posible que un IDE sofisticado nos sugiriese el método Negrita() como una posibilidad a la hora de manipular una cadena, como hace Intellisense con los métodos de instancia habituales.

Los extension methods vienen a cubrir estos inconvenientes, creando una vía de alternativa para codificar el ejemplo anterior, facilitando después su uso de una forma más sencilla. Ojo al parámetro que recibe la función, que incluye la palabra reservada "this" por delante del mismo:
public static class HtmlStringUtils
{
public static function string Negrita(this string s)
{
return "<strong>" + s + "</strong>";
}
[...]
}
 
De esta forma, incluyendo como primer parámetro el tipo precedido de la palabra "this", este método estático se convertirá automáticamente en un método de extensión de dicho tipo, y pueda ser utilizado como si fuera un método de instancia más del mismo:
Intelisense con métodos de extensión

return currentUser.Name.Negrita();
 

Y, por supuesto, tendríamos toda la potencia de nuestro querido Intellisense (en VS2008) a nuestra disposición.

Lo único a tener en cuenta es el primer parámetro, que debe ser del tipo a extender. En éste se introducirá la instancia de dicho tipo de forma automática, y el resto de parámetros serán enviados al método en el mismo orden, es decir:


// Método de extensión sobre un string
public static string Colorea(this string s, Color color)
{
[...]
}

// Forma de invocarlo:
string str = User.Name.Colorea(Color.Red);

 
Vemos que la utilización es mucho más natural y, aunque parezca que estamos rompiendo todas las bases del paradigma de la orientación a objetos, no es más que un atajo para incrementar productividad y facilitar la visión del código, además de servir como apoyo a tecnologías novedosas como Linq.

Sin embargo, no todo son ventajas. Es interesante añadir posibles problemas que pueden causar la utilización descontrolada de esta nueva característica.

En primer lugar, no olvidemos que a menos que Visual Studio (o cualquier entorno similar) nos eche una mano, al leer un código fuente será imposible saber si una llamada que estamos observando es un método de instancia o se trata de uno de extensión. Aunque no deja de ser una pequeña molestia, puede provocar una inquietante sensación de desconocimiento y dispersión del código fuente.

Otro motivo de dolor de cabeza puede ser el versionado de los métodos de extensión. Éstos pueden tener una vida completamente independiente de la clase a la que afectan, lo que puede provocar efectos no deseados ante la evolución de ésta.

Especialmente peligrosos pueden ser los relacionados con los nombres de métodos de extensión. Por ejemplo, la inclusión de un método en una clase podría hacer (de hecho, haría) que un método de extensión asociado a la misma y con un nombre similar no se ejecutara, pues el miembro de la instancia siempre tendría preferencia sobre éste. El problema es que el compilador no podría avisar de ningún problema, y es en ejecución donde podrían aparecer las incompatibilidades o diferencia de funcionalidades entre ambos métodos.

Veamos un ejemplo simple, siguiendo con el caso expuesto más atrás, ¿qué ocurriría si una vez en uso el método de extensión Negrita() Microsoft decidiera añadir al tipo string un método de instancia llamado Negrita() en una versión posterior del framework, que retornara un tag HTML <b>? Pues que el compilador no sería capaz de detectar nada raro, por lo que no nos daríamos cuenta del cambio, y nuestra aplicación dejaría de validar XHTML.

De la misma forma, también pueden causar problemas difíciles de detectar la especificación de namespaces incorrectos. Nada impide que un mismo método de extensión sea definido en dos espacios de nombres diferentes, lo cual hace que el namespace indicado en el using sea el que esté decidiendo el extension method a ejecutar, lo cual no resulta nada natural ni intuitivo en estos casos.

En conclusión: la recomendación es usar métodos de instancia, los habituales, siempre que se pueda, recurriendo a la herencia. Y para cuando no, contaremos con este valioso aliado.

Publicado en: http://www.variablenotfound.com/.
lunes, 10 de diciembre de 2007
Hasta la versión 3.0 de C#, la declaración de una variable se debía realizar indicando su tipo de datos antes del identificador elegido para la misma. También era muy frecuente definir en ese mismo momento su valor inicial, siguiendo un patrón similar al siguiente:
  string s = "cadena";
Sin embargo, la declaración anterior es redundante. Si la constante "cadena" es un string, ¿por qué hace falta indicar que la variable s también lo es?

Las variables locales implícitamente tipadas permiten obviar en su declaración el tipo que tendrán, dejando al compilador la tarea de averiguar cuál será en función de las variables o constantes que se usen al inicializarlo. Por tanto, será posible escribir código como:
  var x = XmlDateTimeSerializationMode.Local;
Y será equivalente a:

XmlDateTimeSerializationMode x = XmlDateTimeSerializationMode.Local;
 
Creo que no hace falta decir cuál de ellas es más cómoda a la hora de programar, ¿no? Simplemente hemos indicado con la palabra var que preferimos que sea el compilador el que haga el trabajo sucio.

Otro contexto donde este tipo de variables pueden facilitarnos la vida de forma frecuente es en los bucles for, foreach y bloques using:
  // Un ejemplo de bucle...
var chars = "Saludicos".ToCharArray();
foreach (var ch in chars)
{
Console.Write(ch); // ch es char
}

// Y ahora un bloque using...
using (var ctx = new AppContext())
{
// usamos ctx, que es de tipo AppContext
}
 
También es importante la existencia de esta nueva forma de declaración para posibilitar la creación de objetos de tipo anónimo, es decir, aquellos cuya especificación de clase se crea en el mismo momento de su definición. Por tanto, una declaración como la siguiente será válida:
  var x = new { Nombre = "Juan", Edad = 23 };
Para no desviarme del objetivo de este post, otro día hablaremos más detenidamente de las clases anónimas, aunque adelantaré que una vez compilado el código anterior el resultado será algo parecido al siguiente:

class __Anonymous1
{
private string nombre ;
private int edad ;
public string Nombre { get { return nombre ; } }
public int Edad { get { return edad ; } }
public __Anonymous1(string nombre, int edad)
{
this.nombre = nombre;
this.edad = edad;
}
}
...
__Anonymous1 x = new __Anonymous1("Juan", 23);

 
Existen ciertas reglas de obligado cumplimiento para usar variables locales implícitamente tipadas:
  • La declaración debe incluir un valor de inicialización. En otras palabras, no será posible usar en una línea var i;, puesto que el compilador no podría inferir el tipo en este momento.
  • El valor de inicialización debe ser una expresión evaluable como clase en tiempo de compilación. Expresamente prohibido el valor null, es decir, nada de var n = null;, puesto que el compilador no sabría de qué tipo se trata; eso sí, si fuera necesario, podría forzarse un casting var str = null as string;.
  • La declaración no puede incluir más de una variable. Una línea como var i = 1, s = "hola"; generará un error en compilación.
  • El inicializador no puede referirse a la propia variable declarada, obviamente.
  • Sólo pueden utilizarse como variables locales en bloques de código, en bucles for y foreach y como recurso de un bloque using.

Por último, me gustaría añadir un par de detalles que considero interesantes.

Seguimos teniendo Intellisense...Primero, el hecho de utilizar la palabra "var" y no indicar de forma explícita el tipo puede hacernos pensar que estamos utilizando tipado dinámico en tiempo de ejecución, como lo hacemos con Javascript, sin embargo esto no es así. Como he comentado anteriormente, el compilador toma el tipo del lado derecho de la asignación de inicialización, por lo que si la variable no es inicializada se produce un error de compilación:
Implicitly-typed local variables must be initialized
(Las variables locales implícitamente tipadas deben ser inicializadas)
Por ello, un entorno como Visual Studio sabe en todo momento el tipo exacto de que se trata, y nos puede ofrecer las ayudas en la codificación, detección de errores sintáticos e intellisense, como se puede observar en la imagen.

Segundo, y muy interesante. Como ya comenté en su momento, la nueva versión de Visual Studio permite la generación de ensamblados para versiones anteriores de la plataforma, es decir, que es posible escribir código C# 3.0 y generar un ensamblado para el framework 2.0. Esto, a efectos prácticos, implica que una vez demos el salto definitivo a VS2008 podremos usar las variables locales de tipo implícito, así como otras novedades del lenguaje, incluso en aplicaciones diseñadas para .NET 2.0.



Publicado en: Variable Not Found.
lunes, 26 de noviembre de 2007
Hasta hoy no sabía que la arroba, además de permitir la definición de constantes string literales y multilíneas (mi gran descubrimiento del mes pasado), también puede ser utilizado en C# para utilizar nombres reservados del lenguaje como identificadores.

Según la especificación del lenguaje C#, un identificador (de una variable, clase, propiedad...) puede ser una de las palabras clave del lenguaje (for, if, int, string...) si va precedida por una arroba, permitiendo aberraciones como la siguiente:

class @class
{
public static void @static(bool @bool)
{
if (@bool)
System.Console.WriteLine("true");
else
System.Console.WriteLine("false");
}
}
 
En fin, dudo mucho que vaya a utilizar esta posibilidad alguna vez, pero está bien saber que existe.

Publicado en: Variable Not Found.
domingo, 11 de noviembre de 2007
Las primeras versiones de la plataforma .Net introdujeron el PostBack como el mecanismo de recarga de una página gracias al cual era posible la persistencia del estado de controles y la interacción con ellos de forma muy sencilla y potente en el lado del servidor, modificando la filosofía de programación de webs que habíamos usado hasta entonces (ASP clásico, CGIs...).

Sin embargo, si querías usar los controles de servidor en todo su esplendor te veías obligado a meter tareas completas dentro de una misma página; así, aquellas que presentaban funcionalidades relativamente complejas se convertían en batiburrillos donde se incluían formularios de entrada de datos, código de validaciones, formularios de salida de información, etc. Por ejemplo, podíamos tener en un mismo Webform paneles de introducción de criterios de búsqueda, paneles de información o errores, paneles con un grid para mostrar los resultados e incluso otro panel para mostrar una vista ampliada de un registro concreto, y jugar con las visibilidades para mostrar unos u otros en función de los pasos dados por el usuario.

Desde ASP.Net 2.0 es posible realizar los llamados "Cross Page PostBacks", o PostBacks hacia páginas distintas de la inicial, permitiéndonos separar funciones y hacer nuestro código un poco más legible, estructurado y reutilizable. El ejemplo anterior podría ser diseñado en tres páginas independientes, separando las distintas vistas, una solución mucho más limpia:
  • en la primera estaría el formulario de introducción de criterios.
  • en la segunda podríamos simplemente tomar los parámetros de la anterior y mostrar un listado con los resultados obtenidos, o bien un mensaje de información si no hay coincidencias.
  • en la tercera podríamos montar una ficha con los datos detallados de un elemento, que habría sido seleccionado por el usuario en la página anterior.
¿Y cómo se hace? Sencillo.

En primer lugar, hay que modificar el comportamiento de los botones de acción (o similar, de hecho también podría ser ImageButtons o LinkButtons) para que realicen el envío a otra página, indicándole su URL en la propiedad PostBackUrl. Eso hará que, tras su pulsación, el control sea enviado inmediatamente al archivo .aspx que se defina en la misma.

Un aspecto muy a tener en cuenta es el término "inmediatamente": el control es transferido a la nueva página sin ejecutar posibles validaciones en servidor, por lo que podrían llegar gazapos a la segunda. Sin embargo, si los validadores son en cliente, se ejecutarán con normalidad (si el usuario no tiene desactivado Javascript, of course!).

Ya en la página destino, hay varias opciones para recuperar el valor de los controles de la página invocadora. La primera de ellas, la más sencilla, consiste en usar la propiedad PreviousPage de la clase Page para obtener una referencia hacia la página de origen y obtener sus controles de la siguiente forma:

if (PreviousPage != null)
{
TextBox txt =
(TextBox)PreviousPage.FindControl("TextBox1");
Label1.Text = txt.Text; // Por ejemplo
}

Sin embargo, no es una solución aconsejable, puesto que un simple cambio de nombre del control en la página origen provocaría un error en tiempo de ejecución, puesto que FindControl no sería capaz de encontrarlo con el nombre "TextBox1".

Hay otra forma mucho más potente, que consiste en especificar en la página destino un tipado fuerte para la de origen usando en su archivo .aspx la siguiente directiva:

<%@ PreviousPageType VirtualPath="~/PaginaOrigen.aspx" %>

De esta forma, cualquier referencia a PreviousPage en la página destino se considerará automáticamente del tipo de la página de origen, pudiendo acceder a sus propiedades de forma directa, sin necesidad de castings ni nada parecido. Sin embargo, todo sea dicho, debido a que el nivel de visibilidad de los controles de un Webform son protected, no podemos acceder directamente a su contenido, debemos usar accesores o propiedades públicas para ello.

Por ejemplo, podríamos definir en la clase (codebehind) de la página de origen una propiedad como la siguiente como accesor al contenido de un control TextBox llamado txtTexto:

public string Texto
{
get {return txtTexto.Text; }
}

Y en la página destino, una vez introducida la directiva descrita anteriormente especificando la URL de la página de origen, podríamos hacer lo siguiente:

if (PreviousPage != null)
{
Label1.Text = PreviousPage.Texto; // Por ejemplo
}

En resumen, esta técnica permite estructurar mucho mejor nuestras aplicaciones web, aunque sea a cambio de realizar un sobreesfuerzo en el desarrollo. En mi opinión puede valer la pena su uso en páginas que generen demasiadas vistas diferentes para ser introducidas en un único Webform sin comprometer la mantenibilidad, o cuando resulte interesante de cara a la reutilización de páginas.

No es conveniente, a mi entender, su utilización indiscriminada en formularios simples, pues precisamente los PostBacks fueron introducidos en ASP.Net para evitar la proliferación innecesaria de páginas sueltas (.aspx) y facilitar el mantenimiento del estado en la inherentemente desconectada tecnología Web.
viernes, 2 de noviembre de 2007
Unas semanas atrás escribía una entrada sobre Nifty Corners Cube, una librería javascript que permitía redondear las esquinas de los elementos de bloque de una web (como divs, h, etc.) sin necesidad de crear imágenes o hacer malabarismos con el marcado, sólo añadiendo unas referencias al archivo .js y algunos scripts básicos de inicialización.

Sin embargo, para un desarrollador habituado a arrastar y soltar, estas dos simples operaciones suponen demasiado esfuerzo como para considerar el uso de esta librería ;-), de ahí que me decidiera a crear NiftyDotNet.

NiftyDotNet es un componente para ASP.NET, escrito en C#, que encapsula todos los archivos y lógica necesarios para hacer funcionar Nifty Corners Cube en nuestras webs de una forma aún más fácil, simplemente arrastrando y soltando el control sobre nuestros webforms y ajustando unos sencillos parámetros, como el tamaño del borde o la selección de elementos a los que afectará.

Para que quede más claro, ahí va un ejemplo: observamos un formulario web en tiempo de diseño con un div central (que tiene un id='box1') y un control Nifty que afecta al mismo. A la derecha podemos ver también las distintas opciones de parametrización del control (puedes hacer clic sobre la imagen para ampliarla un poco):



Y continuación una captura con la página en tiempo de ejecución:



Como se puede ver, las esquinas del div central han sido redondeadas por el componente sin usar imágenes externas, sólo javascript no intrusivo. Increíble, ¿no? ;-)

El proyecto, publicado bajo GPL, se distribuye en tres paquetes, a elegir según el gusto y pretensiones del usuario:
  • Un ensamblado listo para ser utilizado en nuestros proyectos, o para añadirlo a la caja de herramientas (Toolbox) del entorno de desarrollo.
  • Una web de demostración, en la que podéis haceros una idea de la utilidad del componente. No hay una demo on-line debido a que en los servidores donde se encuentra no existe esta posibilidad, cuando encuentre un alojamiento apropiado la pondré para que pueda verse en vivo y en directo.
  • La solución VS2005 con el código fuente completo de ambos.

En la actualidad hay ya una versión bastante estable y depurada (a falta de comentarios de usuarios, claro!). Además, ha sido testeada tanto con Microsoft .Net Framework como con Mono, lo cual es siempre una buena noticia.

Por supuesto estaré encantado de recibir vuestras aportaciones, sugerencias, colaboraciones o comentarios de cualquier tipo.



Enlaces:
jueves, 25 de octubre de 2007
Comprobar si una variable de tipo string está vacía es una tarea que seguro realizamos muy a menudo en nuestras aplicaciones. Observando código, tanto propio como ajeno, he visto que existen varias formas de hacerlo, y a veces cometemos errores que pueden ser fácilmente evitables prestando un poco de atención.

Por ejemplo, dada una variable str declarada como string, utilizando en C# la expresión str.Equals("") podemos conocer si str contiene una cadena vacía. Sin embargo, si str contiene un valor nulo (lo cual es perfectamente posible al tratarse de un tipo referencia) se provocará una excepción de tipo System.NullReferenceException, puesto que estamos intentando llamar a un método de un objeto inexistente.

Ocurre lo mismo si intentamos averiguar el número de caracteres que contiene: (str.Length==0) es cierto si la cadena está vacía, pero igualmente revienta si se trata de un valor nulo.

Una posible solución es preguntar previamente si la cadena es nula y sólo en caso contrario preguntar, siguiendo alguno de los dos patrones descritos anteriormente, si se trata de un string vacío, algo así:
((str!=null) && (str.Length==0))
.

Como podéis observar, aunque válido, parece demasiado laborioso para los que tenemos prisa. Otra forma más corta e ingeniosa de poner lo mismo sería la siguiente: "".Equals(str). Como podéis ver, el problema del nulo desaparece, puesto que se llama al método Equals de la cadena constante "" que siempre tiene valor (la cadena vacía).

Sin embargo, cualquiera de los casos anteriormente citados pueden no funcionar correctamente si consideramos los nulos como una forma más de expresar una cadena vacía. Por ejemplo, observad el siguiente código:

private string saludar(string nombre)
{
if ("".Equals(nombre))
return "No saludo a nadie";
else
return "Hola, " + nombre;
}
 

La función retorna el literal "No saludo a nadie" cuando le llega un nombre vacío (""). Sin embargo, si le llega un valor nulo no se cumple la primera igualdad, entraría en el bloque else y retornaría un saludo absurdo, "Hola, ". Y es que hay veces donde semánticamente el nulo y la cadena vacía son idénticos.

Para estos casos es conveniente hacer equivalentes ambos valores, de forma que nuestra función se comporte exactamente igual tanto si recibe un nulo como si le llega un string vacío. Veamos algunas formas de conseguirlo.

Una fórmula que he visto alguna vez consiste en sumar a nuestro string una cadena vacía en algún momento del proceso, es decir, usar algo como: ""+str. Esta expresión devolverá siempre un string vacío o con el valor original de la variable str, pero nunca un nulo. Una vez realizada esta operación, podemos hacer la comparación con .Equals("") o .Length==0, aunque se recomienda este último por su mejor rendimiento.

Otra forma, algo mejor que la anterior, es usar dos comparaciones combinadas con OR: ((str == null) || (str.Equals(String.Empty))). Así, si str es nulo la expresión evalúa a cierto y sólo en caso contrario se realizará la comparación con la cadena vacía (String.Empty es lo mismo que el string "").

Pero sin duda la mejor opción sería usar el método estático introducido en la clase string en la versión 2.0 de la plataforma: string.IsNullOrEmpty(). Siguiendo con el ejemplo anterior, podríamos reescribirlo de la siguiente manera, consiguiendo el efecto deseado:

private string saludar(string nombre)
{
if (string.IsNullOrEmpty(nombre))
return "No saludo a nadie";
else
return "Hola, " + nombre;
}
 
Este sería un buen momento para dar por finalizado el post si no fuera por que existe un inconveniente a este método, algo que puede parecer increíble: en el framework de Microsoft IsNullOrEmpty() puede hacer que tu aplicación reviente en tiempo de ejecución en las versiones de producción (release) de los ensamblados debido a una mala optimización del JIT cuando utilizamos este método dentro de un bucle. No daré más detalles pues hay multitud de páginas hablando del problema (como VTortola, o El Bruno), pero aquí se aconsejan alternativas a utilizar. En fin, que este método, según se lee, debe ser usado con precaución, o incluso evitado si lo pensamos incluir en un bucle.

Llegados a este punto, por tanto, lo aconsejable es quedarnos con fórmulas artesanales como ((str == null)||(str.Length==0), hasta que IsNullOrEmpty esté en condiciones de ser utilizado, podemos suponer que en la próxima versión de la plataforma.

No he comprobado si existe el mismo problema sobre la plataforma Mono, pero dado que son implementaciones distintas lo más probable es que no ocurra, por lo que IsNullOrEmpty podría ser utilizado sin causar dolores de cabeza. A ver si un día tengo un ratillo y lo compruebo.

Hay que ver lo que da de sí una cosa tan simple, ¿eh?
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.
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.
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.