如何不复制原数组截取子数组?C#索引器实现疑问
避免数组复制,直接访问原数组子区间的解决方案
嘿,我懂你不想复制数组的需求——毕竟额外的内存开销和复制操作完全没必要!你的核心问题在于构造函数里用了ToList().GetRange(start, length).ToArray(),这会直接创建原数组的副本。咱们可以换个思路,保存原数组的引用,同时记录子数组的起始位置和长度,然后通过索引器做偏移来直接访问原数组的对应元素,完全不用复制。
修改后的代码
public class Indexer { // 保存原数组的引用,不做复制 private readonly double[] _originalArray; // 子数组在原数组中的起始索引 private readonly int _startIndex; // 子数组的长度 private readonly int _length; public double this[int index] { get { // 检查索引是否在子数组的合法范围内 if (index < 0 || index >= _length) throw new IndexOutOfRangeException("索引超出子数组范围"); // 直接访问原数组的对应位置(起始索引 + 当前索引) return _originalArray[_startIndex + index]; } set { if (index < 0 || index >= _length) throw new IndexOutOfRangeException("索引超出子数组范围"); _originalArray[_startIndex + index] = value; } } public int Length => _length; public Indexer(double[] array, int start, int length) { // 增强参数合法性校验 if (array == null) throw new ArgumentNullException(nameof(array)); if (start < 0 || length < 0 || start + length > array.Length) throw new ArgumentException("起始位置或长度参数不合法"); // 仅保存原数组引用和参数,不复制数组 _originalArray = array; _startIndex = start; _length = length; } }
关键改动说明
- 移除数组复制操作:构造函数不再创建新数组,只保存原数组的引用、起始位置和子数组长度,几乎没有额外内存开销。
- 索引器偏移处理:在
get和set逻辑中,把用户传入的index转换成原数组的实际索引(_startIndex + index),直接操作原数组的对应元素。 - 强化边界检查:除了构造函数的参数校验,索引器内部也增加了范围检查,避免用户访问超出子数组的位置。
注意事项
这种方案的小权衡是:通过Indexer修改元素会直接影响原数组,因为咱们操作的是原数组的引用。如果你的需求是让子数组和原数组完全隔离(修改子数组不影响原数组),那复制是不可避免的;但如果只是需要一个“视图”式的访问入口,这个方案就完美匹配你的需求。
内容的提问来源于stack exchange,提问作者Mak
相关产品推荐
相关产品推荐

