Uniones en C#

Hay veces que uno no encuentra lo que busca, y cuando no lo está buscando, lo encuentra. O algo así. El hecho está en que empecé a hacer una pequeña utilidad interna en C# que necesitaba bastantes estructuras y encima con campos repetidos.

Eso en C++ es fácil de solventar. Un se crea una jerarquía de estructuras igual que podría hacerlo de clases, y listo. Es decir, si yo necesito tres estructuras diferentes que tengan, por ejemplo, varios campos del mismo nombre y tipo, lo más fácil es crear una estructura base y heredar de ella. Algo así:

struct Base
{
    string Nombre;
    string NombreAlternativo;
};

struct Casa:public Base
{
    string Dirección;
};

struct Coche:public Base
{
    string Propietario;
};

De este modo ahorro escritura, ya que tanto la estructura Casa como Coche tendrán los campos Nombre y NombreAlternativo sin haberlos tenido que teclear. Suena un poco trivial pero cuando tienes diez o doce estructuras lo agradeces, incluso de esta forma te evitas los errores de tecleo y pones en una de ellas un campo con “Nonbre” en lugar de Nombre.

Eso en C++, en C# llega uno tan contento, se pone a picar código y… ¡ñas, no deja! El compilador protesta como un loco…

Me voy a la ayuda y, efectivamente, una limitación más del .NET: pese a que ellas mismas heredan de ValueType e indirectamente de Object (por cierto realizando una metástasis muy extraña y pasando de ser un tipo-referencia, como es Object, a un tipo-valor…)

Pero sigo leyendo para abajo y me encuentro con una sorpresa, y es cómo hacer uniones aprovechando los atributos.

El tema está aquí, y básicamente viene a decir, en la sección “Attributes on Structs”, que utilizando los atributos “LayoutKind.Explicit” y “FieldOffset”, podemos definir el punto de inicio de cada elemento de la estructura de forma manual.

Veamos un ejemplo muy socorrido en C/C++ en relación a las direcciones IP, que todos hemos manejado alguna vez. Una dirección IP se puede ver como un entero sin signo de 32 bits (que es como las ve el software) o como cuatro números situados entre 0 y 255. Esto en C/C++ se puede expresar así:

union IP
{
    __int32 As32bits;
    unsigned char asBytes[4];
};

Para referirnos a ellas, podemos usar ambas partes y ambas serán el mismo valor:

IP miIP;
miIp.AsBytes[0]=192;
miIp.AsBytes[0]=168;
miIp.AsBytes[0]=1;
miIp.AsBytes[0]=1;

Y como miIP.As32bits tendremos en valor equivalente.

Pues bien, en C# esto se puede conseguir más o menos así:

using System.Runtime.InteropServices;
[StructLayour(LayoutKind.Explicit)]
struct IP
{
    [FieldOffset(0)]
    Public Int32 As32bits;
    [FieldOffset(0)]
    Public byte a;
    [FieldOffset(1)]
    Public byte b;
    [FieldOffset(2)]
    Public byte c;
    [FieldOffset(3)]
    Public byte d;
}

Y podríamos acceder a ella tanto asignando los valores a, b, c, d como As32bits. También podríamos añadirlo como un array, pero eso queda de ejercicio de clase.

(NOTA: La entrada está escrita sin comprobar el código, por lo que podría haber algún gazapo. De todos modos, la esencia del código es correcta.)

2 comentarios sobre “Uniones en C#”

  1. Hay un pequeño error en donde debería poner:

    [StructLayout(LayoutKind.Explicit)]

    El problema es que si usas LayoutKind.Explicit creas una estructura insegura (unsafe), lo que le quita mucha de la gracia.

Responder a rfog Cancelar respuesta

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