感谢您的建议,但我tryed一个KeyedCollection的一些实现,并决定将所有收藏/ Dictionarys切换到我的一个KeyedCollection的自定义实现。性能和字典一样快,但没有使用KVP。下面是我用一些替换方法观察到的实现,它运行速度非常快。
public class ObservableKeyedCollection<TKey, TItem> : KeyedCollection<TKey, TItem>, INotifyCollectionChanged
{
private const string CountString = "Count";
private readonly Func<TItem, TKey> _getKeyForItemDelegate;
// Constructor now requires a delegate to get the key from the item
public ObservableKeyedCollection(Func<TItem, TKey> getKeyForItemDelegate) : base()
{
if (getKeyForItemDelegate == null)
throw new ArgumentNullException("Delegate passed can't be null!");
_getKeyForItemDelegate = getKeyForItemDelegate;
}
protected override TKey GetKeyForItem(TItem item)
{
return _getKeyForItemDelegate(item);
}
/// <summary>
/// Method to add a new object to the collection, or to replace an existing one if there is
/// already an object with the same key in the collection.
/// </summary>
public void AddOrReplace(TItem newObject)
{
int i = GetItemIndex(newObject);
if (i != -1)
SetItem(i, newObject);
else
Add(newObject);
}
/// <summary>
/// Method to replace an existing object in the collection, i.e., an object with the same key.
/// An exception is thrown if there is no existing object with the same key.
/// </summary>
public void Replace(TItem newObject)
{
int i = GetItemIndex(newObject);
if (i != -1)
SetItem(i, newObject);
else
throw new Exception("Object to be replaced not found in collection.");
}
/// <summary>
/// Method to get the index into the List{} in the base collection for an item that may or may
/// not be in the collection. Returns -1 if not found.
/// </summary>
private int GetItemIndex(TItem itemToFind)
{
TKey keyToFind = GetKeyForItem(itemToFind);
if (this.Contains(keyToFind))
return this.IndexOf(this[keyToFind]);
else return -1;
}
// Overrides a lot of methods that can cause collection change
protected override void SetItem(int index, TItem item)
{
var oldItem = base[index];
base.SetItem(index, item);
OnCollectionChanged(NotifyCollectionChangedAction.Replace, item, oldItem);
}
protected override void InsertItem(int index, TItem item)
{
base.InsertItem(index, item);
OnCollectionChanged(NotifyCollectionChangedAction.Add, item);
}
protected override void ClearItems()
{
base.ClearItems();
OnCollectionChanged();
}
protected override void RemoveItem(int index)
{
TItem item = this[index];
base.RemoveItem(index);
OnCollectionChanged(NotifyCollectionChangedAction.Remove, item);
}
private bool _deferNotifyCollectionChanged = false;
public void AddRange(IEnumerable<TItem> items)
{
_deferNotifyCollectionChanged = true;
foreach (var item in items)
Add(item);
_deferNotifyCollectionChanged = false;
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (_deferNotifyCollectionChanged)
return;
if (CollectionChanged != null)
CollectionChanged(this, e);
}
#region INotifyCollectionChanged Members
public event PropertyChangedEventHandler PropertyChanged;
public event NotifyCollectionChangedEventHandler CollectionChanged;
private void OnPropertyChanged()
{
OnPropertyChanged(CountString);
}
protected virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
private void OnCollectionChanged()
{
if (_deferNotifyCollectionChanged)
return;
OnPropertyChanged();
if (CollectionChanged != null) CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
private void OnCollectionChanged(NotifyCollectionChangedAction action, TItem changedItem)
{
if (_deferNotifyCollectionChanged)
return;
OnPropertyChanged();
if (CollectionChanged != null) CollectionChanged(this, new NotifyCollectionChangedEventArgs(action, changedItem));
}
private void OnCollectionChanged(NotifyCollectionChangedAction action, TItem newItem, TItem oldItem)
{
if (_deferNotifyCollectionChanged)
return;
OnPropertyChanged();
if (CollectionChanged != null) CollectionChanged(this, new NotifyCollectionChangedEventArgs(action, newItem, oldItem));
}
private void OnCollectionChanged(NotifyCollectionChangedAction action, IList newItems)
{
if (_deferNotifyCollectionChanged)
return;
OnPropertyChanged();
if (CollectionChanged != null) CollectionChanged(this, new NotifyCollectionChangedEventArgs(action, newItems));
}
#endregion
}
偏题主题社论:即使在可观察的情况下,字典仍然吸引人。拿那个OD impl把它扔进这个该死的垃圾篮里。抓住你一个闪亮的新KeyedCollection和螺栓INotifyCollectionChanged和打捞任何INCC impl你可以从OD impl(也许你不应该把它扔在垃圾桶里)。 KeyedCollections是IEnumerable ,其中T有一个属性是关键。 KC可以很好地与WPF绑定一起工作,它们喜欢IE ,但它使用了IEnumerable >字典。 KVP包装让事情变得比他们需要的更难。 –
Will