|
Программирование >> Программирование с использованием ajax
Обобщения Одна из немногочисленных жалоб в отношении первой версии языка С# была связана с отсутствием поддержки обобщений (generics). Обобщения в языке С++ (называемые там шаблонами) давно считаются замечательным приемом, поскольку позволяют одному единственному определению типа разрастаться во множество специализированных типов во время компиляции и тем самым экономить огромное количество времени и усилий. По какой-то причине обобщения так и не вошли в первую версию языка С#, и он из-за этого пострадал. Возможно, так случилось потому, что обобщения часто находят довольно сложными для изучения, или может потому, что было решено, что они не столь уж необходимы. К счастью, начиная с версии С# 2.0, они стали доступными. Даже еще лучше то, что теперь их не очень трудно использовать, хотя для этого, конечно, все равно требуется взглянуть на вещи по-другому. В этой главе рассматриваются следующие темы. □ Что собой представляют обобщения. Сначала обобщения рассматриваются в относительно общих чертах, потому что изучение основных понятий является критически важным для эффективного использования обобщений. □ Как выглядят в действии некоторые из общедоступных типов, предлагаемых .NET Framework. Это поможет увидеть их функциональные возможности и мощь, а также новый синтаксис, который для них требуется использовать в коде. □ Как определять свои собственные обобщенные типы - обобщенные классы, интерфейсы, методы и делегаты, - и какие дополнительные приемы существуют для дальнейшей настройки обобщенных типов, вроде ключевого слова default и ограничениях типов. Что собой представляют обобщения Чтобы наилучшим образом проиллюстрировать, что собой представляют обобщения и почему они являются настолько полезными, вспомним классы коллекций из предыдущей главы. Там показывалось, как базовые коллекции могут содержаться в классах, вроде ArrayList, а также то, что такие коллекции страдают от отсутствия контроля типа, из-за чего требуется приводить элементы object к типу объектов, которые в действительности хранятся в коллекции. Поскольку в ArrayList могут храниться любые объекты, которые наследуются от System.Object (т.е. практически какие угодно), необходимо соблюдать осторожность. Предположение о том, что в коллекции содержатся объекты только определенных типов может заканчиваться генерацией исключений и разбиением логики кода. В предыдущей главе были показаны некоторые приемы, с помощью которых можно обходить подобные проблемы, включая и код, который нужно использовать для проверки типа объекта. Однако там же и выяснилось, что гораздо более эффективным решением является применение строго типизированной коллекции с самого начала. Путем наследования от класса CollectionBase и предоставления своихсобственных методов для добавления, удаления и получения доступа к членам коллекции можно ограничивать члены коллекции только теми, которые наследуются от определенного базового типа или поддерживают определенный интерфейс. Однако тут как раз и начинаются проблемы. При каждом создании нового класса, который должен содержаться в коллекции, требуется делать одно из описанных ниже действий. □ Использовать какой-нибудь созданный класс коллекции, который может содержать элементы нового типа. □ Создавать новый класс коллекции, способный хранить элементы нового типа и реализующий все требуемые методы. Обычно вместе с новым типом требуется и дополнительная функциональность, поэтому чаще всего нужно все равно создавать новый класс коллекции. Из-за всего этого подготовка классов коллекций может отнимать приличное время. Обобщенные классы, напротив, гораздо упрощают дело. Обобщенным классом называется такой класс, который создается вокруг типа или типов, каковые предоставляются во время создания экземпляра, и тем самым позволяет делать объект строго типизированным практически безо всяких усилий. В контексте коллекций процесс создания коллекции объектов типа Т выглядит так же просто, как звучит, и может осуществляться с помощью единственной строки кода. То есть вместо такого кода: CollectionClass col = new CollectionClass(); col.Add(new ItemClass()); можно использовать следующий код: CollectionClass<ItemClass> col = new CollectionClass<ItemClass> () ; col.Add(new ItemClass ()) ; Квадратные скобки в синтаксисе являются способом, которым обобщенным типам передаются типы переменных. В предыдущем коде, следовательно, CollectionClass<ItemClass> нужно читать как CollectionClass из ItemClass. Конечно, этот синтаксис еще будет более подробно рассматриваться позже в этой главе. Обобщения охватывают не только коллекции, но просто для них они подходят больше всего, как можно будет увидеть позже в этой главе при рассмотрении пространства имен System.Collections .Generic. За счет создания обобщенного класса можно генерировать методы с сигнатурой, позволяющей им становиться строго типизированными на базе любого типа, даже с учетом того, что этим типом может быть как тип-значение, так и ссылочный тип, и что придется иметь дело с особыми случаями. Можно даже делать допустимым только определенный набор типов путем ограничения типов, применяемых для создания экземпляра обобщенного класса, только теми, которые поддерживают конкретный интерфейс или наследуются от конкрет- ного типа. Более того, обобщенными классами дело не заканчивается: также можно создавать обобщенные интерфейсы, обобщенные методы (которые допускается определять и в не обобщенных классах) и даже обобщенные делегаты. Все это прибавляет коду гибкости, а раз так, разумное применение обобщений может экономить многие часы при его разработке. Наверняка у вас возник вопрос о том, как все это возможно. Обычно при создании класса он компилируется в тип, который затем можно использовать в своем коде. Вы можете подумать, что после создания обобщенный класс должен компилироваться в целую кучу типов, чтобы затем можно было создавать его экземпляры. К счастью, все происходит не так, а с учетом возможности создания в .NET практически бесконечного количества классов, и очень хорошо, что это не так. За кулисами исполняющая среда .NET позволяет обобщенным классам генерироваться динамически только тогда, когда в них возникает необходимость. Никакой обобщенный класс А для класса В не будет существовать до тех пор, пока вы не запросите его путем создания его экземпляра. Те кто, знаком с языком С++ или интересуется им, должны обратить внимание, что в этом как раз и состоит одно из отличий между шаблонами С++ и обобщенными классами С#. В С++ компилятор определяет, где в коде был использован шаблон специфического типа, например, шаблон А для класса В, и компилирует код, необходимый для создания такого типа. В С# все происходит во время выполнения. В целом, обобщения позволяют создавать гибкие типы, способные обрабатывать объекты одного и более специфических типов, определяются которые лишь при создании экземпляра обобщения или использовании его каким-то другим образом. Теперь пришла пора увидеть, как обобщения выглядят в действии. Использование обобщений Прежде чем рассказывать о том, как создавать свои собственные обобщения, не помешает ознакомиться с теми, которые поставляются в составе .NET Framework. Таковыми являются типы, доступные в пространстве имен System.Collections.Generic, которое уже несколько раз встречалось в коде, поскольку оно включается в состав консольных приложений по умолчанию. Использовать какие-либо из предлагаемых в этом пространстве имен типов пока не приходилось, но это скоро изменится. В настоящем разделе речь пойдет именно о типах в этом пространстве имен, а также о том, как их применять для создания строго типизированных коллекций и улучшения функциональных возможностей тех, что уже существуют. Первый делом, однако, будут рассмотрены другие, более простые обобщенные типы, позволяющие обходить уже упоминавшуюся ранее небольшую проблему с типами-значениями, а именно - нулевые типы (nullable types). Нулевые типы в предыдущих главах показывалось, что одним из отличий между типами-значениями (к числу которых относится большинство базовых типов, вроде int и double, а также структуры) и ссылочными типами (вроде string и любого класса) является то, что типы-значения должны обязательно содержать какое-то значение. Они могут существовать в состоянии без присвоенного значения в промежутке сразу же после их объявления и непосредственно перед присваиванием им значения, но пользоваться этим никак нельзя. В отличие от них, ссылочные типы могут быть нулевыми (т.е. принимать значение null).
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |