2017-01-05 20 views
3

我想实现的是对一个日期比较容忍的IEqualityComparer。我也看过this question。问题是我无法使用解决方法,因为我在LINQ .GroupJoin()中使用IEqualityComparer。我已经尝试了一些允许宽容的实现。我可以让Equals()工作,因为我有两个对象,但我不知道如何实现GetHashCode()使用的IEqualityComparer的GetHashCode的公差

我最好的尝试看起来是这样的:

public class ThingWithDateComparer : IEqualityComparer<IThingWithDate> 
{ 
    private readonly int _daysToAdd; 

    public ThingWithDateComparer(int daysToAdd) 
    { 
     _daysToAdd = daysToAdd; 
    } 

    public int GetHashCode(IThingWithDate obj) 
    { 
     unchecked 
     { 
      var hash = 17; 
      hash = hash * 23 + obj.BirthDate.AddDays(_daysToAdd).GetHashCode(); 
      return hash; 
     } 
    } 

    public bool Equals(IThingWithDate x, IThingWithDate y) 
    { 
     throw new NotImplementedException(); 
    } 
} 

public interface IThingWithDate 
{ 
    DateTime BirthDate { get; set; } 
} 

随着.GroupJoin()建设HashTableGetHashCode()它适用的日子同时添加到/所有对象。这不起作用。

+0

是daysTo添加宽容,因为在1月5日等于1月6日容忍1天?这种相等的定义不是传递性的,所以我怀疑可以在每个对象返回相同哈希码的简单解决方案之外正确使用IEqualityComparer来实现。 –

+0

忘记它。将'GroupJoin'替换为'SelectMany'和简单的'Where'(不是很高效,但应该可以工作)。 –

+0

@mikez是的,那是宽容。命名很糟糕。如果我无法完成这项工作,我将只实现一个定制版本的'GroupJoin()'。 –

回答

2

的问题是不可能的,在概念上。您试图以一种不具有您尝试执行的操作所需的平等形式的方式比较对象。例如,GroupJoin取决于如下假设:如果A等于B,B等于C,那么A等于C,但在您的情况下,情况并非如此。 A和B可能“足够接近”在一起,因为你想分组它们,但A和C可能不一样。

你将需要不落实IEqualityComparer可言,因为你不能满足其需要的合同。如果你想创建一个集合中的项目到另一个集合中“足够接近”的所有项目的映射,那么你将需要自己编写该算法(这么做很有效率很可能很难,但这样做效率不高,不应该那么困难),而不是使用GroupJoin,因为它无法执行该操作。

+0

这似乎是正确的答案。答案是没有答案,这是令人失望的。 –

1

我看不到任何方式产生了给定的标准逻辑哈希码。
哈希码用于确定2个日期是否应该粘在一起。如果它们应该组合在一起,那么它们必须返回相同的散列码。

如果您的“浮动”是5天,这意味着必须1/1/2000生成相同的散列码为2000年1月4日,2000年1月4日和必须产生相同的散列码为1/8/2000年(因为他们都在5天内彼此)。这意味着1/1/2000具有与1/8/2000相同的代码(因为如果a = b且b = c,a = c)。

1/1/2000和2000年1月8日是第5天“浮动”的外部。

+0

非常真实。我想我将不得不放弃使用'GroupJoin'并实现一个允许从左侧开始种子的'Comparer'的版本。 –