Составной ключ в словаре; переопределить GetHashCode (), Equals и т. д. или использовать структуры? - PullRequest
4 голосов
/ 15 марта 2010

У меня довольно много словарей, в которых ключ является составной из нескольких разных значений (в основном это строки и целые числа). Должен ли я реализовать эти ключи как классы (и переопределить GetHashCode(), Equals() и т. Д.) Или вместо этого использовать struct?

ReSharper позволяет легко выполнить переопределение, но код выглядит ужасно. Есть ли какие-либо последствия для производительности вместо использования структуры?

Ответы [ 3 ]

3 голосов
/ 15 марта 2010

Если вашей единственной проблемой является определение равенства для использования в Dictionary<TKey,TValue>, то другой путь, который вы можете выбрать, - это реализация IEqualityComparer<T>. Это можно передать вручную в конструктор словаря и позаботиться о сравнениях на равенство для значения TKey без изменения типа ключа.

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

1 голос
/ 04 января 2012

Я бы на самом деле сказал, что для любой структуры следует всегда вручную кодировать переопределение Equals() и GetHashCode() вместе с реализацией IEquatable<T>, если есть вероятность, что он может быть использован кем-то в качестве ключа, поэтомуЯ, конечно, не стал бы использовать его просто для того, чтобы этого не делать.

Помимо того, что требуется бокс, реализация по умолчанию довольно медленная, так как для изучения полей используется отражение.Есть также ошибка, по крайней мере, в некоторых версиях фреймворка (реализация вполне разумно оптимизирует как бинарное сравнение, когда это дает правильные результаты, но, к сожалению, неправильно оценивает, когда это так, и, следовательно, две структуры, содержащие эквивалент decimalполя могут считаться неравными).

Когда требуется быстрая составная схема, которая на самом деле не имеет никакого значения для системы, кроме того, что она представляет собой составной ключ, я рекомендую использовать Tuple.Tuple.Create() позволяет легко их составлять, и переопределения для Equals() и GetHashCode() вполне разумны.

В некоторых случаях также может быть целесообразно использовать анонимные классы в качестве ключей (только в контекстеданного метода, конечно), и здесь переопределения для Equals() и GetHashCode() также довольно разумны.

0 голосов
/ 02 июля 2013

Для создания такого составного класса рекомендуется использовать метод наследования от Tuple<int, string, ...>.

Таким образом, вам не нужно переопределять GetHashCode и Equals самостоятельно, базовый класс сделает это за вас.

Вы можете легко предоставить значимые методы доступа get для каждого поля.

public class CompositeKey : Tuple<string, int>
{
    public CompositeKey(string name, int age)
        : base(name, age)
    {
    }
    public string Name { get { return Item1; } }
    public int Age { get { return Item2; } }
}

Это также обеспечивает неизменность, которая подходит для ключей словаря.

Что касается производительности, встроенные кортежи довольно быстрые. Я обнаружил, что пользовательские структуры могут быть быстрее, хотя, если вам действительно нужен каждый дополнительный бит производительности, лучше всего напрямую закодировать ваши ключевые данные в int или long.

...