我遇到过几次这种情况,我想通过 INotifyCollectionChanged
接口(interface)观察一个集合,但也希望能够访问该集合的任何元素。 INotifyCollectionChanged
接口(interface)不提供任何方式来访问元素,除了更改事件中涉及的元素(通常包含在 NotifyCollectionChangedEventArgs
中)。
这是我的想法:
- 我们知道任何实现
INotifyCollectionChanged
的东西都是一个集合 (d'uh)。 - 由于
NotifyPropertyChangedEventArgs
包含指示更改位置的索引,我们知道可以通过索引访问元素。
可以通过索引访问的集合是一个列表,因此要求任何 INotifyCollectionChanged
实现者也实现 IList
似乎是有意义的。这可以通过让 INotifyCollectionChanged
扩展 IList
轻松完成。
有谁知道为什么不是这样?
最佳答案
我认为您需要查找 SOLID软件设计原则,特别是Liskov Substitution Principle .
您问过为什么 INotifyCollectionChanged
接口(interface)不也扩展 IList
接口(interface)。让我使用 Liskov 替换原则用一个反问题来回答它:
Can I say an
INotifyCollectionChanged
is anIList
?
不,我不这么认为,原因如下:
INotifyCollectionChanged
传达的意思是实现此接口(interface)的类需要在其基础集合发生更改时通知其用户,无论该基础集合是IList
还是ICollection
,甚至IEnumerable
,我们不知道。它是IList
接口(interface)的不同概念,它只是一个带有公开 indexer 的ICollection
您提到了
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);
}
}
}
希望这能回答您的问题。
关于c# - 为什么 INotifyCollectionChanged 不扩展 IList?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27939451/