Студопедия
Случайная страница | ТОМ-1 | ТОМ-2 | ТОМ-3
АрхитектураБиологияГеографияДругоеИностранные языки
ИнформатикаИсторияКультураЛитератураМатематика
МедицинаМеханикаОбразованиеОхрана трудаПедагогика
ПолитикаПравоПрограммированиеПсихологияРелигия
СоциологияСпортСтроительствоФизикаФилософия
ФинансыХимияЭкологияЭкономикаЭлектроника

Создание пользовательских обобщенных коллекций

Понятие автоматического указателя (auto_ptr) | Перегрузка операторов преобразования типа | Специализации шаблонов | Assert срабатывает только в режиме Debug | Потоки ввода-вывода | Автоматическое управление памятью ссылочных данных | Упаковка и разупаковка данных | Типы данных со значением null | Конструкторы и деструкторы | Частично определяемые классы и их назначение |


Читайте также:
  1. A. Создание персонажей
  2. I. Создание визитной карточки
  3. I. Создание информационного трехстраничного буклета
  4. I. Создание Энергетического и Духовного Тел
  5. MS PowerPoint. Создание слайда с диаграммой и таблицей
  6. MS PowerPoint. Создание управляющих кнопок
  7. VBA7. Сортировка чисел в столбце по возрастанию или убыванию с созданием формы и панели инструментов с кнопкой

Итак, пространство имен System.Collections.Generic предлагает множество типов, позволяющих создавать эффективные контейнеры, удовлетворяющие требованиям типовой безопасности. С учетом множества доступных вариантов очень велика вероятность того, что в.NET 2.0 у вас вообще не возникнет необходимости в построении пользовательских типов коллекции. Тем не менее, чтобы показать, как строится обобщенный контейнер, нашей следующей задачей будет создание обобщенного класса коллекции, который мы назовем CarCollection<T>.

Подобно созданному выше необобщенному типу CarCollection, наш новый вариант будет использовать уже существующий тип коллекции для хранения своих элементов (в данном случае это List<>). Будет реализована и поддержка цикла foreach путем реализации обобщенного интерфейса IEnumerable<>. Обратите внимание на то, что IEnumerable<> расширяет необобщенный интерфейс IEnumerable, поэтому компилятор ожидает, что вы реализуете две версии метода GetEnumerator(). Вот как может выглядеть соответствующая модификация.

public class CarCollection<T>: IEnumerable<T>{ private List<T> arCars = new List<T>(); public T GetCar(int pos) { return arCars[pos]; } public void AddCar(T c) { arCars.Add(c); } public void ClearCars() { arCars.Clear(); } public int Count { get { return arCars.Count; } } // IEnumerable<T> расширяет IEnumerable, поэтому // нужно реализовать обе версии GetEnumerator(). IEnumerator<T> IEnumerable<T>.GetEnumerator() { return arCars.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return arCars.GetEnumerator(); } }

Этот обновленный тип CarCollection<T> можно использовать так.

static void Main(string[] args){ Console.WriteLine("* Пользовательская обобщенная коллекция *\n"); // Создание коллекции объектов Car. CarCollection<Car> myCars = new CarCollection<Car>(); myCars.AddCar(new Car("Rusty", 20)); myCars.AddCar(new Car("Zippy", 90)); foreach (Car c in myCars) { Console.WriteLine("PetName: {0}, Speed: {1}", c.PetName, c.Speed); } Console.ReadLine(); }

При создании обобщенных методов для вас может оказаться сюрпризом появление ошибок компилятора, когда с параметрами типа используются операции C# (+, -, *, == и т.д.). Например, я уверен, вы сочли бы полезными классы Add(), Subtract(), Multiply() и Divide(), способные работать с обобщенными типами.

// Ошибка компиляции! // Нельзя применять операции к параметрам типа! public class BasicMath<T>{ public T Add(T arg1, T arg2) { return arg1 + arg2; } public T Subtract(T arg1, T arg2) { return arg1 - arg2; } public T Multiply(T arg1, T arg2) { return arg1 * arg2; } public T Divide(T arg1, T arg2) { return arg1 / arg2; } }

Как ни печально, этот класс BasicMath<T> не компилируется. Это может показаться большим ограничением, но не следует забывать, что обобщения являются обобщениями. Конечно, тип System.Int32 может прекрасно работать с бинарными операциями C#. Однако, если, например, <T> будет пользовательским классом или типом структуры, компилятор не сможет сделать никаких предположений о характере перегруженных операций +, -, * и /.

Перед рассмотрением обобщенных интерфейсов следует указать на то, что обобщенные классы могут быть базовыми для других классов и могут таким образом определять любое число виртуальных и абстрактных методов. Однако производные типы должны подчиняться определенным правилам, вытекающим из природы обобщенной абстракции. Во-первых, если обобщенный класс расширяется необобщенным, то производный класс должен конкретизироватьпараметр типа.

// Предположим, что создан пользовательский // обобщенный класс списка. public class MyList<T> { private List<T> listOfData = new List<T>();} // Конкретные типы должны указать параметр типа, // если они получаются из обобщенного // базового класса. public class MyStringList: MyList<string> {}

Кроме того, если обобщенный базовый класс определяет обобщенные виртуальные или абстрактные методы, производный тип должен переопределить эти обобщенные методы, используя конкретизированный параметр типа.

// Обобщенный класс с виртуальным методом. public class MyList<T>{ private List<T> listOfData = new List<T>(); public virtual void PrintList(T data) { } } public class MyStringList: MyList<string> { // В производных методах нужно заменить параметр типа, // используемый в родительском классе. public override void PrintList(string data) { } }

Если производный тип тоже является обобщенным, дочерний класс может (опционально) использовать заменитель типа в своем определении. Однако знайте, что любые ограничения, размещенные в базовом классе, должны “учитываться” и производным типом. Например:

// Обратите внимание, теперь здесь имеется ограничение, // требующее конструктор по умолчанию. public class MyList<T> where T: new(){ private List<T> listOfData = new List<T>(); public virtual void PrintList(T data) { } } // Производный тип должен учитывать ограничения базового. public class MyReadOnlyList<T>: MyList<T> where T: new(){ public override void PrintList(T data) { } }

Если вы только не планируете построить свою собственную библиотеку обобщений, вероятность того, что вам придется строить иерархии обобщенных классов, оказывается практически нулевой. Тем не менее, вы теперь знаете, что язык C# обеспечивает поддержку наследования обобщений.


Дата добавления: 2015-11-16; просмотров: 133 | Нарушение авторских прав


<== предыдущая страница | следующая страница ==>
Механизм вызова событий| Создание обобщенных интерфейсов

mybiblioteka.su - 2015-2024 год. (0.006 сек.)