#net #словари
Предыстория: Все мы прекрасно знакомы со стандартным типом Dictionary, а также его свойством, что при попытке доступа к элементу по несуществующему ключу будет создано исключение KeyNotFoundException. Это привычно для всех и подобное поведение ожидаемо для словаря значений Недавно же я разбирал один код, который выдавал NullReferenceException там, где его по логике вещей быть не могло. Отдебажив его, я обнаружил следующую вещь: Человек использовал в своем коде StringDictionary (к слову, весьма радует, ибо я знаю внушающее количество .NET программистов, которые ни разу не заглядывали в System.Collections.Specialized) и забыл поставить проверку на существование строки по указанному ключу, тем самым словарь молча возвращал null и чуть позже код падал, так как строки со значением null должны были отсутствовать внутри словаря и проверка на это не подразумевалась В случае со стандартным Dictionary и созданием указанного выше исключения эту ошибку отловить было бы куда проще, однако у StringDictionary немного иная "идеология", так что по несуществующему ключу он возвращает null (который, к слову, без вызова метода ContainsKey неотличим от существующей по указанному ключу строки с null-значением) Собственно, сам вопрос: Почему при проектировании StringDictionary отошли от архитектуры привычного всем словаря и вместо логичного выброса соответствующего исключения сделали просто возвращение null? Мне кажется, что подобное решение должно быть подкреплено какими-то серьезными фактами. Из моих догадок: так как StringDictionary создан для быстрого (O(1)) поиска строк в словаре, то есть скорость в данном случае критична, то выбросом исключений решили пренебречь, так как это не самая быстрая операция) Однако это лишь моя догадка, хотелось бы услышать Ваше мнение/увидеть ссылки по данному вопросу)
Ответы
Ответ 1
Все гораздо проще - Specialized - это рудимент до-генериковского .net 1.1. Генерик-реализация Dictionary не может возвращать null для несществующих значений - она должна работать и с reference types, и с value types, причем работать одинаково. Вернуть же null для value type несоколько затруднительно. На момент появления генериков классы из Specialized активно использовались, и их поведение сохранили ради совместимости. В современном проекте единственая причина для работы с Specialized - это необходимость интеграции с legacy кодом. Они не реализуют новых генерик интерфейсов, они ведут себя странно и непредсказуемо (например, StringDictionary приводит ключи к lowercase), и они могут быть медленее новых генериков даже на базовых операциях, например: [Benchmark] public StringDictionary StringDictionary() { StringDictionary stringDictionary = new StringDictionary(); foreach (var i in Enumerable.Range(0, 1000000)) { stringDictionary[i.ToString()] = i.ToString(); } return stringDictionary; } [Benchmark] public DictionaryNewDictionary() { var stringDictionary = new Dictionary (); foreach (var i in Enumerable.Range(0, 1000000)) { stringDictionary[i.ToString()] = i.ToString(); } return stringDictionary; } Method | Mean | Error | StdDev | ----------------- |---------:|---------:|---------:| StringDictionary | 694.0 ms | 5.631 ms | 5.268 ms | NewDictionary | 280.2 ms | 5.369 ms | 5.022 ms |
Комментариев нет:
Отправить комментарий