I have a List
containing some data. I would like to pass it to a function which accepts ReadOnlySpan
.
List i
Thanks for all the comments explaining that there's no actual way to do it and how exposing the internal Array inside List could lead to bad behaviour and a broken span.
I ended up refactoring my code not to use a list and just produce spans in the first place.
void Consume<T>(ReadOnlySpan<T> buffer)
// ...
var buffer = new T[512];
int itemCount = ProduceListOfItems(buffer); // produce now writes into the buffer
Consume(new ReadOnlySpan<T>(buffer, 0, itemCount);
I'm chosing to make the explicit tradeoff of over-allocating the buffer once to avoid making an extra copy later on.
I can do this in my specific case because I know there will a maximum upper bound on the item count, and over-allocating slightly isn't a big deal, however there doesn't appear to be a generalisation here, nor would one ever get added as it would be dangerous.
As always, software performance is the art of making (hopefully favorable) trade-offs.
In .Net 5.0, you can use CollectionsMarshal.AsSpan() (source, GitHub isue) to get the underlying array of a List<T>
as a Span<T>
.
Keep in mind that this is still unsafe: if the List<T>
reallocates the array, the Span<T>
previously returned by CollectionsMarshal.AsSpan
won't reflect any further changes to the List<T>
. (Which is why the method is hidden in the System.Runtime.InteropServices.CollectionsMarshal
class.)
You can write your own CustomList<T>
that exposes the underlying array. It is then on user code to use this class correctly.
In particular the CustomList<T>
will not be aware of any Span<T>
that you can obtain from the underlying backing array. After taking a Span<T>
you should not make the list do anything to create a new array or create undefined data in the old array.
The C++ standard library allows user code to obtain direct pointers into vector<T>
backing storage. They document the conditions under which this is safe. Resizing makes it unsafe for example.
.NET itself does something like this with MemoryStream
. This class allows you access to the underlying buffer and indeed unsafe operations are possible.