個人的備忘録

調べたり思いついたりした事の置き場

BinaryWriter/Readerとエンディアン変換

.Net FrameworkのBinaryWriter/Readerはビッグエンディアンに対応していない。
ので、ビッグエンディアンを扱う場合はこんな感じで書いていた。

static void Main(string[] args)
{
    using (var stream = new MemoryStream())
    using (var writer = new BinaryWriter(stream))
    {
        writer.Write(SwapBytes(0x1234));
    }
}
static UInt16 SwapBytes(UInt16 value)
{
    return (UInt16)((value << 8) | (value >> 8));
}

別にこれはこれでなんの不都合もないのだが、ふと暗黙の型変換を使うと綺麗にかけるのではないかと思い立つ。

public struct UInt16BigEndian
{
    UInt16 value;

    public static implicit operator byte[](UInt16BigEndian target)
    {
        return new byte[] { (byte)(target.value >> 8), (byte)(target.value & 0xff) };
    }
    public static implicit operator UInt16 (UInt16BigEndian target)
    {
        return target.value;
    }
    public static implicit operator UInt16BigEndian(UInt16 target)
    {
        return new UInt16BigEndian(target);
    }
    public static implicit operator UInt16BigEndian(byte[] bytes)
    {
        return new UInt16BigEndian((UInt16)((bytes[0] << 8) | bytes[1]));
    }

    public UInt16BigEndian(UInt16 value)
    {
        this.value = value;
    }
}

こんな感じの型を定義する。
ついでにStreamの拡張メソッドも定義する。

static class StreamExtension
{
    public static void WriteBytes(this Stream stream,byte[] bytes)
    {
        stream.Write(bytes, 0, bytes.Length);
    }
    public static byte[] ReadBytes(this Stream stream, int length)
    {
        var buf = new byte[length];
        stream.Read(buf, 0, length);
        return buf;
    }
}

すると、こんなふうに使える。

class Packet
{
    public UInt16 Length { get; set; }
    public byte[] Data { get; set; }

    public byte[] ToByteArray()
    {
        using (var stream = new MemoryStream())
        {
            stream.WriteBytes((UInt16BigEndian)Length);
            stream.WriteBytes(Data);

            return stream.ToArray();
        }
    }

    public static Packet CreateFrom(byte[] bytes)
    {
        using (var stream = new MemoryStream(bytes))
        {
            UInt16BigEndian length = stream.ReadBytes(2);
            byte[] data = stream.ReadBytes(length);

            return new Packet { Length = length, Data = data };
        }
    }
}

中々見た目が良い。