0
我从this article开始获取不同类型的MutableKey集合。带MutableKey的KeyedCollection
我想为我的所有集合的抽象KeyedCollection基类,所以我使用泛型和我的目的一个接口,但我想知道如果有一个更优雅的解决方案,以避免暴露集合属性我的物品。
public class FooItem : IMyKeyedCollectionItem<FooItem>
{
// *** In this way the setter of the Collections property is public, any other solution to avoid this? **//
public HashSet<MyKeyedCollectionBase<FooItem>> Collections { get; set; } = new HashSet<MyKeyedCollectionBase<FooItem>>();
private string _name;
public string Name
{
get { return _name; }
set
{
if (Collections != null)
{
foreach (var collection in Collections)
{
collection.ChangeKey(this, value);
}
}
_name = value;
}
}
}
/// <summary>
/// Interface for the mutablekey keyedcollection.
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IMyKeyedCollectionItem<T> where T : IMyKeyedCollectionItem<T>
{
/// <summary>
/// Collections that contain this item.
/// </summary>
HashSet<MyKeyedCollectionBase<T>> Collections { get; set; }
}
// KeyedCollection is an abstract class, so I have to derive
public abstract class MyKeyedCollectionBase<T> : KeyedCollection<string, T> where T : IMyKeyedCollectionItem<T>
{
public MyKeyedCollectionBase() : base(StringComparer.OrdinalIgnoreCase, 0) { } // case-insensitive
public MyKeyedCollectionBase(MyKeyedCollectionBase<T> collection)
{
if (collection != null)
{
foreach (var item in collection)
Add(item);
}
}
protected override void InsertItem(int index, T item)
{
base.InsertItem(index, item);
AddCollectionToItem(item);
}
private void AddCollectionToItem(T item)
{
if (item.Collections == null)
item.Collections = new HashSet<MyKeyedCollectionBase<T>>();
item.Collections.Add(this);
}
private void RemoveCollectionFromItem(T item)
{
item.Collections.Remove(this);
if (item.Collections.Count == 0)
item.Collections = null;
}
protected override void SetItem(int index, T item)
{
var replaced = Items[index];
base.SetItem(index, item);
AddCollectionToItem(item);
RemoveCollectionFromItem(replaced);
}
protected override void RemoveItem(int index)
{
var removedItem = Items[index];
base.RemoveItem(index);
RemoveCollectionFromItem(removedItem);
}
protected override void ClearItems()
{
foreach (var removed in Items)
RemoveCollectionFromItem(removed);
base.ClearItems();
}
// Expose this method internally to allow mutable item keys: When the key for an item changes, this method is used to change the key in the lookup dictionary
internal virtual void ChangeKey(T item, string newKey)
{
base.ChangeItemKey(item, newKey);
}
}
public class MyFooKeyedCollection : MyKeyedCollectionBase<FooItem>
{
protected override string GetKeyForItem(FooItem item)
{
return item.Name;
}
}
https://codereview.stackexchange.com/可能会感兴趣的。 – mjwills
两件事。你总是调用'ChangeKey',即使'_name == value'似乎是不必要的。其次,'FooItem'“知道”它的收藏,这不应该是它的责任。如何实现[INotifyPropertyChanged](https://stackoverflow.com/a/1316417/1336590)并让集合为其包含的每个对象注册该事件,然后在任何引发该事件的对象时适当地调用'ChangeKey' 。 - 这样,集合全权负责持有和维护对象,并且对象保持无视。 – Corak
嗨@Corak,伟大的提示,我阐述了它,它似乎很好。 – ilCosmico