Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
DiVM / OSISP / ОCиСП-Часть3 / Теория / Теория (ОСиСП).doc
Скачиваний:
29
Добавлен:
11.05.2015
Размер:
616.96 Кб
Скачать

Шаблоны в с# (появились недавно в .Net 2.0)

Шаблоны – это способ обобщенного программирования.

Пример:

public class Stack<T> // в < > указываются параметры, Т – тип параметров

{ // Stack – обобщенный класс

private T [ ] items; // объявляем массив

int current;

public void Push( T data)

{

current ++ ;

items[current] = data;

}

public T Pop( )

{

T result = items[current];

current --;

return result;

}

}

Класс Stack предназначен для работы со стеком некоторых объектов, тип которых заранее неизвестен. Шаблоны в С# отличаются от шаблонов С++ тем, что шаблоны в С++ - это большая макроподстановка. При использовании шаблона

(например,

Stack<Control> S = new Stack<Controls> (),

где Stack – это префикс, а Control – суффикс, с которым работает шаблон)

компилятор выполняет макроподстановку. В С++ компилятор подставит тип Control. Это делается на этапе компиляции программы:

  1. При этом если в шаблоне есть синтаксическая ошибка, то о ее существовании узнаем только при создании объекта, использующего шаблон.

  2. У шаблона некоторые компиляторы компилируют не весь шаблон сразу, а только использованные методы (это в С++), т.е. будет проверена корректность синтаксиса конструктора. Для проверки синтаксиса метода необходимо его вызвать:

S.Push();

  1. Создание, объявление в разных .cpp модулях новых реализаций класса Stack<Control> S2 в С++ приводит к созданию двух одинаковых реализаций шаблонов. Они будут в разных объектных модулях, и линкер должен «догадаться», что это один и тот же шаблон, но он не всегда их воспринимает как одну реализацию.

  2. Из шаблона в С++ сделать dll- библиотеку нельзя, т.к. конкретная реализация шаблона будет дублироваться.

  3. Как правило, в программах используется много ссылочных типов данных, и если есть ссылочные объекты, то ссылка – это указатель. В С++ если пишем Stack<Control>… , а у Control-a есть наследник Button : Stack<Button> S2, то линкер не догадается, что это одно и то же. Но физически эти классы абсолютно эквивалентны, т.е. будет дублирование одной и той же реализации класса.

Button

C++: Stack <Control *> stack;

C# : Stack <Control> stack = new Stack <Control>;

Если в контейнере есть объекты ссылочных типов, то есть автоматическое преобразование типов.

При использовании шаблонов в С++ нельзя указать при объявлении шаблона, какие требования предъявляются к типу данных, которые выступают в качестве параметра.

Например, если в С++ объявлен шаблон:

template <class T> calss Stack

{

T* current;

void DoSomething

{

current -> DoSomething( );

}

}

Только на этапе компиляции программы, которая создают экземпляр шаблонного класса, параметризованный конкретным типом, происходит компиляция кода метода DoSomething, и только на этапе компиляции проверяется, что в объекте есть этот метод. Никаких средств указать: а что должен поддерживать класс T при параметризации для разработчика не предоставляется.

Если в программе где-то написать stack.DoSomething(), то будет ошибка ERROR Compilation.

В C# шаблоны доработаны. По сути это совсем другие шаблоны.

Пример:

public class Dictionary <K,V> where K: IComparable,IEnumerable

{

public V Find (K key)

{

for (int 0; i< Keys.Length; ++i)

if (key.CompareTo(Keys[i]) == 0)

return Values[i];

return null;

}

}

K – параметризация типом ключа

V – параметризация типом значения

where – ключевое слово, с помощью которого можно определить дополнительные ограничения (у нас K: IComparable – тип, передаваемый в шаблон, должен поддерживать интерфейс IComparable IEnumerable)

т.к. используется метод CompareTo, то мы написали поддержку интерфейса IComarable.

При создании экземпляра шаблона:

Dictionary <string, Control> dict = …

сразу идёт проверка компилятором того, поддерживает ли string интерфейс IComparable.

( CompareTo возвращает: -1, если A1<A2

0, если A1=A2

1, если A1>A2)

Основные изменения коснулись эффективности использования:

  1. в С++ шаблоны нельзя было помещать в модули. В С# шаблоны компилируются, располагаются в .cs файлах, компилируется и создаётся библиотека шаблонов, она содержит код порождения классов, т.е. библиотека генерирует программный код.

При генерации происходит обращение к библиотеке с запросом на генерацию программного кода с нужными параметрами. Если такой класс уже генерировался, то он не генерируется, а даётся ссылка на уже сгенерированный.

Если захватывается экземпляр класса, у которого параметры являются ссылочными, то библиотека возвращает один и тот же экземпляр класса для всех ссылочных аргументов независимо от их типа. Физическая реализация для параметров ссылочного типа всегда одна и та же.

Для размерных типов библиотека порождения создаёт новый экземпляр класса, который реализует шаблон. Причём реализация получается эффективной, т.к. шаблонный класс содержит в себе динамический массив элементов. Тип данных шаблона – тип элемента. Для ссылочных типов – это массив ссылок, для размерных типов– это массив структур.

В Java нет разделения на ссылочные и размерные типы, и если есть динамический массив, то это всегда массив указателей. Также шаблоны в Java отличаются от шаблонов в C# ещё и тем, что в C# информация о шаблонах помещается в метаданные. С помощью метаинформации можно узнать, какие шаблоны есть в библиотеке и с какими параметрами.

В Java после компиляции в программе шаблона не остаётся.