ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание
Шрифт:
Работа с типом Stack
Тип System.Collections.Stack представляет коллекцию, в которой элементы размещаются по правилу "последним прибыл – первым обслужен". Как и следует ожидать, Stack определяет члены с именами Push и Pop (для добавления элементов в стек и удаления их из стека). В следующем примере стека используется стандартный тип System.String.
Здесь строится стек, содержащий три строковых типа (названных в соответствии с порядком их вставки). "Заглядывая" в стек, вы видите элемент, находящийся на вершине стека, поэтому первый вызов Peek выявляет третью строку. После серии вызовов Pop и Peek стек, в конечном счете, опустошается, и тогда дополнительный вызов Peek/Pop приводит к генерированию системного исключения.
Исходный код. Проект CollectionTypes размещен в подкаталоге, соответствующем главе 7.
Пространство имен System.Collections.Specialized
Кроме типов, определенных в пространстве имен System.Collections, библиотеки базовых классов .NET предлагают набор более специализированных типов, определенных в пространстве имен System.Collections.Specialized. Например, типы StringDictionary и ListDictionary обеспечивают "стилизованную" реализацию интерфейса IDictionary. Описания основных типов класса из этого пространства имен предлагаются в табл. 7.5.
Таблица 7.5. Типы пространства имен System.Collections.Specialized.
Тип | Описание |
---|---|
CollectionsUtil | Создает коллекции, игнорирующие регистр символов в строках |
HybridDictionary | Реализует IDictionary, используя ListDictionary, пока коллекция мала, и переключаясь на Hashtable, когда коллекция становится большой |
ListDictionary | Реализует IDictionary, используя однонаправленный список. Рекомендуется для коллекций, которые содержат не более десятка элементов |
NameValueCollection | Представляет отсортированную коллекцию связанных ключей и значений типа String, которые могут быть доступны или по ключу, или по индексу |
StringCollection | Представляет коллекцию строк |
StringDictionary | Реализует Hashtable с ключом, строго типизированным, как строка, а не объект |
StringEnumerator | Поддерживает простой цикл по элементам StringCollection |
Резюме
Интерфейс можно определить, как именованную коллекцию абстрактных членов. Ввиду того, что интерфейс не предлагает деталей реализаций, он обычно рассматривается, как, вариант поведения, возможного для данного типа. При реализации одного и того же интерфейса в нескольких классах вы получаете возможность обращаться с соответствующими типами одинаково (это называется интерфейсным полиморфизмом).
Для определения новых
интерфейсов в C# предлагается ключевое слово interface. Любой тип может поддерживать столько интерфейсов, сколько необходимо, нужно только указать их в списке определения типа, разделяя запятыми. При этом можно создавать интерфейсы, которые оказываются производными нескольких базовых интерфейсов.Помимо возможности создания пользовательских интерфейсов, вы имеете возможность использовать ряд стандартных интерфейсов, определенных в библиотеках .NET (т.е. предлагаемых каркасом приложений). Вы можете строить пользовательские типы, реализующие эти встроенные интерфейсы, чтобы обеспечить выполнение ряда стандартных действий, таких как клонирование, сортировка или перечисление. Наконец, в этой главе вы узнали о классах коллекций, определенных в пространстве имен System.Collections, и изучили ряд общих интерфейсов, которые используются связанными с коллекциями типами.
ГЛАВА 8. Интерфейсы обратного вызова, делегаты и события
До этого момента в нашей книге в каждом примере приложении программный код Main тем или иным способом направлял запросы соответствующим объектам. Но мы пока что не рассматривали возможность обратного обращения объекта к вызывающей стороне. В большинстве программ типичным для объектов системы оказывается двухсторонняя коммуникация, которая реализуется с помощью интерфейсов обратного вызова, событий и других программных конструкций. Эта глава начинается с рассмотрения того, как с помощью типов интерфейса реализовать функциональные возможности обратного вызова.
Затем вы узнаете о типе делегата .NET, который является объектом, обеспечивающим типовую безопасность и "указывающим" на метод или методы, которые могут быть вызваны позднее. Но, в отличие от традиционного указателя на функцию в C++, делегаты .NET представляют собой объекты, которые имеют встроенную поддержку многоадресного и асинхронного вызова методов. Мы рассмотрим асинхронное поведение типов делегата позже, при изучении пространства имен System.Threading (см. главу 14).
Выяснив, как создавать типы делегата и работать с ними, мы с вами рассмотрим ключевое слово C# event, которое призвано упростить и ускорить работу с типами делегата. Наконец, в этой главе будут рассмотрены новые возможности языка C#, связанные с использованием делегатов и событий, включая анонимные методы и групповые преобразования методов, Вы увидите, что указанный подход открывает более короткий путь к целевым объектам соответствующих событий.
Интерфейсы обратного вызова
При рассмотрении материала предыдущей главы вы имели возможность убедиться, что интерфейсы определяют доведение, которое может поддерживаться самыми разными типами. Кроме использований интерфейсов для поддержки полиморфизма, их можно использовать и в качестве механизма обратного вызова. Соответствующий подход дает объектам возможность осуществлять двухсторонний обмен, используя общее множество членов.
Чтобы показать варианты использования интерфейсов обратного вызова, мы изменим уже знакомый нам тип Car так, чтобы он мог информировать вызывающую сторону о приближении поломки машины (т.е. о том, что текущая скорость на 10 км/ч ниже максимальной скорости) и о свершившейся поломке (когда текущая скорость равна или выше максимальной скорости). Способность посылать и принимать соответствующие события будет реализована с помощью интерфейса, носящего имя IEngineEvents.
Интерфейсы событий обычно реализуются не объектом, непосредственно "заинтересованным" в получении событий, а некоторым вспомогательным объектом, который называется объектом-приемником. Отправитель событий (в данном случае это тип Car) при определенных условиях выполняет для приемника соответствующие вызовы. Предположим, что класс приемника называется CarEventSink, и он просто выводит поступающие сообщения на консоль. Кроме того, наш приемник содержит строку, в которой указано его информативное имя.