potisanのプログラミングメモ

プログラミング素人です。昔の自分を育ててくれたネット情報に少しでも貢献できるよう、情報を貯めていこうと思っています。Windows環境のC++やC#がメインです。

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);
}