.NET Hashtable - один и тот же ключ, разные хеши - PullRequest
3 голосов
/ 09 марта 2010

Возможно ли, чтобы две строки .net имели разные хэши? У меня есть Hashtable, среди прочего, ключевой «путь». Когда я зацикливаюсь на элементах таблицы, чтобы напечатать его, я вижу, что ключ существует.

Однако, при попытке найти его, соответствующий элемент не найден. Отладка показывает, что искомая строка имеет хеш, отличный от того, который я предоставляю в качестве ключа.

Этот код находится в проекте Castle Monorail, в котором в качестве движка просмотра используется brail. Ключ, который я ищу, вставляется линией Брайля следующим образом:

UrlHelper.Link(node.CurrentPage.LinkText, {@params: {@path: "/Page1"}})

Затем, в этом методе (в пользовательском IRoutingRule):

public string CreateUrl(System.Collections.IDictionary parameters)
{
    PrintDictionaryToLog(parameters);
    string url;
    if (parameters.Contains("path")) {
        url = (string)parameters["path"];
    }
    else {
        return null;
    }
}

Ключ выводится в журнал, но функция возвращает ноль. Я не знал, что это может даже быть проблемой со строками .net, но я думаю, что это какая-то проблема кодирования?

О, и это моно.

В соответствии с запросом, соответствующая строка из журнала:

2010-03-08 22:58:00,504 [7] DEBUG Knickle.Framework.Routing.PageRoute (null) - Parameters: {System.String controller=null, System.String path=Page1, System.String path=/Page1, System.String action=null, System.String area=null}

Кроме того, здесь я добавил строку кода над вызовом печати журнала:

parameters.Add("path", "Page1");

Загляните в журнал, и вы заметите, что есть два ключа пути. Отладчик показывает оба ключа в разных местах таблицы.

Ответы [ 6 ]

2 голосов
/ 09 марта 2010

Вот ссылка на MSDN на GetHashCode для строк. Если они равны, хеш-коды должны совпадать, однако, если они не равны, они все равно могут иметь тот же хеш (как бы мала эта вероятность не была).

http://msdn.microsoft.com/en-us/library/system.string.gethashcode.aspx

Из статьи:

Если два строковых объекта равны, Метод GetHashCode возвращает идентичный ценности. Тем не менее, не существует значение хеш-кода для каждой уникальной строки значение. Разные строки могут возвращаться тот же хеш-код.

1 голос
/ 21 марта 2013

Именно эта строка делает это [Castle.MonoRail.Framework.Services.DefaultUrlBuilder: 397] ...

// Forces copying entries to a non readonly dictionary, preserving the original one
parameters = new Hashtable(parameters, StringComparer.InvariantCultureIgnoreCase);

Если IEqualityComparer удален, проблема исчезает.

Если это моно-ошибка (что, я думаю, должно быть), это все еще проблема с моно 2.10.8.1 (Debian 2.10.8.1-5ubuntu1).

Тестовый пример требует написания и подачи.

1 голос
/ 09 марта 2010

Строки, которые соответствуют StringComparison.Ordinal или, проще говоря, String.Equals, будут иметь одинаковый хеш-код при любых обстоятельствах.

1 голос
/ 09 марта 2010

никогда не должно случиться. Проверьте конечные пробелы, экранирование URL и т. Д.

0 голосов
/ 21 марта 2013

Hashtable оптимизирует поиск. Он вычисляет хэш каждого добавляемого вами ключа. Затем он использует этот хэш-код для очень быстрого поиска элемента. Это более старый тип .NET Framework. Это медленнее, чем общий тип словаря.

Словарь Пример

Сначала вы можете создать новый Hashtable с самым простым конструктором. Когда он создан, Hashtable не имеет значений. Мы напрямую присваиваем значения с помощью индексатора, который использует квадратные скобки [].

Далее: В этом примере к объекту Hashtable добавляются три целочисленных ключа по одному строковому значению.

Добавить записи в Hashtable и отобразить их [C #]

using System;
using System.Collections;

class Program
{
    static void Main()
    {
    Hashtable hashtable = new Hashtable();
    hashtable[1] = "One";
    hashtable[2] = "Two";
    hashtable[13] = "Thirteen";

    foreach (DictionaryEntry entry in hashtable)
    {
        Console.WriteLine("{0}, {1}", entry.Key, entry.Value);
    }
    }
}

Результат

13, Thirteen
2, Two
1, One

Программа отображает все объекты DictionaryEntry, возвращаемые перечислителем в цикле foreach. Вызов WriteLine содержит строку формата, которая отображает пары ключ / значение через запятую.

Foreach

Вы можете перебирать Hashtables, используя тип DictionaryEntry в цикле foreach. Вы также можете получить коллекцию ключей и скопировать ее в ArrayList. DictionaryEntry содержит два объекта: ключ и значение.

Foreach DictionaryEntry Содержит Далее мы увидим некоторые из наиболее распространенных и важных методов экземпляров в Hashtable. Вы захотите вызвать ContainsKey на вашем Hashtable с ключевым содержимым. Этот метод возвращает true, если ключ найден, независимо от значения.

Также: Содержит работает так же. Мы видим пример использования индексатора с квадратными скобками [].

Программа, использующая метод Contains [C #]

using System;
using System.Collections;

class Program
{
    static Hashtable GetHashtable()
    {
    // Create and return new Hashtable.
    Hashtable hashtable = new Hashtable();
    hashtable.Add("Area", 1000);
    hashtable.Add("Perimeter", 55);
    hashtable.Add("Mortgage", 540);
    return hashtable;
    }

    static void Main()
    {
    Hashtable hashtable = GetHashtable();

    // See if the Hashtable contains this key.
    Console.WriteLine(hashtable.ContainsKey("Perimeter"));

    // Test the Contains method. It works the same way.
    Console.WriteLine(hashtable.Contains("Area"));

    // Get value of Area with indexer.
    int value = (int)hashtable["Area"];

    // Write the value of Area.
    Console.WriteLine(value);
    }
}

выход

True
True
1000

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

Индексатор Несколько типов Далее мы добавляем несколько типов в Hashtable. В этом примере добавляются строковые ключи и ключи int. Каждая из пар ключ / значение имеет разные типы. Вы можете поместить их все в один и тот же Hashtable.

Программа, которая использует несколько типов [C #]

using System;
using System.Collections;

class Program
{
    static Hashtable GetHashtable()
    {
    Hashtable hashtable = new Hashtable();

    hashtable.Add(300, "Carrot");
    hashtable.Add("Area", 1000);
    return hashtable;
    }

    static void Main()
    {
    Hashtable hashtable = GetHashtable();

    string value1 = (string)hashtable[300];
    Console.WriteLine(value1);

    int value2 = (int)hashtable["Area"];
    Console.WriteLine(value2);
    }
}

выход

Carrot
1000

Этот код может выдавать исключения. Кастинг - деликатная операция. Если приведение было применено к другому типу, оператор может вызвать исключение InvalidCastException. Вы можете избежать этого, используя операторы is или as.

Cast Вы можете избежать проблем с использованием Hashtable. Вы можете использовать оператор as, чтобы попытаться привести объект к определенному ссылочному типу. Если приведение не выполнено, результат будет нулевым.

Null Совет: Вы также можете использовать оператор is. Этот оператор возвращает истину или ложь на основе результата.

Является Как Программа, которая генерирует значения Hashtable [C #]

using System;
using System.Collections;
using System.IO;

class Program
{
    static void Main()
    {
    Hashtable hashtable = new Hashtable();
    hashtable.Add(400, "Blazer");

    // This cast will succeed.
    string value = hashtable[400] as string;
    if (value != null)
    {
        Console.WriteLine(value);
    }

    // This cast won't succeed, but won't throw.
    StreamReader reader = hashtable[400] as StreamReader;
    if (reader != null)
    {
        Console.WriteLine("Unexpected");
    }

    // You can get the object and test it.
    object value2 = hashtable[400];
    if (value2 is string)
    {
        Console.Write("is string: ");
        Console.WriteLine(value2);
    }
    }
}

выход

Blazer строка: блейзер

С помощью Hashtable вы можете уменьшить количество приведений и повысить производительность с помощью оператора as. Это одно из предупреждений о производительности, которое выдает FxCop, инструмент статического анализа от Microsoft.

FxCop * Ключи, значения * Затем мы получаем все ключи или значения. Мы можем зациклить эти значения или сохранить их в отдельной коллекции ArrayList. В этом примере показаны все ключи, затем все значения, а затем сохранены ключи в ArrayList.

Примечание : Этот пример C # Hashtable использует свойство Keys. Это свойство возвращает все ключи.

Зацикливание ключей, значений и сохранение в ArrayList [C #]

using System;
using System.Collections;

class Program
{
    static void Main()
    {
    Hashtable hashtable = new Hashtable();
    hashtable.Add(400, "Blaze");
    hashtable.Add(500, "Fiery");
    hashtable.Add(600, "Fire");
    hashtable.Add(800, "Immolate");

    // Display the keys.
    foreach (int key in hashtable.Keys)
    {
        Console.WriteLine(key);
    }

    // Display the values.
    foreach (string value in hashtable.Values)
    {
        Console.WriteLine(value);
    }

    // Put keys in an ArrayList.
    ArrayList arrayList = new ArrayList(hashtable.Keys);
    foreach (int key in arrayList)
    {
        Console.WriteLine(key);
    }
    }
}

выход

800       (First loop)
600
500
400
Immolate  (Second loop)
Fire
Fiery
Blaze
800       (Third loop)
600
500
400

Цикл по клавишам. Первый цикл в программе перебирает коллекцию, возвращаемую свойством экземпляра Keys в экземпляре Hashtable. Вы можете использовать цикл foreach для самого простого синтаксиса.

Цикл по значениям. Второй цикл в программе показывает, как перечислять только значения в экземпляре Hashtable. Четыре слова, сохраненные в Hashtable как значения, будут напечатаны на экране.

Console.WriteLine Хранение в ArrayList. В этом примере создается новый ArrayList с конструктором копирования и передается ему свойство Keys (или Values) в качестве аргумента. После выполнения конструктора ArrayList список ArrayList может быть перечислен.

ArrayList

Подсказка : Публичные средства доступа Keys and Values ​​возвращают коллекцию ключей и значений в Hashtable во время их доступа.

Однако : Если вам необходимо просмотреть все ключи и значения в парах, лучше всего перечислить сам экземпляр Hashtable.

Подсчет, Очистить

Вы можете сосчитать элементы в Hashtable с помощью свойства Count. В примере также показано использование метода Clear для удаления всего содержимого Hashtable. Альтернатива - переназначить ссылку на Hashtable на новую Hashtable ().

Примечание : В этом примере показано, как использовать свойство Count. Это свойство возвращает количество элементов.

Программа, использующая Count на Hashtable [C #]

using System;
using System.Collections;

class Program
{
    static void Main()
    {
    // Add four elements to Hashtable.
    Hashtable hashtable = new Hashtable();
    hashtable.Add(1, "Sandy");
    hashtable.Add(2, "Bruce");
    hashtable.Add(3, "Fourth");
    hashtable.Add(10, "July");

    // Get Count of Hashtable.
    int count = hashtable.Count;
    Console.WriteLine(count);

    // Clear the Hashtable.
    hashtable.Clear();

    // Get Count of Hashtable again.
    Console.WriteLine(hashtable.Count);
    }
}

выход

4
0

Сначала программа добавляет четыре ключа с четырьмя значениями в экземпляр Hashtable. Затем он захватывает Count, который равен 4. Затем он использует Clear в Hashtable, который теперь имеет 0 элементов. Hashtable пуст, но не равен нулю.

Подсчитать свойство на Hashtable. Класс Hashtable реализует средство доступа к общедоступному экземпляру, которое возвращает количество элементов в Hashtable. Свойство Count не выполняет длительных вычислений или циклов.

Примечание : MSDN заявляет, что для Count «получение значения этого свойства является операцией O (1)».

Постоянное время. Это свойство является постоянным средством доступа. Он сообщит, что Hashtable имеет несколько фактических элементов в своих корзинах (или ноль). Возвращает целое число и является простым средством доступа с низкими требованиями к ресурсам.

Benchmark

Продолжая, мы проверяем коллекцию Hashtable в пространстве имен System.Collections с коллекцией Dictionary в пространстве имен System.Collections.Generic. Сначала эталонный тест заполняет эквивалентную версию каждой коллекции.

Тогда : Он проверяет один ключ, который найден, и тот, который не найден. Это повторяется 20 миллионов раз.

Hashtable используется в тесте [C #]

Hashtable hashtable = new Hashtable();
for (int i = 0; i < 10000; i++)
{
    hashtable[i.ToString("00000")] = i;
}

Dictionary used in benchmark [C#]

var dictionary = new Dictionary<string, int>();
for (int i = 0; i < 10000; i++)
{
    dictionary.Add(i.ToString("00000"), i);
}

Statements benchmarked [C#]

hashtable.ContainsKey("09999")
hashtable.ContainsKey("30000")

dictionary.ContainsKey("09999")
dictionary.ContainsKey("30000")

Тест 20 миллионов просмотров

Hashtable result:  966 ms
Dictionary result: 673 ms

Код Hashtable значительно медленнее, чем код Dictionary. Я считаю, что Hashtable здесь на 30% медленнее. Это означает, что для строго типизированных коллекций Словарь работает быстрее.

Конструкторы

В классе Hashtable есть 15 перегруженных конструкторов. Они предоставляют способы указать мощности. Они позволяют копировать существующие коллекции в Hashtable. Вы также можете указать способ вычисления хеш-кода.

Советы конструктора Краткое описание

Мы использовали коллекцию Hashtable. Это старая коллекция, которая устарела из коллекции Dictionary. Знание того, как его использовать, крайне важно при поддержке старых программ. Эти программы важны для многих организаций.

0 голосов
/ 07 апреля 2010

Какую версию Mono вы использовали? Это может быть ошибка в Mono, если так, отчет об ошибке будет приветствоваться.

Но да, я согласен с Севой в том, что, возможно, причина в некоторых конечных пробелах или разделителях или в какой-то другой проблеме кодирования, из-за которой строки отличаются тонким образом и приводят к разным хешам.

...