2012-03-09 25 views
7

Với các lớp học sau:Tại sao nhóm LINQ này có số lượng 3 thay vì 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); 
    } 
} 

thử nghiệm này thất bại (bất ngờ):

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

Và thử nghiệm này đèo (dự kiến):

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

Tại sao kết quả thử nghiệm đầu tiên trong một số 3?

Trả lời

10

Phần đầu tiên của kiểm tra bình đẳng được thực hiện thông qua mã băm; bạn phải cung cấp triển khai mã băm hợp lệ (vì lý do tại sao, hãy xem Why is it important to override GetHashCode when Equals method is overridden?). Comparer của bạn có thể làm điều này, nhưng nó trì hoãn đến đối tượng:

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

và đối tượng không cung cấp một hash-mã hợp lệ. Một thực hiện phù hợp bên WeekOfYear sẽ là một cái gì đó như:

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

Ghi nhận tôi cũng đã cung cấp một override cho bình đẳng quá.

Thực tế, vì đối tượng của bạn cung cấp tất cả mã ở đây, không có lợi ích nào trong trình so sánh tùy chỉnh; bạn có thể xóa hoàn toàn WeekOfYearComparer vì hành vi mặc định là tìm kiếm các hoạt động bình đẳng/so sánh phù hợp trên loại cơ bản:

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

Xin cảm ơn, Marc. Tôi nghĩ rằng nó có thể có một cái gì đó để làm với mã băm nhưng không chắc chắn. Điều này chắc chắn đã giải quyết được vấn đề. Chúc mừng. –

Các vấn đề liên quan