ref foreach 与 List

Dan*_*Dan 11 c#

为什么不能在迭代 a 的循环ref var中使用?foreachList<T>

Random rand = new();

// This is fine
Span<int> numbers = new int[] { 3, 14, 15, 92, 6 };
foreach (ref var number in numbers)
{
    number = rand.Next();
}

// This is not fine
List<int> nums = new() { 3, 14, 15, 92, 6 };
foreach (ref var number in nums)
{
    number = rand.Next();
}
Run Code Online (Sandbox Code Playgroud)

The*_*ias 9

这是因为Span<T>配备了一个具有ref Current属性的枚举器,而 则List<T>没有。

Span<T>.Enumerator.Current财产:

public ref T Current { get; }
Run Code Online (Sandbox Code Playgroud)

List<T>.Enumerator.Current财产:

public T Current { get; }
Run Code Online (Sandbox Code Playgroud)

List<T>如果需要,您可以使用该方法访问 a 的内部存储CollectionsMarshal.AsSpan<T>


更新:实际上,正如 @GuruStron 在评论中指出的那样,C# 编译器甚至不使用该Span<T>.Enumerator结构,而是将foreach循环转换为快速while循环。例如下面的代码:

foreach (ref int item in span)
{
    //...
}
Run Code Online (Sandbox Code Playgroud)

...翻译为:

int i = 0;
while (i < span.Length)
{
    ref int item = ref span[i];
    //...
    i++;
}
Run Code Online (Sandbox Code Playgroud)

  • 同样基于[反编译](https://sharplab.io/#v2:D4AQTAjAsAUCAMACEEAsBuWsBKBDAdgCYD2AtogE4GGIC8i+ApgO4AUAlJjAMoAOBAHgCW+AC4A+BgFdSAI0YUAznQYtEI0QG0AuogDeiAMwAaRGlMQArKYCcYUwDZEAXy4AzYhUa 4AxgAtEVi83RAA3XAppOQV1fCj5JXZYPVhENPiY+ioiADoAOUYAD1EOLmcsGAAZIUVRYTFJfBlleiY2dn0jC1QLa0Q7RxcuWA8vXwDWcMim6MiRKMUkmBSYdOQIG1YZhM5YcpggA===)在这种情况下甚至没有使用。 (2认同)