C#索引器测试问题求助:数组值异常及跨实例赋值失效
解决C#索引器测试中的两个问题
我来帮你逐个拆解问题并给出彻底的解决方案:
问题1:实例化indexer0后,indexer1输出3、3而非预期的2、3
根源分析
你的Index类存在两个核心问题:
- 共享数组引用:所有
Index实例都直接使用传入的原始数组引用,没有独立副本,修改一个实例的数组会影响所有关联实例; - 构造函数逻辑错误:构造函数不仅没有实现数组切片的预期功能,反而直接修改了原始数组的元素。第一次实例化
indexer0时,已经把原始数组{1,2,3,4}修改为{2,3,3,4};第二次实例化indexer1时,又用这个被修改后的数组再次执行构造逻辑,最终把数组改成了{3,3,3,4},所以indexer1[0]和indexer1[1]都会输出3。
问题2:临时变量解决问题1后,indexer2的赋值无法同步到indexer3
根源分析
如果为了避免问题1给每个Index实例克隆一份独立数组,那么各个实例的数组完全隔离,修改一个实例的元素自然不会影响其他实例。但你的需求是让不同Index实例共享底层数据,所以克隆数组的思路不符合预期。
完整解决方案:将Index设计为原始数组的视图类
正确的思路是让Index类作为原始数组的切片视图:保存原始数组的引用,通过起始索引映射视图的索引到原始数组的对应位置,既不会修改原始数组的初始数据,又能实现不同视图间的数据同步。
修正后的Index类代码
class Index { // 保存原始数组的引用,实现多视图数据同步 private double[] _originalArray; // 当前视图在原始数组中的起始索引 private int _startIndex; // 视图的元素个数 public int Length { get; } // 索引器:将视图索引映射到原始数组的对应位置 public double this[int x] { get { // 添加边界检查,避免越界异常 if (x < 0 || x >= Length) throw new IndexOutOfRangeException("视图索引超出范围"); return _originalArray[_startIndex + x]; } set { if (x < 0 || x >= Length) throw new IndexOutOfRangeException("视图索引超出范围"); _originalArray[_startIndex + x] = value; } } // 构造函数:初始化视图的原始数组、起始和结束索引 public Index(double[] originalArray, int startIndex, int endIndex) { _originalArray = originalArray ?? throw new ArgumentNullException(nameof(originalArray), "原始数组不能为null"); if (startIndex < 0 || startIndex >= originalArray.Length) throw new ArgumentOutOfRangeException(nameof(startIndex), "起始索引超出原始数组范围"); if (endIndex < startIndex || endIndex >= originalArray.Length) throw new ArgumentOutOfRangeException(nameof(endIndex), "结束索引必须大于等于起始索引且不超出原始数组范围"); _startIndex = startIndex; // 计算视图的元素个数 Length = endIndex - startIndex + 1; } }
测试代码运行结果
使用修正后的Index类,你的测试代码会输出符合预期的结果:
static void Main(string[] args) { double[] array = { 1, 2, 3, 4 }; var indexer0 = new Index(array, 1, 2); Console.WriteLine(indexer0.Length); // 输出2 Console.WriteLine("Result = 2,3"); var indexer1 = new Index(array, 1, 2); Console.WriteLine(indexer1[0]); // 输出2 Console.WriteLine(indexer1[1]); // 输出3 → 问题1解决 Console.WriteLine("Copy 25"); var indexer2 = new Index(array, 1, 2); var indexer3 = new Index(array, 0, 2); indexer2[0] = 25; // 修改原始数组的索引1位置的值 Console.WriteLine(indexer3[1]); // 输出25 → 问题2解决 Console.WriteLine("Array"); foreach (var item in array) { Console.WriteLine(item); // 输出1、25、3、4 } Console.ReadKey(); }
方案优势
- 不破坏原始数组初始数据:构造函数仅初始化视图参数,不修改原始数组;
- 多视图数据同步:所有
Index实例共享原始数组引用,修改一个视图的元素会同步到其他映射到同一位置的视图; - 健壮性提升:添加了参数合法性检查和边界判断,避免越界异常。
内容的提问来源于stack exchange,提问作者Tibomso
相关产品推荐
相关产品推荐

