C# Unions

snarfblam

Mega-Ultra Chicken
Joined
Jun 10, 2003
Messages
1,832
Location
USA
User Rank
*Expert*
C++ offers a special kind of type that is not present in C#: a union.

For anyone who is not familiar with unions, here is a quick explanation of how they work and what theyre good for.

How They Work
A union is somewhat like a struct. A union definition defines a type. A union type has fields and methods like a struct. The key difference is that a union stores all of its fields in the same memory location, whereas a struct stores each field in a different memory location.
04e9989f2aca3872ab2dfcd52644952a.gif
40b8e9889d57877ca3d34e16554f521d.gif

What they are good for
The primary use for a union is to conserve memory. Because the fields are stored in the same memory, generally only one field can be used at a time. Assigning one field changes the values of all fields, possibly to an invalid value. But, because all fields are stored in the same location, the size of the union is the size of the largest field, whereas the size of a struct is, at least, the total of the sizes of all fields.

There is another use for unions too: treating the same binary data as different kinds of values. For instance, we could store an IntPtr in a union and then retrieve the value as a regular Int32. In other words, we can convert and dissect data with a union.

Why Bother?
Nearly any kind of conversion we could make through the use of a union we could make through the use of the Convert and BitConverter classes, so why bother using a union? Because it would be fast. The use of a union would be as an optimization. Although a union can occasionally produce less code than the use of conversion classes, the code tends to be harder to read and must be written with much more care because it can introduce kinds of bugs we arent used to encountering. They should only be used when you really need the speed.

And Now, For Your Viewing Pleasure
If unions are a feature that is not present in C# then why did you read all that? Because unions are a feature present in the Common Language Runtime, and this feature can be utilized through the use of attributes, specifically the System.Runtime.InteropServices.StructLayoutAttribute and the System.Runtime.InteropServices.FieldOffsetAttribute.

Where C++ uses the union keyword for unions, C# must modify a struct with attributes to produce the same behavior. System.Runtime.InteropServices.StructLayoutAttribute allows us to specify how, in memory, the fields of a struct will be laid out : automatically, sequentially, or explicitly. We are looking for the last of the three.

When we are using an explicit layout, System.Runtime.InteropServices.FieldOffsetAttribute is the attribute that specifies where in memory the field will be. For instance, to view the binary value of a char as an unsigned integer, we could use the following struct:
C#:
[StructLayout(LayoutKind.Explicit)]
public struct CharShortConverter
{
    [FieldOffset(0)]
    public char Char;

    [FieldOffset(0)]
    public ushort UShort;

    // This method is not necessary to use a union, but it is very helpful because
    // otherwise we would have to explicitly initialize all the fields each time
    // we declare a variable of this type.
    public static CharShortConverter GetConverter() {
        CharShortConverter converter;

        converter.Char =  ;
        converter.UShort = 0;

        return converter;
    }
}
This struct could be used as follows:
C#:
// Get a converter
CharShortConverter converter = CharShortConverter.GetConverter();

// Assign a char to the union, read it back as a UShort, and display the value.
converter.Char = x;
MessageBox.Show(converter.UShort.ToString());

It would be much quicker, of course, to write code that used the BitConverter class, and usually much smarter, too. If, however, we had to convert a very large number of chars to ushorts, the use of a union could speed things up quite a bit. Instead of invoking a function we only need to assign a variable and read it back.

Shortcomings
The first shortcoming of this method is clearly visible in the first code listing. Because C# has no understanding of what a union is, it does not understand that assigning a value to one field initializes all fields, and so we must initialize the same memory multiple times to make the compiler happy. To make our lives easier, it is smartest to write a static method that will return an already-initialized variable.

The second shortcoming is that, unlike C++, a C# union cant contain arrays. C# unions cant contain any reference types (reference types are garbage collected and structs are not), and arrays are reference types. This means that where in C++ we could access the bytes of an 64-bit integer by index, in C# we must declare eight fields and access them by name.

A Useful Example
The CharShortConverter isnt particularly useful, although I have a much more useful example, which is actually the reason I investigated unions in C# in the first place: image processing. When using unsafe code or the Marshal class to access raw image (as in the tutorial, Bitmap Manipulation) data it is very handy to have a quick way to access the individual color components of each pixel, and so we have the Pixel struct.
C#:
// Represents a 32-bit ARGB pixel
// Allows pixel data to be accessed much faster than via
// the Color struct or the BitConverter class.
[StructLayout(LayoutKind.Explicit)]
public struct Pixel
{
    // Composite ARGB value
    [FieldOffset(0)] public int ARGB;
    // Color components
    [FieldOffset(3)] public byte A;
    [FieldOffset(2)] public byte R;
    [FieldOffset(1)] public byte G;
    [FieldOffset(0)] public byte B;

    // Method to get an instance of this union
    public static Pixel GetPixel() {
        Pixel result;

        result.A = 0;
        result.R = 0;
        result.G = 0;
        result.B = 0;
        result.ARGB = 0;

        return result;
    }

    // Set this union to represent the specified color
    public void LoadColor(System.Drawing.Color c) {
        ARGB = c.ToArgb();
    }

    // Create a Color struct that represents this union
    public Color ToColor() {
        return Color.FromArgb(ARGB);
    }
}
 
Last edited by a moderator:
Back
Top