Как исправить ошибку с установкой словаря, чувствительного к неправильному регистру?

Как исправить ошибку с установкой словаря, чувствительного к неправильному регистру?
Как исправить ошибку с установкой словаря, чувствительного к неправильному регистру? - pawel_czerwinski @ Unsplash

Я заметил одну ошибку в кодировании (при использовании .Net). Вы объявляете класс данных, который должен иметь поле словаря (или get/set Property), назовем его для примера 'Properties'. У него есть строковый тип ключа.

    public System.Collections.Generic.Dictionary<string, object> Properties { get; set; }

Возможно, мы захотим использовать его как обычный класс данных. Таким образом, мы можем десериализовать JSON или строки SQL или что-то еще, чтобы заполнить словарь свойств. По счастливой случайности, наш сериализатор JSON понимает тип словаря и может сделать это довольно хорошо. НО (и тут возникает проблема...) в нашей бизнес-логике мы хотим, чтобы этот словарь не учитывал регистр при обработке ключей.

"Хорошо, нет проблем", - скажете вы. "Словари могут это делать. Каждый раз, когда мы пишем код, инициализирующий словарь класса, мы будем делать вот так:

    Properties = new Dictionary<string, object>(StringComparer.InvariantCultureIgnoreCase)

Видите ли вы проблему в этом? Потому что мы поместили туда публичный сеттер. Любой может вызвать этот сеттер словаря и поместить в наш объект словарь с учетом регистра. И Мерфи уверяет нас, что так оно и будет; не из дурных побуждений, конечно, но потому что слишком легко забыть необязательный параметр StringComparer в Dictionary.

И что еще хуже, у нас есть код, который нам не принадлежит, в нашем десериализаторе JSON или фреймворке отображения объектов, который не удосуживается использовать StringComparer. Или, возможно, он просто выбирает неправильный, например, StringComparer.CurrentCultureIgnoreCase или OrdinalIgnoreCase. Это явно катастрофа, которая только и ждет, чтобы произойти. Что же нам делать?

Видите ли вы проблему в этом? Потому что мы поместили туда публичный сеттер.

Так что не надо публичного сеттера.

Создайте новый класс CaseInsensitiveDictionary, который содержит приватный Dictionary, инициализированный с нечувствительностью к регистру. Выставляйте этот приватный Dictionary только через методы для взаимодействия с ним (например, add, remove и т.д.) - или предоставляйте только get доступ к нему. Вы, вероятно, захотите реализовать IEnumerable, IDictionary и другие интерфейсы.

public sealed class CaseInsensitiveDictionary<string,TValue>
{
    private Dictionary<string, TValue> _dictionary = new Dictionary<string, object>(StringComparer.InvariantCultureIgnoreCase);
   // ... constructors, add, remove, etc methods
}

Везде, где вы используете Dictionary сейчас, замените его на этот новый класс. Если вам нужно обрабатывать десериализацию JSON и т.д., вы можете предоставить методы для этого в новом классе.

Это похоже на то, что делается в .NET framework - например, Dictionary vs SortedList - новый класс создается, когда необходимо ограничение (упорядочивание).


LetsCodeIt, 24 марта 2023 г., 21:06