Файл: Лекция 22. Классы прототипы, параметризованные коллекции.doc

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 10.01.2024

Просмотров: 23

Скачиваний: 1

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

Лекция 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 mas = new List();

//добавление в коллекцию объектов класса Moster и производного от него Daemon

mas.Add(new Monster ("Вася"));

mas.Add(new Daemon("Демон", 3));

//вывод всех элементов в коллекции

foreach (Monster x in mas) x.passport();

//объявление экземпляра коллекции List с параметром – типом данных – int

List masl = new 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 slova = new List(s.Split(razdeliteli));

//mas – список с параметрами – слово и количество его вхождений, причем слова-это ключи, значения-счетчики вхождений

Dictionary mas = new 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 = new 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 = new 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(ref T[] a) where T : IComparable

{

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(ref a);

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();

}

}

}

Преимущества использования параметризованных классов и методов:

  • описывают способы хранения и алгоритмы обработки данных независимо от типов данных

  • выполняют контроль типов во время компиляции, а не исполнения программы

  • увеличивают скорость обработки данных за счет исключения операций преобразования, упаковки и распаковки типов.