首页 文章

在.NET中表示不可变列表的最佳方法是什么?

提问于
浏览
5

我最近开始使用F#进行“实际工作”,并重新发现了不可变数据结构的美妙之处,例如F#中的歧视联盟和记录 . 我还发现它们很容易从C#中使用,特别是因为它们不需要对F#运行时有任何直接依赖 . 但是,在表示这些结构中的列表时,我还没有找到理想的解决方案 .

我的第一次尝试是将列表键入为seq <'a>(在C#世界中为IEnumerable),它提供了一个很好的通用集合接口,而不像ICollection <>及其朋友那样导出任何改变集合的方法 . 但是,由于我无法控制受歧视的联合或记录的构造函数,因此这些类型的实例的创建者可以提供可能在使用时更改或抛出的IEnumerable <>实现(例如LINQ表达式) . IEnumerable <>因此不会给编译器提供任何帮助,证明该值是不可变的,因此线程安全 .

我目前的策略是使用F#list类型,它确保了一个不可变的集合,但是在F#运行时添加了一个依赖项,当从非F#项目中使用它时看起来有些偏差 . 但它确实允许IEnumerable <>没有的F#模式匹配 . 它也没有在列表的实际表示中给出任何选择,并且在某些情况下(例如原始值的大列表),F#列表表示并不真正适合 .

我真正希望看到的是.NET中的不可变数组类型,表示与普通数组一样紧凑,但编译器保证不会发生变异 . 我会欢迎const在C中,尽管它可能不太可能发生 . 与此同时,我还有其他选择吗?

4 回答

  • 7

    如果你想要的是一个不可变的数组实现,那么你可以使用类似下面的内容

    public sealed class ImmutableArray<T> : IEnumerable<T>{
      private readonly T[] m_array;
      public T this[int index] {
        get { return m_array[index]; }
      }
      public int Length {
        get { return m_array.Length; }
      }
      public ImmutableArray(IEnumerable<T> enumerable) {
        m_array = enumerable.ToArray();
      }
      // IEnumerable<T> implementation ommitted
    }
    
  • 1

    将您的普通数组包装在ReadOnlyCollection<T>实例中:

    var readOnlyData = new ReadOnlyCollection<TheType>(theRealCollection);
    

    (注意,这不会复制底层集合,但会保留一个引用,并且会修改 IList<T> 等的成员以引发异常 . )

  • 1

    我建议在immutability上查看Eric Lippert's系列,这是一个非常有用的读物 . 关于immutable queue的第4部分将是一个很好的起点 .

  • 2

    Microsoft发布了Immutable collections nugget包的稳定版本 . 它还没有ImmutableArray . 但是这些不可变数据结构应该非常有用 .

    • ImmutableList

    • ImmutableDictionary

    • ImmutableSortedDictionary

    • ImmutableHashSet

    • ImmutableSortedSet

    • ImmutableStack

    • ImmutableQueue

    http://blogs.msdn.com/b/dotnet/archive/2013/09/25/immutable-collections-ready-for-prime-time.aspx

相关问题