【发布时间】:2020-01-23 22:48:40
【问题描述】:
使用新的readonly instance member features in C# 8,我尝试在我的代码中减少不必要的结构实例复制。
我确实对结构数组进行了一些foreach 迭代,根据this answer,这意味着在迭代数组时会复制每个元素。
我想我现在可以简单地修改我的代码来防止复制,就像这样:
// 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
但是,使用这样的索引器可以编译:
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 实例?
【问题讨论】:
-
这不会使您的问题无效,但是复制实例(只有 4 个字节)实际上比就地使用它(编译器必须担心别名)效率更高。
-
@BenVoigt 这是一个有效的评论,我应该补充一点,这只是愚蠢的示例代码,我的结构可能大于 4 个字节。 - 现在编辑为 32 字节大。
-
链接的提案是否以任何方式修改了
foreach的行为?我以为这只是关于readonlystructs 的成员 -
另外基于我(有限的)知识,实现你想要的方法是使用
ReadOnlySpan<Color> colors = new Color[128];(它允许你在foreach中使用ref readonly) -
这里要记住的一点是,foreach 不 与集合一起工作。它仅适用于枚举器。 Wich 将从任何现有集合中隐式创建。因此,您将在开始和每次迭代/调用 .next() 时获得所有枚举器开销。通常我只在人们遇到枚举数的“非可变”属性时才提到它。但是对于您的情况,这种性能差异可能很重要并影响更大的问题。