2012-03-09 17 views
7

Dadas las siguientes clases:¿Por qué esta agrupación LINQ tiene un recuento de 3 en lugar de 2?

public class WeekOfYear : IEquatable<WeekOfYear>, IComparable<WeekOfYear> 
{ 
    private readonly DateTime dateTime; 
    private readonly DayOfWeek firstDayOfWeek; 

    public WeekOfYear(DateTime dateTime) 
     : this(dateTime, DayOfWeek.Sunday) 
    { 
    } 

    public WeekOfYear(DateTime dateTime, DayOfWeek firstDayOfWeek) 
    { 
     this.dateTime = dateTime; 
     this.firstDayOfWeek = firstDayOfWeek; 
    } 

    public int Year 
    { 
     get 
     { 
      return dateTime.Year; 
     } 
    } 

    public int Week 
    { 
     get 
     { 
      return CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(dateTime, CalendarWeekRule.FirstDay, firstDayOfWeek); 
     } 
    } 

    public bool Equals(WeekOfYear other) 
    { 
     return Year == other.Year && Week == other.Week; 
    } 

    public int CompareTo(WeekOfYear other) 
    { 
     if (Year > other.Year || Year == other.Year && Week > other.Week) 
     { 
      return 1; 
     } 
     if (Equals(other)) 
     { 
      return 0; 
     } 
     return -1; 
    } 

    public override string ToString() 
    { 
     return String.Format("Week of {0}", dateTime.FirstDayOfWeek(firstDayOfWeek).ToString("MMMM dd, yyyy")); 
    } 
} 

public class WeekOfYearComparer : IEqualityComparer<WeekOfYear>, IComparer<WeekOfYear> 
{ 
    public bool Equals(WeekOfYear x, WeekOfYear y) 
    { 
     return x.Equals(y); 
    } 

    public int GetHashCode(WeekOfYear weekOfYear) 
    { 
     return weekOfYear.GetHashCode(); 
    } 

    public int Compare(WeekOfYear x, WeekOfYear y) 
    { 
     return x.CompareTo(y); 
    } 
} 

no pasa esta prueba (inesperadamente):

[Test] 
public void Fails() 
{ 
    var dates = new List<DateTime> 
        { 
         new DateTime(2012, 1, 1), 
         new DateTime(2012, 2, 1), 
         new DateTime(2012, 1, 1) 
        }; 

    IEnumerable<IGrouping<WeekOfYear, DateTime>> groups = dates.GroupBy(date => new WeekOfYear(date), new WeekOfYearComparer()); 

    Assert.That(groups.Count(), Is.EqualTo(2)); // count is 3 
} 

y esta prueba pases (como era de esperar):

[Test] 
public void Works() 
{ 
    var dates = new List<DateTime> 
        { 
         new DateTime(2012, 1, 1), 
         new DateTime(2012, 2, 1), 
         new DateTime(2012, 1, 1) 
        }; 

    var groups = dates.GroupBy(
     date => 
      { 
       var weekOfYear = new WeekOfYear(date); 
       return new { weekOfYear.Year, weekOfYear.Week }; 
      }); 

    Assert.That(groups.Count(), Is.EqualTo(2)); 
} 

¿Por qué el primer resultado de la prueba en un conteo de 3?

Respuesta

10

La primera parte de una comprobación de igualdad se realiza mediante el código hash; usted debe proporcionar una implementación de código hash válida (por qué, consulte Why is it important to override GetHashCode when Equals method is overridden?). Tu comparador podía hacer esto, pero difiere al objeto:

public int GetHashCode(WeekOfYear weekOfYear) 
{ 
    return weekOfYear.GetHashCode(); 
} 

y el objeto no proporcionan un hash-código válido. Una aplicación adecuada dentro WeekOfYear sería algo así como:

public bool Equals(WeekOfYear other) 
{ 
    return other != null && Year == other.Year && Week == other.Week; 
} 
public override bool Equals(object obj) 
{ 
    return Equals(obj as WeekOfYear); 
} 
public override int GetHashCode() 
{ // exploit number of weeks in year 
    return (Year.GetHashCode()*52) + Week.GetHashCode(); 
} 

Observando también he proporcionado un override por la igualdad también.

En realidad, dado que su objeto proporciona todo el código aquí, no hay ningún beneficio en un comparador personalizado; Podría quitar WeekOfYearComparer por completo, ya que el comportamiento por defecto es la búsqueda de la igualdad de operaciones/de comparación adecuados del tipo subyacente:

var groups = dates.GroupBy(date => new WeekOfYear(date)); 
+0

Gracias, Marc. Pensé que podría tener algo que ver con el código hash, pero no estaba seguro. Esto definitivamente resolvió el problema. Aclamaciones. –

Cuestiones relacionadas