85

I'm translating a library written in C++ to C#, and the keyword 'union' exists once. In a struct.

What's the correct way of translating it into C#? And what does it do? It looks something like this;

struct Foo {
    float bar;

    union {
        int killroy;
        float fubar;
    } as;
}
timrau
  • 22,578
  • 4
  • 51
  • 64
Viktor Elofsson
  • 1,581
  • 2
  • 13
  • 20
  • It might be safer but when you're interacting with C libraries that provide these sorts of data structures this decision in C# breaks even the rudimentary encapsulation of your C/C++ structures. I'm trying to deal with something like this: struct LibrarySType { AnotherType *anotherTypeBuff; int oneSetOfFlags; int anotherSetOfFlags; union { struct { int structMember1; ... } oneUseOfThisLibraryType; struct { char *structMember2; ... } anotherUseOfThisLibraryType; ... } u; int64 *moreStuff; ... you get the idea } Now I didn't invent this clever data structure, but it's part of a vendor API I need – Steve Wart Oct 19 '10 at 18:30

7 Answers7

95

You can use explicit field layouts for that:

[StructLayout(LayoutKind.Explicit)] 
public struct SampleUnion
{
    [FieldOffset(0)] public float bar;
    [FieldOffset(4)] public int killroy;
    [FieldOffset(4)] public float fubar;
}

Untested. The idea is that two variables have the same position in your struct. You can of course only use one of them.

More informations about unions in struct tutorial

Armin Ronacher
  • 31,998
  • 13
  • 65
  • 69
  • 10
    Note that this will work only if the types involved are primitive types (like int and float). Once objects are involved, it won't let you. – Khoth Sep 24 '08 at 12:40
  • 13
    Does it work with value types (like enum) or just primitive types? – Taylor Leese Jul 24 '09 at 18:53
  • 1
    If you have other complex types, the second one could be a property that converts to/from the other. Depends on the usage of the Union and how it is used in other code you are porting. – AaronLS Nov 12 '12 at 05:47
  • 2
    "You can of course only use one of them." may be unclear. You can access and set both of them, but they overwrite each other. I would clarify this point. – Xonatron Oct 24 '17 at 03:10
  • @Khoth You can hold anything in a field in a struct. Same with explicit struct layouts. –  Apr 09 '20 at 21:42
  • Re **overlapping** an **object reference** with another field: Whether this is allowed depends on the **security** of the environment you are running in. On `UWP`, as soon as you attempt to create an instance of the struct, you'll get `System.TypeLoadException`. – ToolmakerSteve Dec 01 '21 at 21:30
  • As mentioned previously (but with no reference), Structs can also be used as C# "union" members. See or search for the defunct SO Docs page "How to use C# Structs to create a Union type (Similar to C Unions)", currently found here: https://sodocumentation.net/csharp/topic/5626/how-to-use-csharp-structs-to-create-a-union-type---similar-to-c-unions- with Fiddle: https://dotnetfiddle.net/cROlki (Or, just try it... :) This doesn't mention security issues so I can't comment on that, my use was not UWP). – Maxim Paperno Mar 13 '22 at 22:15
  • What do the `FieldOffset` values denote? A byte position? – Mike Bruno Oct 27 '22 at 19:36
22

You can't really decide how to deal with this without knowing something about how it is used. If it is merely being used to save space, then you can ignore it and just use a struct.

However that is not usually why unions are used. There two common reasons to use them. One is to provide 2 or more ways to access the same data. For instance, a union of an int and an array of 4 bytes is one (of many) ways to separate out the bytes of a 32 bit integer.

The other is when the data in the struct came from an external source such as a network data packet. Usually one element of the struct enclosing the union is an ID that tells you which flavor of the union is in effect.

In neither of these cases can you blindly ignore the union and convert it to a struct where the two (or more) fields do not coincide.

Steve Fallows
  • 6,274
  • 5
  • 47
  • 67
  • 3
    What I think is important in Steve's answer, is you really need to understand the usage of the particular union you are porting. There may be other constructs in C# that will meet the needs in a more elegant way. – AaronLS Nov 12 '12 at 05:48
  • 3
    Though I understand what @AaronLS meant, it would be nice a link to docs or something about common ways to do that _elegantly_ in C#. I can guess some of the very basic ways, depending on the usage, like using properties to return a 'cast' of one value of the union as it was the other member. But wonder what other elegant ways could be for the common scenarios. – 40detectives Jun 27 '19 at 12:00
6

In C/C++ union is used to overlay different members in the same memory location, so if you have a union of an int and a float they both use the same 4 bytes of memory to store, obviously writing to one corrupts the other (since int and float have different bit layout).

In .Net Microsoft went with the safer choice and didn't include this feature.

EDIT: except for interop

Striezel
  • 3,693
  • 7
  • 23
  • 37
Nir
  • 29,306
  • 10
  • 67
  • 103
  • that could be because .NET is higher-level and you probably don't have to worry about explicitly serializing data and transferring between little-endian and big-endian machines. Unions provide a nice way to convert, using the trick a previous comment noted. – tloach Sep 24 '08 at 15:41
  • 2
    The use of explicit-layout structures is not limited to interop. Primitives and public members of non-reference types can overlay other primitives and public members of non-reference types in arbitrary fashion with fully defined behavior, whether or not code ever passes the structures in question to outside code. In this regard, .NET supports lower-level constructs than "modern" C. – supercat Aug 01 '18 at 14:56
4

If you're using the union to map the bytes of one of the types to the other then in C# you can use BitConverter instead.

float fubar = 125f; 
int killroy = BitConverter.ToInt32(BitConverter.GetBytes(fubar), 0);

or;

int killroy = 125;
float fubar = BitConverter.ToSingle(BitConverter.GetBytes(killroy), 0);
Steve Lillis
  • 3,263
  • 5
  • 22
  • 41
0

You could write a simple wrapper but in most cases just use an object it is less confusing.

    public class MyUnion
    {
        private object _id;
        public T GetValue<T>() => (T)_id;
        public void SetValue<T>(T value) => _id = value;
    }
-1

Personally, I would ignore the UNION all together and implement Killroy and Fubar as separate fields

public struct Foo
{
    float bar;
    int Kilroy;
    float Fubar;
}

Using a UNION saves 32 bits of memory allocated by the int....not going to make or break an app these days.

ckramer
  • 9,419
  • 1
  • 24
  • 38
  • 9
    this might not work depending on how it is accessed by other parts of the library, in some instances you can write to one instance and read from the other to get the same data but in a slightly different format, that functionality will be broken if you split it into two distinct variables – KPexEA Sep 24 '08 at 20:51
  • 1
    @KPexEA I agree. However, if on the other hand, it is the type of union where some flag indicates which of the two fields is the appropriate one, then this will work fine. I think what is really important is to understand the usage and purpose of the union in each case, before deciding how to port it. – AaronLS Nov 12 '12 at 05:53
  • 5
    If you want to create a structure with 10 or 20 unioned types, as structs are byval, it's much faster to pass around a couple bytes than 1k per argument. – Brain2000 Sep 12 '18 at 16:17
-4
public class Foo
{
    public float bar;
    public int killroy;

    public float fubar
    {
        get{ return (float)killroy;}
        set{ killroy = (int)value;}
    }
}
Yan Chen
  • 53
  • 2
  • 7