持久集合和标准集合接口

Sea*_*n U 2 .net c# collections

我正在实现一个持久集合 - 为了论证,让我们说它是一个单链表,是函数式语言中常见的样式.

class MyList<T>
{
    public T Head { get; }
    public MyList<T> Tail { get; }

    // other various stuff
    // . . .
}
Run Code Online (Sandbox Code Playgroud)

拥有这个类实现似乎很自然ICollection<T>,因为它可以实现所期望的所有正常行为ICollection<T>,至少在广泛的行程中.但是这个阶级的行为和行为之间存在很多不匹配ICollection<T>.例如,Add()方法的签名

void Add(T item);  // ICollection<T> version
Run Code Online (Sandbox Code Playgroud)

假设添加将作为改变集合的副作用执行.但这是一个持久的数据结构,因此Add()应该创建一个新的列表并返回它.

MyList<T> Add(T item);  // what we really want
Run Code Online (Sandbox Code Playgroud)

解决此问题的最佳方法似乎是创建我们想要的版本,并生成接口中定义的版本的非功能性显式实现.

void ICollection<T>.Add(T item) { throw new NotSupportedException(); }
public MyList<T> Add(T item) { return new MyList<T>(item, this); }
Run Code Online (Sandbox Code Playgroud)

但我对这个选项有一些担忧:

  1. 这会让用户感到困惑吗?我设想有人正在使用这个类的场景,并发现在它上面调用Add()有时会引发异常,有时会运行但不会像ICollection通常预期的那样修改列表,具体取决于相关的类型信息使用参考?

  2. 继(1)之后,ICollection<T>s 的实现IsReadOnly应该可以归结为真.但这似乎与Add()与类实例一起使用的其他点隐含的内容相冲突.

  3. 是否(2)通过再次遵循显式实现模式以非混淆的方式解决,新版本返回false并返回显式实现true?或者这是否只是使它甚至错误地暗示更糟MyList<T>Add()方法是赋值函数?

  4. 或者最好忘记尝试使用现有的界面,只是创建一个单独的IPersistentCollection<T>界面来IEnumerable<T>代替?

编辑我更改了类的名称,并切换到使用ICollection.我想专注于对象的行为以及它与界面的关系.我只是将cons清单作为一个简单的例子.我很欣赏这样的建议:如果我要实现一个缺点列表,我应该尝试提出一个较少混淆的名称,并且应该避免实现IList,因为该接口用于快速随机访问,但它们有些切线问题.

我打算询问的是其他人对于烘焙到框架中的只读(或不可变)集合的语义与实现与界面描述的内容等效行为的持久集合之间的紧张关系的看法,仅在功能上相反而不是通过突变副作用.

Eri*_*ert 5

实施IList<T>会令人困惑吗?

是.虽然有些情况下IList<T>会抛出一个实现- 例如,当你试图调整列表的大小但是它的实现是一个数组时 - 我会发现让一个IList<T>可以在任何情况下都没有变异并且没有快速随机访问.

我应该实施新的IPersistentList<T>吗?

这取决于是否有人会使用它.您班级的消费者是否可能有六种不同的实施IPL<T>方式可供选择?我认为制作一个只由一个类实现的接口没有意义; 只需使用该课程.

如果其ItemsSource是一个IList<T>而不是一个,那么WPF的ItemsControl可以获得更好的性能IEnumerable<T>.

但是你的持久链表无论如何都不会有快速的随机访问.