2010-09-01 7 views
5

Estoy esperando un HashSet que se haya creado con un EqualityComparer especificado para usar ese comparador en una operación de eliminación. ¡Especialmente desde que las operaciones de Contiene son verdaderas!HashSet.Remove no funciona con EqualityComparer

Aquí está el código que estoy utilizando:

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); 
} 

A continuación se muestra un poco de LINQ rápida y sucia que me pone la lógica que quiero, pero estoy adivinando el remove HashSet basado en la EqualityComparer sería significativamente más rápido.

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); 
    } 

¿Alguien puede sugerir por qué el Remove fallaría cuando Contiene el éxito?

Cheers,
Berryl

=== === EDITAR el comparador

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; 
     } 
    } 
} 

=== ACTUALIZACIÓN - === FIJO

Bueno, la buena noticia es que HashSet no está roto y funciona exactamente como debería. Las malas noticias, para mí, son cuán increíblemente estúpido soy cuando no puedo ver el bosque mientras examino las hojas de los árboles.

La respuesta está en realidad en el código publicado más arriba, si nos fijamos en la clase que crea & que posee el HashSet, y luego echando otro vistazo a la Comparer para averiguar qué está mal con ella. Puntos fáciles para que la primera persona lo detecte.

¡Gracias a todos los que vieron el código!

+2

Publicar 'DurationExcludedEqualityComparer'. –

+0

Supongo que su implementación de igualdad en 'DurationExcludedEqualityComparer' es sospechosa. – adrianbanks

+0

¿A qué se parece tu clase 'Allocation' (y también a qué se refieren' Resource' y 'Activity')? – adrianbanks

Respuesta

1

Bueno, el código que "funciona" aparece a la vista StartTime y Resource sin tener en cuenta Activity, mientras que su aplicación IEqualityComparer<Allocation> mira a los tres. ¿Podría su problema estar relacionado con eso?

Además: ¿son sus propiedades StartTime, Resource y Activity invariables? De lo contrario, dado que afectan el resultado GetHashCode, creo que corre el riesgo de romper su HashSet<Allocation>.

+0

Bingo en la primera línea. No estoy seguro si fue algún tipo de recursión, pero es una actividad que posee el HashSet en este caso. Colocar un guardia en el método de asignación de adición (ClockIn) para verificar la asignación pertenece a esta actividad y tomar Activity de los métodos comparer es más lógico en cualquier caso y soluciona el problema devolviendo un hash consistente. ¡Aclamaciones! – Berryl

Cuestiones relacionadas