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 en “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.

Deja un comentario

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