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