potisanのプログラミングメモ

趣味のプログラマーがプログラミング関係で気になったことや調べたことをいつでも忘れられるようにメモするブログです。はてなブログ無料版なので記事の上の方はたぶん広告です。記事中にも広告挿入されるみたいです。

C# 9 バイト配列からメモリ上の読み枠を広げた整数配列を作成する

#nullable enable

using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

[MethodImpl(MethodImplOptions.AggressiveInlining)]
static uint[] CreateUInt32ArrayRough(ReadOnlySpan<byte> value)
    => MemoryMarshal.Cast<byte, uint>(value).ToArray();

[MethodImpl(MethodImplOptions.AggressiveInlining)]
static uint[] CreateUInt32ArrayStrict(ReadOnlySpan<byte> value)
{
    if (value.Length % 4 != 0)
        throw new ArgumentException("領域の長さが不正です。");
    return CreateUInt32ArrayRough(value);
}

SpanReadOnlySpan)とMemoryMarshal.Castを使用してバイト配列を整数配列へ変換できます。MemoryMarshal.Castは元のメモリ領域の長さが不足しても余分を無視して成功してしまうため、余分の無視を許容するRough版と例外を発生するStrict版を用意しています。

また現在のC#ではジェネリックsizeof(T)が使えないため、具体的なuintUInt32)に対してCreateUInt32ArrayRough/Strictを定義しています。

使用例

#nullable enable

using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

var b = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };

// uint[2] {0x04030201, 0x08070605}
var ui1 = CreateUInt32ArrayRough(b);
// uint[1] {0x04030201]
var ui2 = CreateUInt32ArrayRough(b[0..5]);

// uint[2] {0x04030201, 0x08070605}
var ui3 = CreateUInt32ArrayStrict(b);
// <ArgumentException>
var ui4 = CreateUInt32ArrayStrict(b[0..5]);

Console.WriteLine();

[MethodImpl(MethodImplOptions.AggressiveInlining)]
static uint[] CreateUInt32ArrayRough(ReadOnlySpan<byte> value)
    => MemoryMarshal.Cast<byte, uint>(value).ToArray();

[MethodImpl(MethodImplOptions.AggressiveInlining)]
static uint[] CreateUInt32ArrayStrict(ReadOnlySpan<byte> value)
{
    if (value.Length % 4 != 0)
        throw new ArgumentException("領域の長さが不正です。");
    return CreateUInt32ArrayRough(value);
}