代码之家  ›  专栏  ›  技术社区  ›  JamesHoux

ArraySegment必须强制转换为IList,才能使用索引对其进行迭代。有没有办法隐藏不相关的IList方法?

  •  0
  • JamesHoux  · 技术社区  · 6 年前

    为了能够像数组一样直接处理ArraySegment,必须使用“as”将其强制转换为IList。这在这里被描述为正确的行为:

    use of ArraySegment class?

    dotNet ArraySegment Struct

    具体来说,微软的文档中说:

    如果要通过ArraySegment中的索引检索元素 使用IList.Item[Int32]属性修改它。以下 示例检索ArraySegment对象中 分隔字符串数组的一部分。

    令人困惑的是,IList有“Remove”和“RemoveAt”这样的方法。您可能会希望这些不适用于转换为列表的arraysegment。我对此进行了测试,实际上调用Remove会抛出一个运行时错误。但是编译器没有发现问题。

    我试图头脑风暴包装类或某种方法来隐藏列表方法,这些方法不应该在ArraySegment上调用为List。但我什么都想不出来。

    有人对如何解决这个问题有什么建议吗?

    编辑:已建议使用IReadOnlyList而不是IList。 IReadOnlyList使列表完全只读,防止修改存储在底层数组中的元素的值。我希望能够修改原始数组值。我只是不想写list.Remove()或list.Add(),因为这显然是错误的,编译器不应该允许这样做。

    对于任何可能建议Span作为替代方案的人:

    我知道Span,但Span目前在.netframework和Standard中有一些限制。具体来说,它只能用作局部变量,因此不能传递给其他方法。

    老实说,我真的认为微软的IEnumerable继承权还有一点不尽如人意——如果不提供添加/删除功能,我想不出任何方法来创建一个像List这样的可索引序列。ICollection不支持索引。如果有人对这个问题有意见,我洗耳恭听。

    2 回复  |  直到 6 年前
        1
  •  1
  •   Filip Milovanović    6 年前

    ArraySegment<T> 不暴露索引器,除非它被强制转换到 IList<T>

    IReadOnlyList<T> 接口;请注意,如果包含的对象是可变的,则不会阻止您更改它们本身:

    IReadOnlyList<T> 表示列表元素的数目和顺序为只读的列表。列表元素的内容不能保证是只读的。

    还有 ReadOnlyCollection<T> 包装类(添加 using System.Collections.ObjectModel; ). 也没有对索引设置虽然。

    IList<T> 在构造函数中,并实现 你自己的索引器 . 我也会实施 IEnumerable<T>

    // Add these...
    using System.Collections;
    using System.Collections.Generic;
    
    //...
    
    public class MyWrapper<T> : IEnumerable<T>
    {
      private IList<T> _internalList;
    
      public MyWrapper(IList<T> list)
      {
        _internalList = list;
      }
    
      public int Count => _internalList.Count;
    
      // the indexer
      public T this[int index]
      {
        get => _internalList[index];
        set => _internalList[index] = value;
      }
    
      public IEnumerator<T> GetEnumerator()
      {
        return _internalList.GetEnumerator();
      }
    
      IEnumerator IEnumerable.GetEnumerator() 
      {
        return this.GetEnumerator();
      }
    }
    

    然后将数组段传递给构造函数(不强制转换)。

    只要清楚它的意图是什么。

    另外,如果你不介意和一个 复制 仅限于由数组段定义的范围的数组,如果不考虑复制操作成本,则可以对该段调用ToArray或ToList扩展方法。但我怀疑您希望更新原始数组,而您只需要将一个“窗口”插入一个段。

        2
  •  0
  •   Fabio    6 年前

    你还可以用 ArraySegment ,这将阻止添加/删除项以及通过索引访问/更新项 .Array 财产

    var numbers = new[] { 1, 2, 3, 4 };
    var segment = new ArraySegment<int>(numbers);
    
    segment.Array[2] = 101;
    
    // segment contains now { 1, 2, 101, 4}
    

    public static void UpdateAt<T>(this ArraySegment<T> segment, int index, T value)
    {
        segment.Array[index] = value;
    }