web-dev-qa-db-fra.com

Comment obtenir une vue Span <byte> d'une structure sans le mot clé unsafe

Comment une vue Span<byte> (réinterpréter la distribution) peut-elle être créée à partir d'une seule valeur de structure sans copie, sans affectation et sans le mot clé unsafe

Je ne peux actuellement accomplir cela qu'en utilisant le mot clé 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>());
}

Lorsque vous traitez avec un tableau plutôt qu'une valeur unique - ceci est fait facilement et en toute sécurité en utilisant MemoryMarshal.Cast<TTo, TFrom>( ... ), par exemple:

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

Utilisation de netstandard2.0, de la dernière version de la langue C# 7.3 et des derniers packages RC pour System.Memory et System.Runtime.CompilerServices.Unsafe:

<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>

Edit: Concernant les réponses à propos de la sécurité/corruption de la mémoire - la contrainte générique unmanaged introduite dans C # 7.3 peut remplacer la contrainte générique struct et permettre que cette opération soit effectuée de manière sécurisée en mémoire. 

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

where T : unmanaged L'argument type ne doit pas être un type référence et ne doit contenir aucun membre de type référence à aucun niveau d'imbrication.

7
zone117x

Solution partielle: _

Si vous ciblez netcoreapp plutôt que netstandard2.0, une API est disponible dans netcoreapp2.1 (disponible au téléchargement ici à compter de la date de ce commentaire).


Usage:

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

Ceci est not une solution à la question qui demande cette capacité dans netstandard2.0. Néanmoins, cela devrait être utile à beaucoup de personnes qui tombent sur cela. 

4
zone117x