How do I create a Span<T> of length 1 over a single variable (field or ref parameter) of type T
Asked Answered
C

3

10

This question is regarding types Span<T> and RealOnlySpan<T> in .NET Core. The documentation explains how to create a span over an array, or an array segment, or a stack-allocated or unmanaged memory. In some circumstances I would like to create a span of length 1 over a single variable (a field, a ref parameter, or ref local) to pass it to API that can deal with arbitrary spans. How can I do that?

I imagine there could be a constructor Span<T>.Span(ref T), but apparently there isn't one. Copying the variable into an array and creating a span over that array does not solve the problem, because any modifications of the span would not reflect on the original variable.

Cordey answered 28/11, 2019 at 20:55 Comment(0)
P
9
MemoryMarshal.CreateSpan<T>(ref T reference, int length)

Passing 1 in as the length argument. Note, this is inherently unsafe* which is why its in the System.Runtime.InteropServices namespace.

*Its not checked for validity in anyway, if the length is too long you will overwrite other memory, if you return the span from a method and its a local variable you are in trouble etc.

Princely answered 28/11, 2019 at 21:23 Comment(1)
The unsafety here is not that it is not checked for validity (after all if you doubt a ref T points to at least one element, you have a bigger problem elsewhere), but that the result's lifetime is not tied to the reference's ‒ the span is not protected from leaking.Backwash
L
6

A safe alternative to the accepted answer, provided your type is a struct (Example: int value initialized as 123):

ReadOnlySpan<int> mySpan = stackalloc int[1] { 123 };

If you want a non-readonly span, you can declare your variable as a reference to the first element of the span, like so:

Span<int> mySpan = stackalloc int[1] { 123 };
ref var myVariable = ref mySpan[0];

Now accessing either the variable or the content of the span will access/write the same value.

Leporid answered 6/3, 2022 at 9:51 Comment(0)
B
1

Since .NET 7, there is the Span(ref T) constructor finally, since the value type now wraps a real ref T inside, and the language rules were updated to protect against leaks. Do not use MemoryMarshal.CreateSpan for this purpose anymore.

Backwash answered 9/9 at 11:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.