HashSet.Remove不能与EqualityComparer一起工作

问题描述:

我期待已经使用指定的EqualityComparer创建的HashSet在Remove操作上使用该比较器。特别是因为Contains操作返回true!HashSet.Remove不能与EqualityComparer一起工作

这里是我使用的代码:

public virtual IEnumerable<Allocation> Allocations { get { return _allocations; } } 
private ICollection<Allocation> _allocations; 

public Activity(IActivitySubject subject) { // constructor 
    .... 
    _allocations = new HashSet<Allocation>(new DurationExcludedEqualityComparer()); 
} 

public virtual void ClockIn(Allocation a) 
{ 
    ... 
    if (_allocations.Contains(a)) 
     _allocations.Remove(a); 
    _allocations.Add(a); 
} 

下面是一些快速和肮脏的LINQ这让我我想要的逻辑,但我猜测基础上,EqualityComparer将显著加快HashSet中删除。

public virtual void ClockIn(Allocation a) 
{ 
    ... 
    var found = _allocations.Where(x => x.StartTime.Equals(a.StartTime) && x.Resource.Equals(a.Resource)).FirstOrDefault(); 
    if (found != null) 
    { 
      if (!Equals(found.Duration, a.Duration)) 
      { 
       found.UpdateDurationTo(a.Duration); 
      } 
    } 
    else 
    { 
      _allocations.Add(a); 
    } 

任何人都可以提出为什么删除会失败,当包含成功?

干杯,
Berryl

===编辑===比较程序

public class DurationExcludedEqualityComparer : EqualityComparer<Allocation> 
{ 
    public override bool Equals(Allocation lhs, Allocation rhs) 
    { 
     if (ReferenceEquals(null, rhs)) return false; 
     if (ReferenceEquals(lhs, null)) return false; 
     if (ReferenceEquals(lhs, rhs)) return true; 

     return 
      lhs.StartTime.Equals(rhs.StartTime) && 
      lhs.Resource.Equals(rhs.Resource) && 
      lhs.Activity.Equals(rhs.Activity); 
    } 

    public override int GetHashCode(Allocation obj) { 
     if (ReferenceEquals(obj, null)) return 0; 
     unchecked 
     { 
      var result = 17; 
      result = (result * 397)^obj.StartTime.GetHashCode(); 
      result = (result * 397)^(obj.Resource != null ? obj.Resource.GetHashCode() : 0); 
      result = (result * 397)^(obj.Activity != null ? obj.Activity.GetHashCode() : 0); 
      return result; 
     } 
    } 
} 

===更新 - 修正===

好了,好消息是,HashSet的没有损坏,并且完全按照它应该的那样工作。对我而言,坏消息是在检查树上的树叶时无法看到森林的时候,我会变得非常愚蠢!

答案实际上是在上面的发布代码中,如果你看看拥有HashSet的创建&的类,然后再看看比较器来找出它的错误。轻松点第一个人发现它。

感谢所有看过代码的人!

+2

Post'DurationExcludedEqualityComparer'。 – 2010-09-01 21:58:59

+0

我猜想你的'DurationExcludedEqualityComparer'中的平等实现是可疑的。 – adrianbanks 2010-09-01 22:00:55

+0

你的'Allocation'类(以及任何'Resource'和'Activity'引用)是什么样的? – adrianbanks 2010-09-01 22:10:08

那么,你的代码“工作”似乎看StartTimeResource,而忽略Activity,而你的IEqualityComparer<Allocation>执行看起来全部三。你的问题可能与此有关吗?

另外:你的StartTime,ResourceActivity属性不变?否则,由于它们会影响您的GetHashCode结果,我认为您冒着破坏HashSet<Allocation>的风险。

+0

宾果在第一行。我不太确定它是否是某种递归,但在这种情况下,它是一个拥有HashSet的Activity。在添加分配方法(ClockIn)中放置一个警戒来检查属于'this'活动的分配,并且在任何事件中将比较方法中的Activity都取出来更合理,并通过返回一致的哈希来解决问题。干杯! – Berryl 2010-09-02 02:39:34