为什么ImmutableArray.Create复制一个现有的不可变数组?

时间:2017-10-19 13:50:20

标签: c# .net

我正在尝试在方法中创建一个现有ImmutableArray<T>的片段,并认为我可以像这样使用构造方法Create<T>(ImmutableArray<T> a, int offset, int count)

 var arr = ImmutableArray.Create('A', 'B', 'C', 'D');
 var bc ImmutableArray.Create(arr, 1, 2); 

我希望我的两个ImmutableArrays可以在这里共享底层数组。但 当仔细检查这个时,我看到实现没有:

2017年3月18日来自corefx/../ImmutableArray.cs at github的15757a8

    /// <summary>
    /// Initializes a new instance of the <see cref="ImmutableArray{T}"/> struct.
    /// </summary>
    /// <param name="items">The array to initialize the array with.
    /// The selected array segment may be copied into a new array.</param>
    /// <param name="start">The index of the first element in the source array to include in the resulting array.</param>
    /// <param name="length">The number of elements from the source array to include in the resulting array.</param>
    /// <remarks>
    /// This overload allows helper methods or custom builder classes to efficiently avoid paying a redundant
    /// tax for copying an array when the new array is a segment of an existing array.
    /// </remarks>
    [Pure]
    public static ImmutableArray<T> Create<T>(ImmutableArray<T> items, int start, int length)
    {
        Requires.Range(start >= 0 && start <= items.Length, nameof(start));
        Requires.Range(length >= 0 && start + length <= items.Length, nameof(length));

        if (length == 0)
        {
            return Create<T>();
        }

        if (start == 0 && length == items.Length)
        {
            return items;
        }

        var array = new T[length];
        Array.Copy(items.array, start, array, 0, length);
        return new ImmutableArray<T>(array);
    }

为什么必须在此处制作基础项目的副本? 并不是这种方法的文档误导/错误?它说

  

此重载允许辅助方法或自定义构建器类   有效地避免为复制数组时支付多余的税   new array是现有数组的一部分。

但是分段情况正好在它复制时,如果所需的片是空的或整个输入数组,它只会避免复制。

是否还有另一种方法可以实现我想要的东西,而不是实现某种ImmutableArraySpan

1 个答案:

答案 0 :(得分:2)

我将在评论的帮助下回答我自己的问题:

ImmutableArray不能代表底层数组的一个片段,因为它没有相应的字段 - 显然添加64/128位很少使用的范围字段会太浪费。

所以唯一可能的是拥有一个正确的Slice / Span结构,除了ArraySegment之外没有一个结构(不能使用ImmutableArray作为后备数据)。

编写一个实现IReadOnlyList<T>等的ImmutableArraySegment可能很容易,因此这可能是解决方案。

关于文档 - 它尽可能正确,它避免了它可以的所有副本(全部,没有)和其他副本。

新的Span和ReadonlySpan类型的API将附带低级代码(ref return / locals)的神奇语言和运行时功能。这些类型实际上已作为System.Memory nuget包的一部分提供,但在它们被集成之前,将无法使用它们来解决在ImmutableArray上切片ImmutableArray的问题,而ImmutableArray需要这个方法(在System.Collections.Immutable中,它不依赖于System.Memory类型)

public ReadonlySpan<T> Slice(int start, int count)

我猜/希望一旦这些类型到位就会出现这样的API。