ISet <t>通知添加和删除?</t>

时间:2014-11-06 05:56:58

标签: c#

我希望ISet<T>有两个额外的活动ItemAddedItemRemoved

我考虑的一个选项是从MyHashSet<T>派生HashSet<T>,但由于AddRemove不是虚拟的,因此需要使用new。也许这是对关键字的有效使用?

我认为另一个选项是实现ISet<T>并将所有内容委托给HashSet<T>的私有实例。这感觉就像一个庞大的解决方案。

是否有一个模式或框架类可以获得相同的结果但是不需要优雅/理想的编码?

3 个答案:

答案 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接口的RemoveICollection<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; }

}

此类的行为与您的类的行为方式相同,只是在实际添加或从集合中删除元素时触发事件。例如,连续两次添加相同的元素只会触发一个事件。