2013-09-13 4 views
0

У меня есть случай, когда два объекта можно сравнить с разными способами для равенства. Например:Каков правильный способ установки ложного IEqualityComparer <T>?

public class HeightComparer : IEqualityComparer<Person> { 
    public bool Equals(Person x, Person y) { 
     return x.Height.Equals(y.Height); 
    } 

    public int GetHashCode(Person obj) { 
     return obj.Height; 
    } 
} 

И я использую эти компараторов в Dictionary<Person,Person>(IEqualityComparer<Person>) для различных методов. Как бы вы сделали сравнитель, который гарантирует, что каждый человек уникален? Я придумал следующее, но он работает медленно, так как метод GetHashCode() часто возвращает одно и то же значение.

public class NullPersonComparer : IEqualityComparer<Person> { 
    public bool Equals(Person x, Person y) { 
     return false; // always unequal 
    } 

    public int GetHashCode(Person obj) { 
     return obj.GetHashCode(); 
    } 
} 

Я мог бы вернуть то же значение 0 от GetHashCode(Person obj), но он по-прежнему медленно наполнения словаря.

Редактировать

Вот Прецедент:

Dictionary<Person, Person> people = new Dictionary<Person, Person>(comparer); 
foreach (string name in Names) 
{ 
    Person person= new Person(name); 
    Person realPerson; 
    if (people.TryGetValue(person, out realPerson)) 
    { 
     realPerson.AddName(name); 
    } 
    else 
    { 
     people.Add(person, person); 
    } 
    } 
+0

Могли бы вы лучше описать свой вариант использования? Не совсем понятно, что вы подразумеваете под «уникальным» или тем, что вы пытаетесь выполнить. – MgSam

+0

Считается уникальным, даже если в коллекции, которую вы хешируете, содержится много обманов? Внедрите GetHashCode, чтобы он всегда возвращал уникальный номер (возможно, увеличивался на единицу каждый раз, когда он вызывается). Тогда хэш-таблице не нужно будет так часто решать конфликты. – spender

+0

@MgSam различные объекты в памяти. Две ссылки на одного и того же человека должны рассматриваться одинаково. Но два человека с одинаковой статистикой должны быть разными, если они созданы отдельно. – Moop

ответ

2

Если тип не переопределен в Equals или GetHashCode методов, то их реализация по умолчанию, из object, делать то, что вы хотите, а именно обеспечить равенства, основанного на их идентичности, а не их ценности. Вы можете использовать EqualityComparer<Person>.Default, чтобы получить IEqualityComparer, который использует эти семантики, если вы хотите.

Если метод Equals был изменен, чтобы обеспечить своего рода семантики значений, но вы не хотите, что вы хотите идентичность семантики, то вы можете использовать object.ReferenceEquals в собственной реализации:

public class IdentityComparer<T> : IEqualityComparer<T> 
{ 
    public bool Equals(T x, T y) 
    { 
     return object.ReferenceEquals(x, y); 
    } 

    public int GetHashCode(T obj) 
    { 
     return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(obj); 
    } 
} 
+0

Cool , Будет EqualityComparer .Default будет таким же, как ваш IdentityComparer ? – Moop

+1

Если 'Equals' был переопределен, тогда' GetHashCode' также должен был быть переопределен. Вы можете использовать 'System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode', чтобы получить реализацию по умолчанию. Это может уменьшить количество столкновений. –

+0

@Moop Нет, потому что 'Equals' и' GetHashCode' являются виртуальными, поэтому они все равно будут ссылаться на переопределенные версии соответствующих методов. – Servy

Смежные вопросы