В C# ассоциативные массивы как таковые отсутствуют. Вместо них используются словари.
Словарь это экземпляр класса Dictionary. Данные в нём хранятся в виде пары «ключ» (TKey) – «значение» (TValue). Доступ к конкретному «значению» осуществляется по соответствующему «ключу». Данный класс является обобщённым и поэтому как в качестве ключа, так и в качестве значения могут использоваться данные самых различных типов.
Рассмотрим работу со словарём на примере простой и всем известной игры «Крестики-Нолики».
Допустим, на форме имеются девять элементов управления Label и по умолчанию в них отображается дефис «-». При клике мышью, в зависимости от того чей ход, текст отображаемый в конкретном Label будет изменяться на «X» или «0» соответственно.
Создадим закрытое поле, которое будет хранить последний ход. При инициализации присвоим ему значение «0». То, есть первый ход будет у «X».
Далее создадим словарь, который будет на текущем ходу менять текст в Label в зависимости от последнего хода, и заполним его соответствующими значениями. При этом, «ключ» — последний ход, а «значение» — текущий ход.
Сразу отметим, что игра разрабатывается на WPF.
1 2 3 4 5 6 7 8 9 10 11 |
private string _recent; private Dictionary<string, string> _dict; ... public MainWindow() { InitializeComponent(); _recent = "0"; _dict = new Dictionary&lt;string, string&gt;(); _dict.Add("X", "0"); _dict.Add("0", "X"); } |
К сожалению, добавить данные в словарь в C# ниже 5.0 можно только с помощью метода Add. В версии 5.0 наконец-то появилась возможность инициализировать словарь уже заполненный данными.
1 2 3 4 5 |
_dict = new Dictionary<string, string> { {"X","0"}, {"0","X"} }; |
Начиная с C# 6.0, стал доступен ещё один способ инициализации.
1 2 3 4 5 |
_dict = new Dictionary<string, string> { ["X"] = "0", ["0"] = "X" }; |
Теперь реализуем саму логику ходов.
Для этого создадим обработчик события MouseDown. В нём реализуем проверку на соответствие содержимого Label значению по умолчанию, чтобы в данном Label можно было выполнить ход только один раз. Сам ход представляет собой получение значения из словаря по ключу, которым в свою очередь является предыдущий ход. После выполнения хода текущий ход сохраняется в качестве предыдущего.
Для лучшего понимания приведём код обработчика с применением словаря.
1 2 3 4 5 6 7 8 |
private void label_MouseDown(object sender, MouseButtonEventArgs e) { if (((Label)sender).Content.ToString() == "-") { ((Label)sender).Content = _dict[_recent]; _recent = ((Label)sender).Content.ToString(); } } |
А, также код обработчика без его использования.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
private void label_MouseDown(object sender, MouseButtonEventArgs e) { if (((Label)sender).Content.ToString() == "-") { if (_recent == "X") { ((Label)sender).Content = "0"; } else { ((Label)sender).Content = "X"; } _recent = ((Label)sender).Content.ToString(); } } |
Очевидно, что использование словаря позволило значительно упростить логику программы. Поэтому, несмотря на определённые издержки связанные с инициализацией, словарь является идеальным решением в случае, если необходимо вернуть те или иные фиксированные данные в соответствии с некоторым «ключевым» значением.
В то же время это решение идеально лишь для узкого круга специфических задач.
Из словаря можно получить только фиксированные значения. Вычисления в зависимости от значения «ключа» по аналогии с оператором switch не возможны. Также невозможно задать значение по умолчанию. Если данный «ключ» отсутствует в словаре, будет выброшено исключение.
Поэтому словари следует использовать только в качестве хранилища данных по принципу «ключ»-«значение» (key-value) или в качестве замены ассоциативных массивов.
Добавить комментарий