我创建了一个在数组double []
上实现包装器的类,但我无法更改接收数组的元素。这些是测试
public void SetCorrectly ()
public void IndexerDoesNotCopyArray ()
问题听起来像这样。编写类Indexer
,它作为数组double []
的包装器创建,并打开对某个长度的子数组的访问,从一些元素开始。您的决定必须通过项目中包含的测试。与往常一样,您必须在Indexer中监控数据的完整性。
这是我的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Incapsulation.Weights
{
public class Indexer
{
double[] array;
int start;
int length;
public int Length
{
get { return length; }
}
public Indexer(double[] array, int start, int length)
{
if (start < 0 || start >= array.Length) throw new ArgumentException();
this.start = start;
if (length < start || length > array.Length) throw new ArgumentException();
this.length = length;
this.array = array.Skip(start).Take(length).ToArray();
}
public double this[int index]
{
get { return array[index]; }
set { array[index] = value; }
}
}
}
这是测试
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Incapsulation.Weights
{
[TestFixture]
public class Indexer_should
{
double[] array = new double[] { 1, 2, 3, 4 };
[Test]
public void HaveCorrectLength()
{
var indexer = new Indexer(array, 1, 2);
Assert.AreEqual(2, indexer.Length);
}
[Test]
public void GetCorrectly()
{
var indexer = new Indexer(array, 1, 2);
Assert.AreEqual(2, indexer[0]);
Assert.AreEqual(3, indexer[1]);
}
[Test]
public void SetCorrectly()
{
var indexer = new Indexer(array, 1, 2);
indexer[0] = 10;
Assert.AreEqual(10, array[1]);
}
[Test]
public void IndexerDoesNotCopyArray()
{
var indexer1 = new Indexer(array, 1, 2);
var indexer2 = new Indexer(array, 0, 2);
indexer1[0] = 100500;
Assert.AreEqual(100500, indexer2[1]);
}
}
答案 0 :(得分:1)
您面临的问题是,最后一次测试要求您的包装器提供对底层数组的访问。换句话说,无论创建了多少个索引器,它们 all 都指向相同的底层数组。
此处this.array = array.Skip(start).Take(length).ToArray();
行违反了此要求,创建了Array
类的新实例。因此,第一个索引器改变的值不会反映在第二个索引器中 - 它们指向不同的内存区域。
要解决此问题,不要使用LINQ创建新数组,只需存储通过构造函数传递的原始数组。您的this[]
索引器属性必须负责通过start
和end
将start
添加到index
并手动检查边界外情况。
答案 1 :(得分:0)
所有linq扩展方法都会创建新枚举,它们不会改变或返回调用该方法的方法:
var newArray = array.Skip(...).ToArray();
ReferenceEquals(array, newArray); //returns false
您在newArray
元素中所做的任何更改都不会改变array
中的任何内容。
您的SetCorrectly
测试正在比较indexer
和array
,但它始终会失败。您的其他测试也会失败,因为indexer1
和indexer2
引用了两个不同的数组。
然而因为Linq很懒,所以Linq扩展方法的结果可以看出修改array
取决于你实现枚举的时间;这可能发生:
var skippedA = array.Skip(1); //deferred execution
array[1] = //some different value...,
var newArray =skipped.ToArray(); //Skip is materialized here!
newArray[1] == array[1]; //true!