为什么 INotifyCollectionChanged 不扩展 IList?

Ste*_*ven 5 .net c# collections

我曾多次遇到过这样的情况:我想通过INotifyCollectionChanged界面观察一个集合,但又希望能够访问该集合的任何元素。该INotifyCollectionChanged接口不提供任何访问元素的方法,除了那些涉及更改事件的元素(通常包含在 中NotifyCollectionChangedEventArgs)。

现在这是我的想法:

  1. 我们知道无论实现什么INotifyCollectionChanged都是一个集合(d'uh)。
  2. 由于NotifyPropertyChangedEventArgs包含索引指示更改的位置,我们知道元素可以通过索引访问。

可以通过索引访问的集合是一个列表,因此要求任何INotifyCollectionChanged实现者也实现IList. 这可以通过让INotifyCollectionChanged扩展轻松完成IList

有谁知道为什么不是这样?

rex*_*ghk 3

我认为您需要查找SOLID软件设计原则,特别是里氏替换原则

你问为什么INotifyCollectionChanged接口不也扩展IList接口。让我用里氏替换原理回答一个反问题:

我可以说 anINotifyCollectionChanged是 anIList吗?

不,我不这么认为,原因如下:

  1. INotifyCollectionChanged传达的含义是,实现此接口的类需要在其底层集合发生更改时通知其用户,无论该底层集合是 or IListICollection甚至是IEnumerable,我们都不知道。这是接口的不同概念IList,它只是一个ICollection带有公开索引器的接口

  2. 您提到的NotifyPropertyChangedEventArgs(我相信您的意思是NotifyCollectionChangedEventArgs)公开索引的属性,指示集合在什么位置发生更改。然而,这并不意味着这些属性一定会通过 的索引器公开项目IList。它可以是任意数字、魔法常数等等。由实现类决定如何公开索引。

为了演示这一点,请看一下我的自定义类,它实现了INotifyCollectionChanged

public class MyCustomCollection : INotifyCollectionChanged
{
    // This is what I meant by the "underlying collection", can be replaced with
    // ICollection<int> and it will still work, or even IEnumerable<int> but with some
    // code change to store the elements in an array
    private readonly IList<int> _ints;

    public MyCustomCollection()
    {
        _ints = new List<int>();
    }

    public event NotifyCollectionChangedEventHandler CollectionChanged;

    public void AddInt(int i)
    {
        _ints.Add(i);
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(
            NotifyCollectionChangedAction.Move, 
            (IList)_ints, 
            _ints.Count,
            _ints.Count - 1));
    }

    protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        var handler = CollectionChanged;
        if (handler != null)
        {
            handler(this, e);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

希望这能回答您的问题。