[C#] C/C++相当の共用体(union)を扱う

C/C++ではメンバのメモリ領域を共有できる共用体が存在しますが、C#には存在しません。
しかし、属性を駆使して共用体を実装することは可能です。

具体的なコードは以下のようになります。

    [System.Runtime.InteropServices.StructLayout(LayoutKind.Explicit)]
    struct TestUnion {
        [System.Runtime.InteropServices.FieldOffset(0)]
        public int i;

        [System.Runtime.InteropServices.FieldOffset(0)]
        public double d;

        [System.Runtime.InteropServices.FieldOffset(0)]
        public char c;

        [System.Runtime.InteropServices.FieldOffset(0)]
        public byte b;
    }

structの頭に付けている属性[System.Runtime.InteropServices.StructLayout(LayoutKind.Explicit)]はstructを共用体として定義するためのおまじないと思って良いでしょう。
これは外部のアンマネージコード側からC#のクラスを扱いたい場合などにフィールドのオフセットを厳密に指定したい場合などに使用します。

フィールドのオフセットは[System.Runtime.InteropServices.FieldOffset(0)]で指定しています。
0の部分がオフセット値となり、構造体の先頭アドレスを指します。
すべてのフィールドにこの属性記述をしているので、これらが先頭アドレスに配置されることになります。
まさに共用体そのものですね。

この構造体に値を入れて表示すると以下のようになります。

■サンプル

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;

namespace UnionTest {
    // 共用体
    [System.Runtime.InteropServices.StructLayout(LayoutKind.Explicit)]
    struct TestUnion {
        [System.Runtime.InteropServices.FieldOffset(0)]
        public int i;

        [System.Runtime.InteropServices.FieldOffset(0)]
        public double d;

        [System.Runtime.InteropServices.FieldOffset(0)]
        public char c;

        [System.Runtime.InteropServices.FieldOffset(0)]
        public byte b;
    }

    class Program {
        static void Main(string[] args) {
            // 値を代入して表示
            TestUnion tu = new TestUnion();

            tu.i = 123;
            System.Console.WriteLine(tu.i);
            tu.d = 0.0;
            System.Console.WriteLine(tu.i);
            tu.c = 'A';
            System.Console.WriteLine(tu.i);
            tu.c = 'B';
            System.Console.WriteLine(tu.i);
        }
    }
}

■実行結果

123
0
65
66

共用体の実装が煩雑になるのが残念ですが、使う側は今まで通りの記述でできるので良いですね。

■参考サイト
方法: 属性を使用して C/C++ の共用体を作成する (C# および Visual Basic)
LayoutKind 列挙体 (System.Runtime.InteropServices)
アンマネージドコードとは 「アンマネージコード」 (unmanaged code): – IT用語辞典バイナリ