MemoryMarshal contains several APIs that allow reinterpreting Span<byte>, but none of them are a good fit for interpreting Span
MemoryMarshal.Read allows interpreting Span<byte> as arbitrary struct. It creates a local copy that is fine and beneficial for small structs, but becomes expensive for large structs.MemoryMarshal.Cast allows interpreting Span<byte> as sequence of arbitrary structs. It does not create a local copy, but comes with extra overhead required to compute the length of the resulting span.MemoryMarshal.GetReference + Unsafe.As does not create a local copy, but also skips any bounds checks that is not good for security defense in depth.Add methods that allow interpreting Span<byte> as arbitrary large struct without copying to MemoryMarshal.
static class MemoryMarshal
{
public static ref readonly T AsRef<T>(System.ReadOnlySpan<byte> span) where T : struct { throw null; }
public static ref T AsRef(System.Span<byte> span) where T : struct { throw null; }
}
Implementation of these methods is going to be faster functional equivalent of ref MemoryMarshal.Cast<byte, T>(span)[0].
These APIs come with the same set of portability caveats as Memory.Cast. They can be only used when the memory block is sufficiently aligned by other means; or when the target platform does not require strong memory alignment.
Related proposal for other direction dotnet/runtime#24656
dotnet/corefx#30614 has multiple examples of how these methods can be used in real-world code.
A bit like Marshal.PtrToStructure<T> Method (IntPtr) but generally safer, including a >= sizeof(T) check; and ref returning rather than copying?
Right.
Could this use the unmanaged constraint instead of the struct constraint? GC references wouldn't be a good thing with this API.
The implementation will enforce no-GC references at runtime just like MemoryMarshal.Cast and other similar APIs. unmanaged constrain is enforcing more than no-GC references. It would make this API less useful and inconsistent with the rest of the MemoryMarshal and Span methods.
This API and scenarios make sense but we shouldn't use Struct in the name. It seems to make more sense to align this with Unsafe.AsRef(), thus:
static class MemoryMarshal
{
public static ref readonly T AsRef<T>(ReadOnlySpan<byte> span) where T : struct;
public static ref T AsRef(Span<byte> span) where T : struct;
}
@terrajobst where T : unmanaged ?
@mgravell https://github.com/dotnet/corefx/issues/30613#issuecomment-400143239
@jkotas apparently I fail at reading today, thx
Is it possible to use AsRef in .NET Standard 2.1? I was only able to use it targeting netcoreapp3.0
@virzak best to ask this in the dotnet/standard repo
Most helpful comment
Video
This API and scenarios make sense but we shouldn't use
Structin the name. It seems to make more sense to align this withUnsafe.AsRef(), thus: