2017-01-05 16 views
3

Я пытаюсь реализовать IEqualityComparer, который имеет допуски при сравнении дат. Я также посмотрел this question. Проблема в том, что я не могу использовать обходной путь, потому что я использую IEqualityComparer в LINQ .GroupJoin(). Я пробовал несколько реализаций, которые допускают терпимость. Я могу заставить 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() строит HashTable из GetHashCode() это относится дни добавить к обоим/все объекты. Это не работает.

+0

Является ли daysToAdd допуск, так как в январе 5 равен 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

Я не вижу способа генерировать логический хеш-код для данных критериев.
Хэш-код используется для определения того, должны ли две даты совпадать. Если они должны группироваться вместе, они должны возвращать один и тот же хэш-код.

Если ваш «поплавок» составляет 5 дней, это означает, что 1/1/2000 должен генерировать один и тот же хэш-код как 1/4/2000, а 1/4/2000 должен генерировать тот же хэш-код, что и 1/8/2000 (так как они оба находятся в течение 5 дней друг от друга). Это означает, что 1/1/2000 имеет тот же код, что и 1/8/2000 (так как если a = b и b = c, a = c).

1/1/2000 и 1/8/2000 находятся за пределами 5-дневного «плавания».

+0

Очень верно. Я думаю, что мне придется отказаться от использования «GroupJoin» и реализовать версию, которая позволяет использовать «Comparer» с семенем слева. –