Учебное пособие (1077022), страница 15
Текст из файла (страница 15)
Этот механизм применяется в частности дляобработчиков событий в Windows Presentation Foundation.5.12 Контрольные вопросы к разделу 51. Что такое перечисление?2. Как получить значение перечисления на основе строки?3. Как реализуется перегрузка операторов в языке C#?4. Что такое индексатор?5. Как создать обобщенный класс в языке C#?6. Как создать обобщенный метод в языке C#?7. Что такое делегат?8. Что такое неявная типизация и как она используется дляделегатов?9. Как передать в метод параметр типа делегат?10.Что такое лямбда-выражения и как они используются?11.Что такое замыкания?12.Как реализованы локальные функции в языке C#?13.Что такое члены класса, основанные на выражениях?14.Как используется строковая интерполяция в языке C#?15.Как используется обобщенный делегат Func?16.Как применяется обобщенный делегат Action?17.Что такое групповой делегат?18.Как реализуется механизм событий в языке C#?6 Работа с коллекциямиКоллекции – важная часть любого языка программирования.
В языкеC# существует развитая система коллекций. В данном разделе сначаларассмотрены примеры использования стандартных коллекций, а затемпримеры создания нестандартных коллекций.1246.1 Стандартные коллекцииПодходы к работе с коллекциями в языках C++, Java и C# в целомсовпадают. Все коллекции можно разделить на две большие категории –обобщенные (шаблонизированные в С++) и необобщенные.Использование обобщенной коллекции предполагает, что в неепомещаются элементы обобщенного типа, следовательно все элементыколлекции должны быть одного и того же типа, который указывается присоздании обобщенной коллекции.
В соответствии с принципами ООП,вместо указанного обобщенного типа могут применяться производныетипы. Классы обобщенных коллекций находятся в пространстве именSystem.Collections.Generic.Использование необобщенной коллекции предполагает, что в неепомещаются элементы типа object – самого базового типа в иерархиитипов,азначит,необобщенныхэлементыколлекцийразличныхтипов.ОсновныеклассынаходятсявпространствеименSystem.Collections. Список основных классов коллекций приведен втаблице 6.Таблица 6Список основных классов коллекцийКоллекцияОбобщенныйНеобобщенныйклассклассСписокList<T>ArrayListСтекStack<T>StackОчередьQueue<T>QueueМножествоHashSet<T>–Ассоциативныйхранящиймассив, Dictionary<TKey,парыключ- TValue>значение.ТакуюструктуруназываютHashtable125также словарем или хэштаблицейОбобщенные коллекции на практике используются чаще, поэтому вшаблоне консольного приложения в Visual Studio по умолчаниюподключенопространствоименобобщенныхколлекцийSystem.Collections.Generic, а пространство имен необобщенных коллекцийSystem.Collections не подключено.
В случае необходимости его следуетдобавить вручную с помощью ключевого слова using.В таблице 6 приведены только основные коллекции. В .NETсуществуют десятки классов коллекций, в том числе различныеспециализированные, предназначенные для решения конкретных задач(например,битовыеколлекции),коллекциидлябезопасногомногопоточного доступа и т.д. Здесь они не рассмотрены.
Информация оних приведена в работах [1, 2].Далее рассмотрим работу со стандартными коллекциями на основефрагментов примера 10.6.1.1 Обобщенный списокРассмотрим пример работы с обобщенным списком. Создание объектасписка:List<int> li = new List<int>();Добавление элементов в список:li.Add(1);li.Add(2);li.Add(3);В версии языка C# 6 появился более удобный синтаксис дляинициализации списков:List<int> li1 = new List<int>{1,2,3};126List<string> li1_str = new List<string>{"строка 1","строка 2","строка 3"};Вывод элементов списка:foreach (int i in li){Console.WriteLine(i);}В данном примере в качестве класса-обобщения используется int,поэтому создается список целых чисел.
Преимущества примененияобобщенной коллекции состоят в том, что тип элемента известен как придобавлении, так и при выводе. При добавлении Visual Studio подсказываеттип добавляемого элемента с помощью механизма IntelliSense (рис. 19).Тип элемента уже известен, так как он был ранее указан при созданиисписка.Рис. 19. Работа IntelliSense для добавления в обобщенный список.При выводе с использование цикла foreach тип переменной i такжезаранее известен.Для обобщенного списка перегружен индексатор, который позволяетполучить элемент по его номеру в коллекции, элементы нумеруются снуля.
Пример:int item2 = li[1];Свойство Count возвращает количество элементов в коллекции:int count = li.Count;127Метод Contains позволяет проверить существование элемента вколлекции. В данном примере проверяется существование в коллекциичисла «3»:bool is3 = li.Contains(3);Метод Remove позволяет удалить элемент из коллекции, здесь изсписка удаляется число «2»:li.Remove(2);Основное преимущество стандартных коллекций языка C# состоит втом, что для их обработки может быть использован интегрированный языкзапросов LINQ.
Это чрезвычайно облегчает обработку сложных данных вC#.Ограничение рассмотренного примера заключается в том, что в такойсписок можно поместить только целые числа и нельзя – элементы другихтипов.Если в список необходимо сохранять элементы различных типов, томожно использовать необобщенный список.6.1.2 Необобщенный списокРассмотрим работу с необобщенным списком. Создание объектасписка:ArrayList al = new ArrayList();Добавление элементов различных типов в список:al.Add(333);al.Add(123.123);al.Add(«строка»);Вывод элементов списка:foreach (object o in al){//Для определения типа используется механизм рефлексииstring type = o.GetType().Name;if (type == «Int32»){Console.WriteLine(«Целое число: « + o.ToString());128}else if (type == «String»){Console.WriteLine(«Строка: « + o.ToString());}else{Console.WriteLine(«Другой тип: « + o.ToString());}}Преимущество необобщенного списка – возможность добавленияэлементов различных типов.Однако при чтении элементов возникает проблема, связанная с тем,что точно неизвестен тип элемента, который получен из списка, потомучто список возвращает элемент базового типа object.
Решить эту проблемуможно с использованием механизма рефлексии.Механизм рефлексии подробнее будет рассмотрен ниже, здесь жеиспользуется возможность получения информации о реальном типеэлемента, получаемого из списка. Вызов метода o.GetType() для объектавозвращает информацию о его типе данных, а свойство Name позволяетполучить строковое имя типа. Далее осуществляется ветвление построковому имени типа и выполняются различные действия в зависимостиот различных значений типа данных.6.1.3 Обобщенные стек и очередьСтек и очередь отличаются от списка в первую очередь тем, что здесьпроизводится не перебор элементов коллекции, а доступ к первому илипоследнему элементу коллекции.
Принцип работы стека и очереди показанна рис 20.129ЗаписьЗапись (Push)(Push)СтекСтек (Stack)(Stack)ЗаписьЗапись(Enqueue)(Enqueue)ЧтениеЧтение (Pop)(Pop)ЧтениеЧтение(Dequeue)(Dequeue)ОчередьОчередь (Queue)(Queue)ЗаписьЗаписьЗаписьЗаписьЧтениеЧтениеДекДек (deq)(deq)ЧтениеЧтениеРис. 20. Стек, очередь и дек.В случае стека (класс Stack) работа происходит с так называемойвершиной стека, которую условно можно считать первым или последнимэлементом списка данных.
Запись (Push) производится в вершину стека,чтение (Pop) также производится из вершины стека. При чтении элементавтоматически удаляется из стека. Стек реализует принцип работы LIFO(last in, first out – последний вошел, первый вышел).В случае очереди (класс Queue) запись (Enqueue) выполняется в конецочереди, а чтение (Dequeue) – из начала очереди. При чтении элементавтоматически удаляется из очереди. Очередь реализует принцип работыFIFO (first in, first out – первый вошел, первый вышел).Стек и очередь являются частным случаем структуры, которуюпринято называть дек (deq – double ended queue, двунаправленная очередь).В этом случае чтение и запись элементов могут проводиться с обоихконцов списка данных. В .NET не существует стандартного библиотечногокласса, реализующего дек.Рассмотрим работу со стеком.Создание стека:Stack<int> st = new Stack<int>();130Добавление элементов в стек:st.Push(1);st.Push(2);st.Push(3);В реализации стека для .NET возможен перебор элементов с помощьюforeach, хотя в классическом стеке такое действие предусматривать необязательно:foreach(int i in st){Console.WriteLine(i);}С использованием метода Peek возможно чтения элемента из вершиныстека без удаления (прочитанный элемент не удаляется из вершины стека):int i3 = q.Peek();С применением метода Pop выполняется чтение элемента из вершиныстека и его удаление:while (st.Count > 0){int i = st.Pop();Console.WriteLine(i);}Рассмотрим работу с очередью.Создание очереди:Queue<int> q = new Queue<int>();Добавление элементов в очередь:q.Enqueue(11);q.Enqueue(22);q.Enqueue(33);В реализации очереди для .NET возможен перебор элементов спомощью foreach:foreach (int i in q){Console.WriteLine(i);}С использованием метода Peek возможно чтения элемента из началаочереди без удаления:131int i3 = q.Peek();С применением метода Dequeue осуществляется чтение элемента изначала очереди и его удаление:while (q.Count > 0){int i = q.Dequeue();Console.WriteLine(i);}Результаты вывода в консоль для стека и очереди:Стек:Перебор элементов стека с помощью foreach:321Получение верхнего элемента без удаления:3Чтение с удалением элементов из стека:321Очередь:Перебор элементов очереди с помощью foreach:112233Получение первого элемента без удаления:11Чтение с удалением элементов из очереди:112233Необходимо отметить, что чтение данных из стека выполняется вобратном порядке (в соответствии с принципом LIFO), а чтение данных изочереди – в прямом (в соответствии с принципом FIFO).1326.1.4 Обобщенный словарьРабота со словарем отличается от работы со списком в основномтолько тем, что в словарь добавляются пары ключ-значение.В других языках программирования словарь могут также называтьассоциативным (или ассоциированным) массивом или хэш-таблицей.Создание объекта словаря:Dictionary<int, string> d = new Dictionary<int, string>();При создании словаря указывается два обобщенных типа – тип ключаи тип значения.Добавление элементов:d.Add(1, "строка 1");d.Add(2, "строка 2");d.Add(3, "строка 3");В версии языка C# 6 появился более удобный синтаксис дляинициализации словарей:Dictionary<int, string> d1 = new Dictionary<int, string>{[1] = "строка 1",[2] = "строка 2",[3] = "строка 3"};Вывод элементов:foreach (KeyValuePair<int, string> v in d){Console.WriteLine(v.Key.ToString() + "-" + v.Value);}При выводе элементов возникает проблема, связанная с тем, что вцикле foreach необходимо объявить тип данных, который содержит паруключ-значение, читаемые из словаря.















