随着新C# 8 中的只读实例成员功能 https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/readonly-instance-members,我尽量减少不必要的复制struct
我的代码中的实例。
我确实有一些foreach
结构数组上的迭代,并根据这个答案 https://stackoverflow.com/questions/14408124/does-foreach-copy-each-element-if-it-is-an-array-of-structs,这意味着在迭代数组时会复制每个元素。
我想我现在可以简单地修改我的代码以防止复制,如下所示:
// 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
实例本身?
foreach
基于目标类型的定义而不是一些内部黑盒工作。我们可以利用它来创建 by-ref 枚举支持:
//using System;
public readonly struct ArrayEnumerableByRef<T>
{
private readonly T[] _target;
public ArrayEnumerableByRef(T[] target) => _target = target;
public Enumerator GetEnumerator() => new Enumerator(_target);
public struct Enumerator
{
private readonly T[] _target;
private int _index;
public Enumerator(T[] target)
{
_target = target;
_index = -1;
}
public readonly ref T Current
{
get
{
if (_target is null || _index < 0 || _index > _target.Length)
{
throw new InvalidOperationException();
}
return ref _target[_index];
}
}
public bool MoveNext() => ++_index < _target.Length;
public void Reset() => _index = -1;
}
}
public static class ArrayExtensions
{
public static ArrayEnumerableByRef<T> ToEnumerableByRef<T>(this T[] array) => new ArrayEnumerableByRef<T>(array);
}
然后我们可以枚举一个数组foreach
通过引用循环:
static void Main()
{
var colors = new Color[128];
foreach (ref readonly var color in colors.ToEnumerableByRef())
{
Debug.WriteLine($"Color is {color.R} {color.G} {color.B} {color.A}.");
}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)