Its not a "safe" operation, though it is a useful one to gain access to the prebuilt array; without first copying using .ToArray()
namespace System.Runtime.InteropServices
{
public partial static class CollectionsMarshal
{
public Span<T> AsSpan(List<T> list);
public Memory<T> AsMemory(List<T> list);
}
}
/cc @jkotas
I do not think this should be on MemoryMarshal. This should be on a new one, like CollectionsMarshal.
This should not be an extension method. No other methods on *Marshal are extension methods to make you do more typing.
The PowerCollections in corefxlab would be a good place to experiment with this: https://github.com/dotnet/corefxlab/issues/2406
Updated
The PowerCollections in corefxlab would be a good place to experiment with this
Would then need to go via private reflection?
@jkotas is reflection what you have in mind?
@benaadams curious, do you happen to have a motivating scenario?
curious, do you happen to have a motivating scenario?
List<T> is a very convenient datastructure for creating an array of an unknown size. However, to use it as an array you need to copy the entire contents again with .ToArray().
AsSpan/AsMemory would give the "array" correctly bounded (size of List rather than size of backing array); without the copy.
@jkotas is reflection what you have in mind?
I had in mind all the different list and array builders in "Common". They are all variants of List with different performance characteristics.
All internal though 😢
Would it make sense to propose a "ListBuilder"/"SpanBuilder" type then? It could have roughly the same surface area as List, along with an AsSpan/AsMemory method. Once those are called, mutation is no longer allowed.
@ahsonkhan
@safern this does not seem to me essential in order to ship 3.0. Please correct me if I'm wrong.
any updates, just wondering? Sounds like a great API :smiley:
@benaadams We understand that this a logical extension of the current implementation of the type. Could you list some compelling scenarios? We can always come up with potential scenarios.
Creating a Memory/Span (Array-like) of an unknown upfront size. List<T> is currently the main builder type; but getting an array from it .ToArray() causes a secondary allocation.
The alternative would be to expose an alternative builder type https://github.com/dotnet/corefx/issues/31597#issuecomment-413059736
FYI, it's currently being discussed here.
I missed this when I had a list and wanted to do something (been a while... can't remember what the exact situation was) which could be vectorised (since you need to take pointer of the underlying array). It didn't have to be exposed as a Span... but just my thought.
Approved shape:
```C#
namespace System.Runtime.InteropServices
{
public partial static class CollectionsMarshal
{
public static Span
public static ReadOnlySpan
// We don't want this one:
// public Memory<T> AsMemory(List<T> list);
}
}
```
Re-opening until API is exposed from the ref assembly.
The “approved shape” wasn’t completely implemented with https://github.com/dotnet/coreclr/pull/26867. Should we update the “approved shape” above so it is in sync with the code?
Re-flagging as api-ready-for-review to address the AsReadOnlySpan change and also do a quick review on the nullable annotations change (see https://github.com/dotnet/coreclr/pull/26903).
```C#
namespace System.Runtime.InteropServices
{
public partial static class CollectionsMarshal
{
// Updated with nullable annotation
public static Span
// Since the AsSpan(...) overload is no longer changing the internal version,
// we don't need this one anymore
// public static ReadOnlySpan<T> AsReadOnlySpan(List<T> list);
// We don't want this one:
// public Memory<T> AsMemory(List<T> list);
}
}
```
We decided to not increment the version, which is why we removed the AsReadOnlySpan() overload.
C#
namespace System.Runtime.InteropServices
{
public partial static class CollectionsMarshal
{
public static Span<T> AsSpan(List<T>? list);
}
}
Most helpful comment
Video
Approved shape:
```C# AsSpan(List list); AsReadOnlySpan(List list);
namespace System.Runtime.InteropServices
{
public partial static class CollectionsMarshal
{
public static Span
public static ReadOnlySpan
}
```