我有List<T>一些包含一些数据.我想把它传递给一个接受的函数ReadOnlySpan<T>.
List<T> items = GetListOfItems();
// ...
void Consume<T>(ReadOnlySpan<T> buffer)
// ...
Consume(items??);
Run Code Online (Sandbox Code Playgroud)
在这个特定的例子中,T是,byte但它并不重要.
我知道我可以.ToArray()在List上使用,并构造一个span,例如
Consume(new ReadOnlySpan<T>(items.ToArray()));
Run Code Online (Sandbox Code Playgroud)
然而,这会创建(看似)不必要的项目副本.有没有办法直接从列表中获取Span?List<T>是在T[]幕后实施的,所以从理论上来说这是可能的,但在实践中并没有我能看到的那么多?
svi*_*ick 24
在 .Net 5.0 中,您可以使用CollectionsMarshal.AsSpan()( source , GitHub isue ) 将 a 的底层数组获取List<T>为 a Span<T>。
请记住,这仍然不安全:如果List<T>重新分配数组,则Span<T>先前返回的CollectionsMarshal.AsSpan将不会反映对List<T>. (这就是该方法隐藏在System.Runtime.InteropServices.CollectionsMarshal类中的原因。)
感谢所有评论,解释了没有实际的方法可以做到这一点,以及暴露 List 内的内部数组可能会导致不良行为和跨度损坏。
我最终重构了我的代码,不使用列表,而只是首先生成跨度。
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);
Run Code Online (Sandbox Code Playgroud)
我选择进行一次过度分配缓冲区的明确权衡,以避免稍后制作额外的副本。
我可以在我的具体情况下这样做,因为我知道项目数量有一个最大上限,并且稍微过度分配并不是什么大问题,但是这里似乎没有一个概括,也不会添加,因为这会很危险。
一如既往,软件性能是做出(希望是有利的)权衡的艺术。