Open3
dotnet/C#でバイナリ操作したい
バイナリストリームから定義した構造体で読み取る
Span<byte>
とMemoryMarshal.Cast<byte, TStruct>
と定義したTStruct
で読み取れる。強い。
[StructLayout(LayoutKind.Sequential)]
public struct MyStruct
{
public readonly int A;
public readonly int B;
}
Span<byte> buffer = new []{/*...めっちゃ長いバイナリストリーム...*/};
int start = 1234;
MyStruct a = MemoryMarshal.Cast<byte, MyStruct>(buffer.Slice(start, 2))[0];
System.Memory
で導入
Span<T>
/ Memory<T>
.NET Standard 2.0 でも .NET Standard 2.0 (古い.NET Framework 4.*系も対応)でも、nugetでSystem.Memory
導入することで使える(Slow Span)。Slowと言ってもbyte[]
やIList<byte>
より効率良いらしい。
(C#の配列ではコピーが発生するため)
Span<T>
/ Memory<T>
使い分け
- まずは
Span<T>
(バイナリ操作ならSpan<byte>
) - 制限に引っかかるのであれば
Memory<T>
- その上で読み込みのみなら
ReadOnlySpan<T>
/ReadOnlyMemory<T>
に置き換え
変換
Memory<T> -> Span<T> は Span
プロパティでカンタンにできるが、
Span<T> -> Memory<T> が問題。
Memory<byte> m = new Memory<byte>(span.ToArray());
配列を経由するので大量に呼び出す時はメモリに注意。
※特にバイナリ操作だと問題になりがち。
stackalloc
サイズが小さい時は Span<byte>
を使う際、stackalloc
を使うとメモリの「スタック領域」が使われ、高速になる(通常は「ヒープ領域」)。
Span<byte> span = stackalloc byte[100];
容量制限(2GBぐらいらしい?)に注意すれば、Span<T>
との組み合わせで安全に使える。
※Span<T>
登場以前は以前はUnsafeな操作だった。