为什么我无法更改从另一个类获得的数组元素?

时间:2018-01-16 14:43:09

标签: c# arrays

我创建了一个在数组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]);
        }


}

2 个答案:

答案 0 :(得分:1)

您面临的问题是,最后一次测试要求您的包装器提供对底层数组的访问。换句话说,无论创建了多少个索引器,它们 all 都指向相同的底层数组

此处this.array = array.Skip(start).Take(length).ToArray();行违反了此要求,创建了Array类的新实例。因此,第一个索引器改变的值不会反映在第二个索引器中 - 它们指向不同的内存区域。

要解决此问题,不要使用LINQ创建新数组,只需存储通过构造函数传递的原始数组。您的this[]索引器属性必须负责通过startendstart添加到index并手动检查边界外情况。

答案 1 :(得分:0)

所有linq扩展方法都会创建新枚举,它们不会改变或返回调用该方法的方法:

var newArray = array.Skip(...).ToArray();
ReferenceEquals(array, newArray); //returns false

您在newArray元素中所做的任何更改都不会改变array中的任何内容。

您的SetCorrectly测试正在比较indexerarray,但它始终会失败。您的其他测试也会失败,因为indexer1indexer2引用了两个不同的数组。

然而因为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!