【问题标题】:How to get a reference on a sub array如何获取子数组的引用
【发布时间】:2018-01-23 09:56:36
【问题描述】:

我正在尝试从现有数组中获取子数组的引用。 当我对子数组进行修改时,我希望能够更新原始数组。 示例:

byte[] array = {0 , 1, 2, 3, 4};
byte[] subarray = array.Skip(2).Take(3).ToArray();
subarray[0] = 8;
Console.WriteLine("array[2] = " + array[2]);

我想看看:

数组[2] = 8

但是,我得到了:

数组[2] = 2

我读过这个solution,但它不够好,因为我不想提供修改不在范围内的数组值的选项,如下所示:

ArraySegment<byte> segment = new ArraySegment<byte>(array, 2, 3);
byte[] segmentByte = segment.ToArray();

我可以通过segmentByte修改所有原始数组。这是我要防止的。

【问题讨论】:

  • 如何使用您提供的链接中指定的 ArraySegment 作为答案?
  • @ArraySegment: "多个 ArraySegment 实例可以引用同一个原始数组并且可以重叠。", "对 Array 属性返回的数组所做的更改是对原始数组进行的。" > 听起来正是您想要的,您所说的“修改选项......不在范围内”是什么意思?
  • 当您执行ToArray() 时,它会创建一个与主数组没有任何关系的全新对象。
  • 我添加了为什么我不想使用 ArraySegment 的解释
  • 你的技术栈有多新 - 引入了 C# 7.2 Span&lt;T&gt;...

标签: c# .net arrays


【解决方案1】:

您可以编写简单的 ArrayArraySegment&lt;of T&gt; 包装器,只提供一组必需的操作:

struct StrictRangeArraySegment<T>
{
    ArraySegment<T> _segment;
    public StrictRangeArraySegment(T[] array) 
        : this(array, 0, array.Length)
    {
    }
    public StrictRangeArraySegment(T[] array, int offset, int count)
        : this(new ArraySegment<T>(array, offset, count))
    {
    }
    public StrictRangeArraySegment(ArraySegment<T> segment)
    {
        _segment = segment;
    }

    public int Count
    {
        get
        {
            return _segment.Count;
        }
    }

    public T this[int index]
    {
        get
        {
            if (index < 0 || index >= _segment.Count)
                throw new ArgumentOutOfRangeException(nameof(index));
            return _segment.Array[_segment.Offset + index];
        }
        set
        {
            if (index < 0 || index >= _segment.Count)
                throw new ArgumentOutOfRangeException(nameof(index));
            _segment.Array[_segment.Offset + index] = value;
        }
    }
}

参考见ArraySegment&lt;Of T&gt; source code

【讨论】:

    【解决方案2】:

    如果您仔细查看ToList 方法,您会发现它完全生成了一个完全不引用旧列表的新列表。因此,您所做的更改仅反映到subarray

    唯一的解决方案是使用您不想使用的ArraySegment

    public List<TResult> ToList()
    {
        var list = new List<TResult>();
    
        foreach (TSource item in _source)
        {
            list.Add(_selector(item));
        }
        return list;
    }
    

    【讨论】:

    • 他们可以在数组中放置(引用)对象,并修改这些对象中的属性。这将在参考副本中保留下来。但在存储和性能方面,它的成本要高得多。
    【解决方案3】:

    一种选择是创建一种类型,将整数装箱为对象的属性。那么更新属性就会得到想要的结果:

    public class Box<T>
    {
        public T Value {get;set;}
        public Box<T>(T item) {Value = item;}
    }
    
    Box<byte>[] array = {new Box<byte>(0), new Box<byte>(1), new Box<byte>(2), new Box<byte>(3), new Box<byte>(4)};
    Box<byte>[] subarray = array.Skip(2).Take(3).ToArray();
    subarray[0].Value = 8;
    Console.WriteLine("array[2] = " + array[2].Value);
    //you'll see "8" instead of "2" now
    

    您可能还想查看Span&lt;T&gt;。它还没有完全发布,但它可能会在这里实现你的目标。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-11-16
      • 1970-01-01
      • 1970-01-01
      • 2017-09-06
      • 2022-01-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多