Лекция 11. Лекция 22. Классы прототипы, параметризованные коллекции
Скачать 70.5 Kb.
|
Лекция 22. Классы прототипы, параметризованные коллекцииМногие алгоритмы не зависят от типов данных, с которыми они работают. Например, такие алгоритмы как сортировка и поиск. Возможность отделить алгоритмы от типов данных предоставляют классы-прототипы, которые в литературе встречаются под названиями “шаблоны классов”, ” параметризованные классы”, ” обобщённые классы”. Классы прототипы имеют параметр – тип данных и поэтому еще называются параметризованными классами. Чаще всего эти классы применяются для хранения данных, то есть в качестве контейнерных классов или коллекций. Существуют “стандартные” классы прототипы, которые называются параметризованными коллекциями. Такие коллекции – это уже готовые шаблоны для различных структур данных – стеков, очередей, списков, бинарных деревьев и т.д. Эти коллекции хранятся в пространстве имён System.Collections.Generic. Во всех параметризованных коллекциях имеется так называемый параметр в качестве которого обычно выступает тип данных с которым работает эта коллекция. В качестве примера рассмотрим параметризованную коллекцию List <T>, которая является двойником обычной коллекции (семейства) ArrayList. Пример применения параметризованной коллекции List <T> using System.Collections.Generic; using MonsterLib; //описание классов Monster и Daemon смотри в предыдущих //лекциях – данные классы включены в библиотеку MonsterLib … static void Main(string[] args) { //объявление экземпляра коллекции List с параметром – типом данных – классом Monster List //добавление в коллекцию объектов класса Moster и производного от него Daemon mas.Add(new Monster ("Вася")); mas.Add(new Daemon("Демон", 3)); //вывод всех элементов в коллекции foreach (Monster x in mas) x.passport(); //объявление экземпляра коллекции List с параметром – типом данных – int List //добавление в коллекцию целых чисел masl.Add(5); masl.Add(1); //применение метода Sort() коллекции List для целых чисел masl.Sort(); //к элементам коллекции можно обратиться по индексу! int a = masl[0]; Console.WriteLine(a); //вывод всех элементов в коллекции foreach(int x in masl) Console.WriteLine( x+ ” ”); } В предложенном примере реализовано две коллекции на основе параметризованной коллекции List<Т>. Первая коллекция mas содержит список (аналог одномерного массива) экземпляров (объектов) классов типа Monster. В данной коллекции mas можно хранить элементы класса Monster, а также любого класса, производного от Monster. Другие типы данных в коллекции mas недопустимы. Существуют параметризованные коллекции с несколькими параметрами, как например, коллекция Dictionary В следующем примере демонстрируется применение параметризованной коллекции Dictionary Пример применения параметризованной коллекции Dictionary <T,K> В примере программы считывается содержимое текстового файла, считанный текст разбивается на слова и подсчитывается количество повторений каждого слова в тексте. В качестве ключей в примере используются слова, считанные из файла, а значения представляют собой целочисленные счетчики, которые увеличиваются на единицу, когда слово встречается очередной раз. using System.Collection.Generic; using System.IO; … static void Main(string[] args) { //файл должен существовать!!! StreamReader f = new StreamReader(@"d:\text.txt"); //считывание содержимого файла в одну строку string s = f.ReadToEnd(); //массив всех символов-разделителей слов char[] razdeliteli = { '.', ' ', ',', '!' }; //s.Split(raxdeliteli) – разделение строки на слова, используя разделители. Результат - массив строк(слов) slova List //mas – список с параметрами – слово и количество его вхождений, причем слова-это ключи, значения-счетчики вхождений Dictionary foreach (string w in slova) { //если в массиве по ключам(словам) слово встретилось впервые в //значение, соответствующее этому слову заносится 1, если слово //уже встречалось значение увеличивается на единицу //mas[w]-количество повторений слова w if (mas.ContainsKey(w)) mas[w]++; else mas[w] = 1; } //вывод всех слов в массиве mas по ключам foreach (string w in mas.Keys) Console.WriteLine("{0}\t{1}", w, mas[w]); Console.ReadKey(); } Создание класса-прототипа Язык С# позволяет создавать собственные классы-прототипы и их разновидности – интерфейсы, структуры, делегаты, события. Рассмотрим создание класса-прототипа на примере стека. Параметр типа данных, которые охраняться в стеке указывается угловых скобках после имени класса, а затем используется таким же образом, как и обычные типы. using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; namespace ConsoleApplication3 { class Program { public class Stack { int count; //количество элементов в стеке T[] items; //сами элементы стека int top; //вершина стека public int Count //свойство “количество” { get { return count; } set { if ((top > 0)&&(top <=count)) count = value; else Console.WriteLine("Error!!!"); } } public void InitStack() //первоначальное создание стека { Console.Write("Введите количество элементов стека: "); count=Convert.ToInt32(Console.ReadLine()); items = new T[count]; //выделяем память для массива элементов стека top = count; //первоначально вершина стека – в конце } public bool EndOfStack()//конец стека? { if (top == count) return true; else return false; } public void Push(T item)//помещение элемента в стек { if (top == 0) { Console.WriteLine("Error"); return; } else { items[top-1] = item; top = top - 1; } } public T Pop() //извлечение элемента из стека { if (top == count) { Console.WriteLine("Error"); } else top = top + 1; return items[top-1];} } static void Main(string[] args) { //При использовании класса-прототипа вместо параметра Т подставляется //конкретный тип данных //стек целых чисел Stack ints.InitStack(); for (int i = 0; i < ints.Count;i++ ) ints.Push(i); while(!ints.EndOfStack()) { int x = ints.Pop(); Console.WriteLine(x + " "); } //стек дробных чисел Stack double_s.InitStack(); for (double i = 0; i < double_s.Count; i++) double_s.Push(i); while (!double_s.EndOfStack()) { double y = double_s.Pop(); Console.WriteLine("{0:f}",y); } Console.ReadKey(); } }} Обобщенные(параметризованные) методы, ограничения на использование параметризованных типов Ограничения Класс-прототип может содержать произвольное число параметров типа. Для каждого параметра можно задать ограничения, указывающие каким требованиям должен удовлетворять аргумент, соответствующий этому параметру. Например, можно указать, что это юудет тип, использующий некоторый интерфейс (см.пример программы, приведенной ниже). Ограничения задаются после ключевого слова where, например: public class Stack where T:struct {…} Здесь задано ограничение, что класс стек может использовать элементы только значимого типа (типа структуры). Для ссылочного типанеобходимо использовать ключевое слово class. Указание в качетстве ограничений имени класса означает, что соответствующий параметр (аргумент) должен быть инициализирован или именем этого класса, либо его потомка. Обобщенные методы Иногда требуется иметь отдельный метод, параметризованный каким-либо типом данных. Примером такого метода может служить метод сортировки данных. В примере приведена сортировка методом выбора. Алгоритм ее состоит в том, что сначала выбирается наименьший элемент массива и меняется местами с первым элементом. Затем просматриваются элементы, начиная со второго, и наименьший из них меняется местами со вторым элементом и так далее. Всего произведено будет n-1 замен. На последнем проходе цикла при необходимости меняются местами предпоследний и последний элементы массива. using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication4 { class Program { Параметризованный (обобщенный) метод Sort с параметром- типом данных. На данный метод накладывается ограничение – объекты можно сравнивать друг с другом с помощью метода CompareTo static void Sort { T buf; int n = a.Length; for (int i = 0; i < n; i++) { int im = i; for (int j = i + 1; j < n; j++) if (a[j].CompareTo(a[im]) < 0) im = j; buf = a[i]; a[i] = a[im]; a[im] = buf; } } static void Main(string[] args) { int[] a = { 1, 6, 4, 2, 7, 5, 3 }; //вызов метода Sort с явным указанием параметра-типа Sort foreach (int x in a) Console.WriteLine(x); double[] b = { 1.1, 6.6, 4.4, 2.4, 7.6, 5.5, 3.3 }; //вызов метода Sort без указания параметра типа // компилятор по типу переданного параметра определяет какой тип //используется Sort(ref b); foreach (double x in b) Console.WriteLine(x); string[] s = { "sdef", "sd", "sdfsd", "sdf" }; Sort(ref s); foreach (string x in s) Console.WriteLine(x); Console.ReadKey(); } } } Преимущества использования параметризованных классов и методов: описывают способы хранения и алгоритмы обработки данных независимо от типов данных выполняют контроль типов во время компиляции, а не исполнения программы увеличивают скорость обработки данных за счет исключения операций преобразования, упаковки и распаковки типов. |