web-dev-qa-db-ja.com

安全でないキーワードなしで構造体のSpan <byte>ビューを取得する方法

_Span<byte>_ビュー(キャストの再解釈)を、コピーなし、割り当てなし、およびunsafeキーワードなしの単一の構造体値から作成するにはどうすればよいですか? 。

私は現在、安全でないキーワードを使用してのみこれを達成することができます:

_public unsafe Span<byte> AsSpan<T>(in T val) where T : unmanaged
{
    void* valPtr = Unsafe.AsPointer(ref Unsafe.AsRef(val));
    return new Span<byte>(valPtr, Marshal.SizeOf<T>());
}

// Alternatively, slightly easier when using 'ref' instead of 'in'
public unsafe Span<byte> AsSpan<T>(ref T val) where T : unmanaged
{
    void* valPtr = Unsafe.AsPointer(ref val);
    return new Span<byte>(valPtr, Marshal.SizeOf<T>());
}
_

単一の値ではなく配列を処理する場合、これはMemoryMarshal.Cast<TTo, TFrom>( ... )を使用して簡単かつ安全に実行できます。次に例を示します。

_public Span<byte> AsSpan<T>(Span<T> vals) where T : unmanaged
{
    return MemoryMarshal.Cast<T, byte>(vals);
}
_

Netstandard2.0、最新の言語バージョン_C# 7.3_、および_System.Memory_と_System.Runtime.CompilerServices.Unsafe_の最新のRCパッケージを使用する:

_<PropertyGroup>
   <TargetFramework>netstandard2.0</TargetFramework>
   <LangVersion>7.3</LangVersion>
</PropertyGroup>
<ItemGroup>
   <PackageReference Include="System.Memory" Version="4.5.0" />
   <PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.5.0" />
</ItemGroup>
_

編集:メモリの安全性/破損に関する返信に関して-C#7.3で導入されたunmanagedジェネリック制約は、structジェネリック制約を置き換えることができ、これをメモリセーフな方法で実行できます。

参照: https://docs.Microsoft.com/en-us/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters

_where T : unmanaged_ type引数は参照型であってはならず、ネストのどのレベルでも参照型メンバーを含んではなりません。

12
zone117x

部分的な解決策:

Netstandard2.0ではなくnetcoreappをターゲットにしている場合は、netcoreapp2.1で利用可能なAPIがあります(ダウンロード可能 ここ このコメント日現在)。


使用法:

using System.Runtime.InteropServices;

public Span<byte> AsSpan<T>(ref T val) where T : unmanaged
{
    Span<T> valSpan = MemoryMarshal.CreateSpan(ref val, 1);
    return MemoryMarshal.Cast<T, byte>(valSpan);
}

これはnotnetstandard2.0でこの機能を要求する質問の解決策です。それにもかかわらず、これはこれに遭遇する多くの人にとって役立つはずです。

4
zone117x