我可以在不复制 C# 8 中的元素的情况下对结构数组进行 foreach 吗? [英] Can I foreach over an array of structs without copying the elements in C# 8?
问题描述
使用新的 C# 8 中的只读实例成员功能,我尝试减少代码中不必要的结构实例复制.
With the new readonly instance member features in C# 8, I try to minify unnecessary copying of struct instances in my code.
我确实对结构数组进行了一些 foreach
迭代,并且根据 这个答案,这意味着迭代数组时每个元素都被复制.
I do have some foreach
iterations over arrays of structs, and according to this answer, it means that every element is copied when iterating over the array.
我想我现在可以简单地修改我的代码以防止复制,如下所示:
I thought I can simply modify my code now to prevent the copying, like so:
// Example struct, real structs may be even bigger than 32 bytes.
struct Color
{
public int R;
public int G;
public int B;
public int A;
}
class Program
{
static void Main()
{
Color[] colors = new Color[128];
foreach (ref readonly Color color in ref colors) // note 'ref readonly' placed here
Debug.WriteLine($"Color is {color.R} {color.G} {color.B} {color.A}.");
}
}
这很遗憾没有编译
CS1510 A ref or out value must be an assignable variable
但是,使用这样的索引器可以编译:
However, using an indexer like this compiles:
static void Main()
{
Color[] colors = new Color[128];
for (int i = 0; i < colors.Length; i++)
{
ref readonly Color color = ref colors[i];
Debug.WriteLine($"Color is {color.R} {color.G} {color.B} {color.A}.");
}
}
我在 foreach
替代方案中的语法是错误的,还是在 C# 8 中根本不可能(可能是因为枚举是如何在内部实现的)?还是 C# 8 现在应用了一些智能并且不再自己复制 Color
实例?
Is my syntax in the foreach
alternative wrong, or is this simply not possible in C# 8 (possibly because of how the enumeration is implemented internally)?
Or is C# 8 applying some intelligence nowadays and does no longer copy the Color
instances by itself?
推荐答案
受到 Alsein 回答的启发,我意识到我可以简单地使用 AsSpan()<检索数组的
Span
/code> 扩展方法(在 System
命名空间中可用),并使用 ref 枚举它的 span 能力:
Inspried by Alsein's answer, I realized that I can simply retrieve a Span
of an array with the AsSpan()
extension method (available in the System
namespace), and use the span capability of ref-enumerating it:
static void Main()
{
Color[] colors = new Color[128];
foreach (ref readonly Color color in colors.AsSpan())
Debug.WriteLine($"Color is {color.R} {color.G} {color.B} {color.A}.");
}
请记住,这仅适用于数组,而不适用于 List
实例,我还没有找到用于引用枚举结构列表的简单解决方案.
Keep in mind that this only works for arrays, not List<T>
instances, I did not find a simple solution for ref-enumerating lists of structs yet.
我担心性能问题,所以我测量了所花的时间 迭代了 10 和 1000 Color
实例如下:
I was worried about performance, so I measured the time it takes iterating over 10 and 1000 Color
instances in the following ways:
for
带复制for
withref readonly
for
复制和缓存数组长度for
withref readonly
并缓存数组长度foreach
带复制foreach
withref readonly
和AsSpan()
for
with copyingfor
withref readonly
for
with copying and caching the array lengthfor
withref readonly
and caching the array lengthforeach
with copyingforeach
withref readonly
andAsSpan()
ref foreach
和 foreach
似乎表现最好(即使在更长的 10000 个实例运行时):
ref foreach
and foreach
seems to perform the best (even at a longer 10000 instance run):
| Method | ColorCount | Mean | Error | StdDev | Rank |
|------------------ |----------- |------------:|-----------:|-----------:|-----:|
| For | 10 | 76.76 ns | 0.3310 ns | 0.3096 ns | 4 |
| ForRef | 10 | 77.31 ns | 0.4397 ns | 0.3898 ns | 4 |
| ForCacheLength | 10 | 69.39 ns | 0.1923 ns | 0.1605 ns | 3 |
| ForCacheLengthRef | 10 | 69.46 ns | 0.4859 ns | 0.4545 ns | 3 |
| ForEach | 10 | 68.28 ns | 0.7367 ns | 0.6152 ns | 2 |
| ForEachRef | 10 | 64.76 ns | 0.6355 ns | 0.5944 ns | 1 |
| For | 1000 | 6,912.80 ns | 49.9517 ns | 44.2808 ns | 7 |
| ForRef | 1000 | 6,882.85 ns | 44.9467 ns | 39.8441 ns | 7 |
| ForCacheLength | 1000 | 6,874.55 ns | 59.6360 ns | 55.7835 ns | 7 |
| ForCacheLengthRef | 1000 | 6,871.79 ns | 42.3081 ns | 39.5750 ns | 7 |
| ForEach | 1000 | 6,701.68 ns | 31.3103 ns | 27.7558 ns | 6 |
| ForEachRef | 1000 | 6,341.90 ns | 80.8536 ns | 75.6305 ns | 5 |
这篇关于我可以在不复制 C# 8 中的元素的情况下对结构数组进行 foreach 吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!