我在我的WPF应用程序中的许多地方使用ObservableCollection来处理非常大的数组。这造成了一个问题,因为ObservableCollection并没有像List那样对容量进行论证。这是一个重要的优化,可以锁定我的内存使用情况,并确保这些集合不会比所需的大得多。
因此,我实现了以下类:
public class ObservableList<T> : IList<T>, IList, INotifyCollectionChanged
{
public event NotifyCollectionChangedEventHandler CollectionChanged;
#region Properties
private List<T> _List
{
get;
set;
}
public T this[int index]
{
get
{
return _List[index];
}
set
{
if (index < 0 || index >= Count)
throw new IndexOutOfRangeException("The specified index is out of range.");
var oldItem = _List[index];
_List[index] = value;
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, value, oldItem, index));
}
}
public int Count
{
get
{
return _List.Count;
}
}
public bool IsReadOnly
{
get
{
return ((IList<T>)_List).IsReadOnly;
}
}
bool IList.IsFixedSize
{
get
{
return ((IList)_List).IsFixedSize;
}
}
object IList.this[int index]
{
get
{
return ((IList)_List)[index];
}
set
{
if (index < 0 || index >= Count)
throw new IndexOutOfRangeException("The specified index is out of range.");
var oldItem = ((IList)_List)[index];
((IList)_List)[index] = value;
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, value, oldItem, index));
}
}
public bool IsSynchronized
{
get
{
return ((IList)_List).IsSynchronized;
}
}
public object SyncRoot
{
get
{
return ((IList)_List).SyncRoot;
}
}
#endregion
#region Methods
private void OnCollectionChanged(NotifyCollectionChangedEventArgs args)
{
if (CollectionChanged != null)
CollectionChanged(this, args);
}
public void AddRange(IEnumerable<T> collection)
{
_List.AddRange(collection);
var iList = collection as IList;
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
public int IndexOf(T item)
{
return _List.IndexOf(item);
}
public void Insert(int index, T item)
{
_List.Insert(index, item);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index));
}
public void RemoveAt(int index)
{
if (index < 0 || index >= Count)
throw new IndexOutOfRangeException("The specified index is out of range.");
var oldItem = _List[index];
_List.RemoveAt(index);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, oldItem, index));
}
public void Add(T item)
{
_List.Add(item);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));
}
public void Clear()
{
_List.Clear();
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
public bool Contains(T item)
{
return _List.Contains(item);
}
public void CopyTo(T[] array, int arrayIndex)
{
_List.CopyTo(array, arrayIndex);
}
public bool Remove(T item)
{
var result = _List.Remove(item);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item));
return result;
}
public IEnumerator<T> GetEnumerator()
{
return _List.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
int IList.Add(object value)
{
var result = ((IList)_List).Add(value);
;
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, value));
return result;
}
bool IList.Contains(object value)
{
return ((IList)_List).Contains(value);
}
int IList.IndexOf(object value)
{
return ((IList)_List).IndexOf(value);
}
void IList.Insert(int index, object value)
{
((IList)_List).Insert(index, value);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, value, index));
}
void IList.Remove(object value)
{
((IList)_List).Remove(value);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, value));
}
public void CopyTo(Array array, int index)
{
((IList)_List).CopyTo(array, index);
}
#endregion
#region Initialization
public ObservableList()
{
_List = new List<T>();
}
public ObservableList(int capacity)
{
_List = new List<T>(capacity);
}
public ObservableList(IEnumerable<T> collection)
{
_List = new List<T>(collection);
}
#endregion
}它似乎工作得很好,但是我注意到自从切换到这个实现之后,处理时间增加了。接口实现正确了吗?
发布于 2013-10-16 23:47:55
IList的实现是不一致的:您已经显式地实现了IsFixedSize,而IsSynchronized和SyncRoot没有实现,但是它们都是IList接口的三个部分。您可能应该完全显式地实现IList。((IList)_List)[index]。只有在必要时才进行强制转换(例如,当将基础List<T>转换为IList时,因为需要访问某些显式实现的接口方法/属性)。if之后但在实际调用之前取消订阅,您将得到一个NullReferenceException。实现此功能的惯用方法是:私有OnCollectionChanged(NotifyCollectionChangedEventArgs args) { var处理程序= CollectionChanged;if (处理程序!=空)处理程序(此,args);}注意到这仍然会在订阅方造成问题,因为它可能在取消订阅后才被调用,但应该在那里处理。CollectionChanged事件,那么在引发事件的每个操作中都将同步调用已注册的事件处理程序。这并不是完全令人惊讶的是,这会稍微减慢操作的速度。然而,在未观察到的情况下,情况不应该有太大的不同。https://codereview.stackexchange.com/questions/30708
复制相似问题