Словарь ContainsKey не работает со строкой [] - PullRequest
1 голос
/ 29 ноября 2011

Я пытаюсь создать структуру данных с несколькими строковыми ключами.Для этого я попытался создать словарь с элементом string [].Но ContainsKey, похоже, работает не так, как я ожидаю:

Dictionary<string[], int> aaa = new Dictionary<string[], int>();
int aaaCount = 0;
aaa.Add(new string[] { string1, string2 }, aaaCount++);

if (!aaa.ContainsKey(new string[] { string1, string2 }))
{
    aaa.Add(new string[] { string1, string2 }, aaaCount++);
}

Я вижу, что в aaa есть две записи после выполнения кода выше, хотя я ожидал только одну.Это ожидаемое поведение?Как я могу убедиться, что в Словаре нет повторяющихся записей?

Примечание: я пытался сделать то же самое со списком (Список и результат тот же - метод Contains на самом деле не работает со строкой [])

Ответы [ 4 ]

2 голосов
/ 29 ноября 2011

Если вы хотите использовать string[] в качестве TKey, вы должны передать IEqualityComparer<string[]> конструктору из Dictionary. Поскольку в противном случае Словарь использует стандартное сравнение для TKey, а в случае string[] он просто сравнивает ссылки, следовательно, string[] является ссылочным типом. Вы должны реализовать IEqualityComparer самостоятельно. Это можно сделать следующим образом:

(Реализация довольно наивна, я предоставляю ее как отправную точку)

public class StringArrayComparer : IEqualityComparer<string[]>
{
    public bool Equals(string[] left, string[] right)
    {
        if (ReferenceEquals(left, right))
        {
            return true;
        }

        if ((left == null) || (right == null))
        {
            return false;
        }

        return left.SequenceEqual(right);
    }

    public int GetHashCode(string[] obj)
    {
        return obj.Aggregate(17, (res, item) => unchecked(res * 23 + item.GetHashCode()));
    }
}
2 голосов
/ 29 ноября 2011

Вам нужно создать IEqualityComparer<string[]> и передать его конструктору словаря.

Это говорит словару, как сравнивать ключи.
По умолчанию он сравнивает их по ссылке.

2 голосов
/ 29 ноября 2011

Поскольку массив является ссылочным типом, т. Е. Вы проверяете ссылка (идентичность) на равенство, а не равенство на основе значений в массиве. Когда вы создаете новый массив с теми же значениями, сами массивы по-прежнему являются двумя различными объектами, поэтому ContainsKey возвращает false.

Использование массива в качестве словарного ключа немного ... странно. Что вы пытаетесь отобразить здесь? Вероятно, есть лучший способ сделать это.

0 голосов
/ 29 ноября 2011

Возможно, вам лучше, если ваше приложение это поддерживает, объединять строковый массив в одну строку.

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

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

...