INotifyCollectionChanged

INotifyCollectionChanged

我遇到过几次这样的情况,我想通过INotifyCollectionChanged接口观察一个集合,但也希望能够访问集合的任何元素。INotifyCollectionChanged接口不提供任何访问元素的方法,除了那些与更改事件相关的元素(通常包含在NotifyCollectionChangedEventArgs中)。
现在我的想法是:
我们知道无论什么工具INotifyCollectionChanged都是一个集合(d'uh)。
由于NotifyPropertyChangedEventArgs包含指示更改位置的索引,我们知道可以通过索引访问元素。
可以通过索引访问的集合是一个列表,因此要求任何INotifyCollectionChanged实现者也实现IList似乎是有意义的。这可以通过让INotifyCollectionChanged扩展IList来轻松完成。
有人知道为什么不是这样吗?

最佳答案

我认为您需要查找SOLID软件设计原则,特别是Liskov Substitution Principle
您问为什么INotifyCollectionChanged接口不同时扩展IList接口。让我用利斯科夫补贴原则回答一个反问题:
我能说INotifyCollectionChangedIList吗?
不,我不这么认为,原因如下:
INotifyCollectionChanged表示实现此接口的类需要在其基础集合发生更改时通知其用户,我们不知道该基础集合是IList还是ICollection,甚至是IEnumerable。它是一个IList接口的不同概念,它只是一个ICollection带有一个暴露的indexer
您提到的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);
        }
    }
}

希望这能回答你的问题。

10-06 13:40