我希望ISet<T>
有两个额外的活动ItemAdded
和ItemRemoved
。
我考虑的一个选项是从MyHashSet<T>
派生HashSet<T>
,但由于Add
和Remove
不是虚拟的,因此需要使用new
。也许这是对关键字的有效使用?
我认为另一个选项是实现ISet<T>
并将所有内容委托给HashSet<T>
的私有实例。这感觉就像一个庞大的解决方案。
是否有一个模式或框架类可以获得相同的结果但是不需要优雅/理想的编码?
答案 0 :(得分:3)
基于我收到的评论(谢谢),这里有我得到的信息:
public class NotifyingHashSet<T>
{
private HashSet<T> hashSet = new HashSet<T>();
public bool Add(T item)
{
bool added = hashSet.Add(item);
if(added && ItemAdded != null)
{
ItemAdded(this, new NotifyingHashSetEvent<T>(item));
}
return added;
}
public bool Remove(T item)
{
bool removed = hashSet.Remove(item);
if(removed && ItemRemoved != null)
{
ItemRemoved(this, new NotifyingHashSetEvent<T>(item));
}
return removed;
}
public event EventHandler<NotifyingHashSetEvent<T>> ItemAdded;
public event EventHandler<NotifyingHashSetEvent<T>> ItemRemoved;
}
public class NotifyingHashSetEvent<T> : EventArgs
{
public NotifyingHashSetEvent(T item)
{
Item = item;
}
public T Item { get; set; }
}
答案 1 :(得分:2)
在这种情况下,我建议inheriting
而不是composing
。
这将确保您获得HashSet提供的所有内容:
Contains
和其他Set操作,例如IsSubsetOf
HashSet<int> foo = new NotifyingHashSet<int>()
我的实现如下:
public class NotifyingHashSet<T> : HashSet<T>
{
public new void Add(T item)
{
OnItemAdded(new NotifyHashSetChanged<T>(item));
base.Add(item);
}
public new void Remove(T item)
{
OnItemRemoved(new NotifyHashSetChanged<T>(item));
base.Remove(item);
}
public event EventHandler<NotifyHashSetChanged<T>> ItemAdded;
public event EventHandler<NotifyHashSetChanged<T>> ItemRemoved;
protected virtual void OnItemRemoved(NotifyHashSetChanged<T> e)
{
if (ItemRemoved != null) ItemRemoved(this, e);
}
protected virtual void OnItemAdded(NotifyHashSetChanged<T> e)
{
if (ItemAdded != null) ItemAdded(this, e);
}
}
public class NotifyHashSetChanged<T> : EventArgs
{
private readonly T _item;
public NotifyHashSetChanged(T item)
{
_item = item;
}
public T ChangedItem
{
get { return _item; }
}
}
检查内容的一些测试:
[TestClass]
public class NotifyingHashSetTests
{
[TestMethod]
public void ShouldAddToNotifyingHashSet()
{
var notifyingHashSet = new NotifyingHashSet<int>();
notifyingHashSet.ItemAdded += (sender, changed) => Assert.AreEqual(changed.ChangedItem, 1);
notifyingHashSet.Add(1);
}
[TestMethod]
public void ShouldRemoveFromNotifyingHashSet()
{
//can use collection initializer
var notifyingHashSet = new NotifyingHashSet<int> { 1 };
notifyingHashSet.ItemRemoved += (sender, changed) => Assert.AreEqual(changed.ChangedItem, 1);
notifyingHashSet.Remove(1);
}
[TestMethod]
public void ShouldContainValueInNotifyingHashSet()
{
//can use collection initializer
var notifyingHashSet = new NotifyingHashSet<int> { 1 };
Assert.IsTrue(notifyingHashSet.Contains(1));
}
[TestMethod]
public void ShouldAssignToHashSet()
{
HashSet<int> notifyingHashSet = new NotifyingHashSet<int> { 1 };
Assert.IsTrue(notifyingHashSet.IsSubsetOf(new List<int>{ 1,2 }));
}
}
答案 2 :(得分:1)
您自己的答案演示了如何包装HashSet<T>
,而Srikanth的答案演示了如何从HashSet<T>
派生出来。但是,当您从HashSet<T>
派生时,您必须确保新类也正确实现Add
接口的Remove
和ICollection<T>
方法。所以我修改了Srikanth的答案,通过使用ISet<T>
的相关方法的显式接口实现来正确创建HashSet<T>
实现,其中包含来自ICollection<T>
的通知:
public class NotifyingHashSet<T> : HashSet<T>, ICollection<T> {
new public void Add(T item) {
((ICollection<T>) this).Add(item);
}
new public Boolean Remove(T item) {
return ((ICollection<T>) this).Remove(item);
}
void ICollection<T>.Add(T item) {
var added = base.Add(item);
if (added)
OnItemAdded(new NotifyHashSetEventArgs<T>(item));
}
Boolean ICollection<T>.Remove(T item) {
var removed = base.Remove(item);
if (removed)
OnItemRemoved(new NotifyHashSetEventArgs<T>(item));
return removed;
}
public event EventHandler<NotifyHashSetEventArgs<T>> ItemAdded;
public event EventHandler<NotifyHashSetEventArgs<T>> ItemRemoved;
protected virtual void OnItemRemoved(NotifyHashSetEventArgs<T> e) {
var handler = ItemRemoved;
if (handler != null)
ItemRemoved(this, e);
}
protected virtual void OnItemAdded(NotifyHashSetEventArgs<T> e) {
var handler = ItemAdded;
if (handler != null)
ItemAdded(this, e);
}
}
public class NotifyHashSetEventArgs<T> : EventArgs {
public NotifyHashSetEventArgs(T item) {
Item = item;
}
public T Item { get; private set; }
}
此类的行为与您的类的行为方式相同,只是在实际添加或从集合中删除元素时触发事件。例如,连续两次添加相同的元素只会触发一个事件。