Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Books / 3_C#_2005_для_чайников_(Дэвис-2008)

.pdf
Скачиваний:
86
Добавлен:
24.03.2015
Размер:
15.46 Mб
Скачать

Все классы (и структуры) наследуют один тип O b j e c t , сказано об этом яв но или нет. Вы можете перекрывать методы O b j e c t . С практической точки зрения единственный метод, который вы можете захотеть перекрыть — это метод T o S t r i n g ( ) , позволяющий объекту создавать строковое представле­ ние информации о самом себе. Если вы не реализуете собственный метод T o S t r i n g ( ) , то метод по умолчанию класса O b j e c t вернет полное имя класса, например MyNamespace . M y C l a s s . Обычно в этом мало толку.

Пример применения структуры

 

Следующая демонстрационная программа иллюстрирует различные воз­

 

можности структур:

 

 

 

 

 

 

/ / S t r u c t u r e E x a m p l e - д е м о н с т р а ц и я р а з л и ч н ы х с в о й с т в

 

/ / с т р у к т у р н о г о о б ъ е к т а

 

 

 

 

 

 

u s i n g

S y s t e m ;

 

 

 

 

 

 

 

 

 

 

u s i n g S y s t e m . C o l l e c t i o n s ;

 

 

 

 

 

 

n a m e s p a c e S t r u c t u r e E x a m p l e

 

 

 

 

 

 

{

 

 

 

 

 

 

 

 

 

 

 

 

p u b l i c i n t e r f a c e

I D i s p l a y a b l e

 

 

 

 

 

s t r i n g T o S t r i n g ( ) ;

 

 

 

 

 

 

 

/ / С т р у к т у р а

может

р е а л и з о в ы в а т ь

и н т е р ф е й с

 

 

 

p u b l i c s t r u c t T e s t

:

I D i s p l a y a b l e

 

 

 

 

{

 

 

 

 

 

 

 

 

 

 

 

 

/ /

С т р у к т у р а

может

и м е т ь

члены

к а к

о б ъ е к т а ,

т а к

и

к л а с с а

/ /

( с т а т и ч е с к и е ) ;

с т а т и ч е с к и е

члены

м о г у т и м е т ь

 

 

/ / и н и ц и а л и з а т о р ы

 

 

 

 

 

 

 

p r i v a t e

i n t n ;

 

 

 

 

 

 

 

 

p r i v a t e s t a t i c d o u b l e d = 2 0 . 0 ;

 

 

 

 

//

Для

и н и ц и а л и з а ц и и ч л е н о в - д а н н ы х

с т р у к т у р ы

может

 

/ / и с п о л ь з о в а т ь с я к о н с т р у к т о р

 

 

 

 

 

p u b l i c T e s t ( i n t n )

 

 

 

 

 

 

 

{

 

 

 

 

 

 

 

 

 

 

 

 

 

t h i s . n =

n ;

 

 

 

 

 

 

 

 

 

}

 

 

 

 

 

 

 

 

 

 

 

 

/ /

С т р у к т у р а

может

и м е т ь

с в о й с т в а к а к о б ъ е к т а ,

т а к

и

/ / к л а с с а

( с т а т и ч е с к и е )

 

 

 

 

 

 

p u b l i c

i n t

N

 

 

 

 

 

 

 

 

 

{

 

 

 

 

 

 

 

 

 

 

 

 

g e t { r e t u r n n ; } s e t { n = v a l u e ;

p u b l i c s t a t i c d o u b l e D

{

330

Часть V. За базовыми классами

g e t { r e t u r n d;

}

s e t { d = v a l u e ; }

}

 

 

// С т р у к т у р а

может

и м е т ь методы

p u b l i c v o i d

C h a n g e M e t h o d ( i n t nNewValue,

d o u b l e dNewValue)

{

n = n N e w V a l u e ; d = d N e w V a l u e ;

}

// T o S t r i n g - п е р е к р ы т и е м е т о д а T o S t r i n g О и р е а л и з а ц и я / / и н т е р ф е й с а I D i s p l a y a b l e

o v e r r i d e p u b l i c

s t r i n g T o S t r i n g ( )

 

 

 

 

{

 

 

 

 

 

 

 

 

 

 

 

r e t u r n s t r i n g . F o r m a t ( " ( { 0 : N } ,

{ l : N } ) ' \

n , d ) ;

 

p u b l i c c l a s s P r o g r a m

 

 

 

 

 

 

{

 

 

 

 

 

 

 

 

 

 

 

p u b l i c

s t a t i c v o i d M a i n ( s t r i n g [ ]

a r g s )

 

 

 

{

 

 

 

 

 

 

 

 

 

 

 

/ / С о з д а н и е о б ъ е к т а T e s t

 

 

 

 

 

 

T e s t

t e s t

=

new T e s t ( 1 0 ) ;

 

 

 

 

 

 

C o n s o l e . W r i t e L i n e ( " Н а ч а л ь н о е з н а ч е н и е t e s t " ) ;

 

O u t p u t F u n c t i o n ( t e s t ) ;

 

 

 

 

 

 

//

Попытка

м о д и ф и ц и р о в а т ь

о б ъ е к т ,

п е р е д а в а я

е г о

в

/ / к а ч е с т в е а р г у м е н т а

 

 

 

 

 

 

C h a n g e V a l u e F u n c t i o n ( t e s t ,

1 0 0 ,

2 0 0 . 0 ) ;

 

 

 

C o n s o l e . W r i t e L i n e ( " З н а ч е н и е t e s t п о с л е в ы з о в а " +

 

 

 

 

 

 

" C h a n g e V a l u e F u n c t i o n ( 1 0 0,

2 0 0 . 0 ) " ) ;

O u t p u t F u n c t i o n ( t e s t ) ;

 

 

 

 

 

 

//

Попытка

м о д и ф и ц и р о в а т ь

о б ъ е к т ,

п е р е д а в а я

е г о

в

/ / к а ч е с т в е а р г у м е н т а

 

 

 

 

 

 

C h a n g e R e f e r e n c e F u n c t i o n ( r e f t e s t ,

1 0 0 ,

2 0 0 . 0 ) ;

 

C o n s o l e . W r i t e L i n e ( " З н а ч е н и е t e s t п о с л е в ы з о в а " +

 

 

 

 

 

" C h a n g e R e f e r e n c e F u n c t i o n ( 1 0 0 ,

2 0 0 . 0 ) " ) ;

O u t p u t F u n c t i o n ( t e s t ) ;

 

 

 

 

 

 

//

Метод

может

м о д и ф и ц и р о в а т ь

о б ъ е к т

 

 

 

t e s t . C h a n g e M e t h o d ( 1 0 0 0 , 2 0 0 0 . 0 ) ;

 

 

 

 

C o n s o l e . W r i t e L i n e ( " З н а ч е н и е t e s t п о с л е в ы з о в а " +

 

 

 

 

 

 

" C h a n g e M e t h o d ( 1 0 0 0 , 2 0 0 0 . 0 ) " ) ;

O u t p u t F u n c t i o n ( t e s t ) ;

 

 

 

 

 

 

/ /

Ожидаем

п о д т в е р ж д е н и я

п о л ь з о в а т е л я

 

 

 

C o n s o l e . W r i t e L i n e ( " Н а ж м и т е < E n t e r > д л я " +

 

 

 

 

 

 

 

" з а в е р ш е н и я п р о г р а м м ы . . . " ) ;

 

Глава 14. Интерфейсы и структуры

331

C o n s o l e . R e a d ( ) ;

}

// C h a n g e V a l u e F u n c t i o n - п е р е д а ч а с т р у к т у р ы

по

значению j

p u b l i c s t a t i c v o i d C h a n g e V a l u e F u n c t i o n ( T e s t

t ,

 

i n t n e w V a l u e , d o u b l e

dNewValue)

{

t . N =

newValue,-

 

 

T e s t . D = d N e w V a l u e ;

 

 

}

 

 

 

// C h a n g e R e f e r e n c e F u n c t i o n - п е р е д а ч а с т р у к т у р ы по

/ / с с ы л к е

 

 

p u b l i c

s t a t i c v o i d C h a n g e R e f e r e n c e F u n c t i o n ( r e f T e s t t ,

 

i n t n e w V a l u e ,

d o u b l e dNewValue)

{

 

 

 

t . N = n e w V a l u e ;

 

 

T e s t . D = dNewValue;

 

 

}

 

 

 

// O u t p u t F u n c t i o n - вывод информации об

о б ъ е к т е ,

который

/ / р е а л и з у е т м е т о д T o S t r i n g ( )

 

 

p u b l i c s t a t i c v o i d O u t p u t F u n c t i o n ( I D i s p l a y a b l e i d )

{

 

 

 

C o n s o l e . W r i t e L i n e ( " i d = { o } " , i d . T o S t r i n g ( ) ) ;

 

} }

 

 

 

}

 

 

 

Программа

S t r u c t u r e E x a m p l e сначала определяет

интерфейс

IDisplayableJ

а затем простую структуру T e s t , которая реализует этот интерфейс. T e s t также опре- деляет два члена — член экземпляра п и статический член d. Статический инициализа- тор устанавливает член d равным 20; инициализатор для члена п не разрешен.

Структура T e s t определяет конструктор, свойство экземпляра N и статическое свой

ство D.

 

T e s t также определяет собственный метод C h a n g e M e t h o d ()

и перекрывает метод!

T o S t r i n g ( ) . Предоставлением метода T o S t r i n g () структура

T e s t реализует ин-

терфейс I D i s p l a y a b l e .

 

Функция Main () создает объект t e s t вне локальной памяти и использует конструктор для инициализации выделенной ему памяти. Затем M a i n () вызывает функцию Out- p u t F u n c t i o n () для вывода объекта.

Далее функция Main () вызывает функцию C h a n g e V a l u e F u n c t i o n ( ) , передавая ей t e s t с двумя числовыми константами. Функция C h a n g e V a l u e F u n c t i o n () при­ сваивает эти значения членам п и d структуры T e s t . После возврата из функции C h a n g e V a l u e F u n c t i o n () вызывается функция O u t p u t F u n c t i o n ( ) , которая по­ зволяет убедиться, что значение d изменилось, а значение п — нет.

Вызов C h a n g e V a l u e F u n c t i o n () получает объект t e s t по значению, так что объ­ ект t в теле этой функции представляет собой копию исходного объекта t e s t , а не сам объект. Таким образом, присваивание t. N изменяет локальную копию и никак не влияет на объект t e s t e функции M a i n ( ) . Однако все объекты структуры T e s t совместно ис-

332 Часть V. За базовыми классам»

пользуют статический член d, так что присваивание T e s t . D изменяет d для всех объек­ тов, включая t e s t .

Следующей вызывается функция ChangeRef e r e n c e F u n c t i o n ( ) , которая выгля­ дит в точности как и функция C h a n g e V a l u e F u n c t i o n ( ) , за исключением использо­ вания в списке аргументов ключевого слова r e f . Это ключевое слово обеспечивает пе­ редачу объекта t e s t e функцию по ссылке, так что объект t в функции является ссыл­ кой на исходный объект t e s t , а не вновь созданной копией.

Последним вызовом в M a i n () является вызов метода C h a n g e M e t h o d ( ) , всегда ис­ пользующий передачу текущего объекта по ссылке, поэтому изменения, сделанные при вызове этого метода, сохраняются при возврате в Main ( ) .

Вывод программы имеет следующий вид:

Начальное з н а ч е н и е

t e s t

 

id = ( 1 0 . 0 0 , 2 0 . 0 0 )

 

 

Значение

t e s t

п о с л е

в ы з о в а

C h a n g e V a l u e F u n c t i o n ( 1 0 0 , 2 0 0 . 0 )

id = ( 1 0 . 0 0 , 2 0 0 . 0 0 )

 

 

Значение

t e s t

п о с л е

в ы з о в а

C h a n g e R e f e r e n c e F u n c t i o n ( 1 0 0 , 2 0 0 . 0 )

id = ( 1 0 0 . 0 0 , 2 0 0 . 0 0 )

 

Значение

t e s t

п о с л е

в ы з о в а

C h a n g e M e t h o d ( 1 0 0 0 , 2 0 0 0 . 0 )

id = (1,000 . 00 ,

2 , 000 . 00)

 

Нажмите

< E n t e r >

д л я

з а в е р ш е н и я п р о г р а м м ы . . .

Структуры и классы имеют одну общую черту: и те и другие порождены из класса Object, указано ли это явно или нет. Этот факт унифицирует различные типы перемен­ ных в одну всеобъемлющую иерархию классов.

Предопределенные типы структур

Схожесть структур и простых типов-значений не только внешняя. В действительно­

сти простые типы-значения являются структурами.

Например,

i n t —

просто

другое

имя структуры I n t 3 2 , d o u b l e — другое имя

структуры

D o u b l e

и так

далее.

В табл. 14.1 приведен полный список типов и соответствующих имен структур.

 

Таблица 14.1. Имена структур для встроенных типов-значений

Имя типа

Имя структуры

 

 

bool

Boolea n

byte

Byte

sbyte

SByte

char

Char

decimal

Decimal

double

Double

float

S i n g l e

int

I n t 3 2

uint

UInt32

Глава 14. Интерфейсы и структуры

333

Окончание табл. HI

Тип s t r i n g является ссылочным, а не типом-значением, поэтому для негоне существует соответствующей структуры. Вместо этого тип s t r i n g соответст­ вует классу S t r i n g . Тип s t r i n g в С# особенный и обладает рядом свойств, присущих структурам. Более детально он рассматривается в главе 9, "Работаю строками в С#".

Унификация системы типов с помощью структур

Тип i n t — другое имя для I n t 3 2 . Поскольку все структуры порождены от класса O b j e c t , i n t также не должен быть исключением. Это приводит к очень интересным результатам, которые демонстрирует приведенная ниже программа.

// T y p e U n i f i c a t i o n - д е м о н с т р а ц и я т о г о , ч т о i n t и I n t 3 2 в

// д е й с т в и т е л ь н о с т и

 

одно

и

то же,

и ч т о

они порождены от

/ / к л а с с а O b j e c t

 

 

 

 

 

 

 

 

 

 

u s i n g S y s t e m ;

 

 

 

 

 

 

 

 

 

 

 

n a m e s p a c e T y p e U n i f i c a t i o n

 

 

 

 

 

 

 

{

 

 

 

 

 

 

 

 

 

 

 

 

 

 

p u b l i c

c l a s s

P r o g r a m

 

 

 

 

 

 

 

 

{

 

 

 

 

 

 

 

 

 

 

 

 

 

 

p u b l i c

s t a t i c v o i d M a i n ( s t r i n g [ ]

a r g s )

 

 

 

{

 

 

 

 

 

 

 

 

 

 

 

 

 

 

/ /

С о з д а е м i n t

и и н и ц и а л и з и р у е м

е г о

нулем

 

 

i n t

i

=

new

i n t ( ) ;

/ / Д а ,

т а к

можно

д е л а т ь

 

//

П р и с в а и в а е м

ему

з н а ч е н и е

1 и

выводим при

помощи

/ / и н т е р ф е й с а I F o r m a t t a b l e , к о т о р ы й р е а л и з у е т I n t 3 2

i

=

1;

 

 

 

 

 

 

 

 

 

 

 

 

O u t p u t F u n c t i o n ( i ) ;

 

 

 

 

 

 

 

 

II

К о н с т а н т а

2

также

р е а л и з у е т

I F o r m a t t a b l e

 

O u t p u t F u n c t i o n ( 2 ) ;

 

 

 

 

 

 

 

 

//

В д е й с т в и т е л ь н о с т и

вы можете

даже

в ы з в а т ь

м е т о д

/ / к о н с т а н т ы

 

 

 

 

 

 

 

 

 

 

C o n s o l e . W r i t e L i n e ( " Н е п о с р е д с т в е н н ы й

вывод

=

{ о } " ,

 

 

 

 

 

 

 

3 . T o S t r i n g ( ) ) ;

 

 

 

 

 

//

Это

может

быть

п о л е з н ы м ,

н а п р и м е р ,

д л я

выбора

/ / ц е л о г о з н а ч е н и я и з с п и с к а :

 

 

 

 

 

334

Часть V. За базовыми классами

C o n s o l e . W r i t e L i n e ( " \ п В ы б и р а е м и з с п и с к а ц е л ы е " ) ;

o b j e c t [ ] o b j e c t s

=

new o b j e c t [ 5 ] ;

 

o b j e c t s [ 0 ]

= " э т о с т р о к а " ;

 

o b j e c t s [ 1 ] = 2;

 

 

 

 

o b j e c t s [ 2 ]

=

new

P r o g r a m ( ) ;

 

o b j e c t s [ 3 ] = 4;

 

 

 

 

o b j e c t s [ 4 ] = 5 . 5 ;

 

 

 

 

f o r ( i n t i n d e x = 0 ; i n d e x < o b j e c t s . L e n g t h ; i n d e x + + )

{

 

 

 

 

 

 

 

 

i f ( o b j e c t s [ i n d e x ]

i s

i n t )

 

 

{

 

 

 

 

 

 

 

i n t n = ( i n t ) o b j e c t s [ i n d e x ] ;

 

 

C o n s o l e . W r i t e L i n e ( " Э л е м е н т { о } — { l } " , i n d e x , n ) ;

 

}

 

 

 

 

 

 

}

 

 

 

 

 

 

 

//

Унификация

т и п о в

п о з в о л я е т в ы в о д и т ь

т и п ы - з н а ч е н и я и

// с с ы л к и , не р а з л и ч а я их

 

C o n s o l e . W r i t e L i n e ( " \ п В ы в о д в с е х о б ъ е к т о в и з с п и с к а " ) ;

i n t n C o u n t = 0;

 

 

 

 

f o r e a c h ( o b j e c t

о

i n o b j e c t s )

 

{

 

 

 

 

 

 

 

 

C o n s o l e . W r i t e L i n e ( " O b j e c t s [ { o } ] - < { l } > " ,

 

n C o u n t + + , o . T o S t r i n g ( ) ) ;

 

}

 

 

 

 

 

 

 

//

Ожидаем

п о д т в е р ж д е н и я

п о л ь з о в а т е л я

 

C o n s o l e . W r i t e L i n e ( " Н а ж м и т е < E n t e r > д л я " +

 

 

 

 

" з а в е р ш е н и я п р о г р а м м ы . . . " ) ;

C o n s o l e . R e a d ( ) ;

 

 

 

 

// O u t p u t F u n c t i o n

- вывод

п р о и з в о л ь н о г о

о б ъ е к т а ,

// реализующего

T o S t r i n g ()

 

 

p u b l i c s t a t i c v o i d O u t p u t F u n c t i o n ( I F o r m a t t a b l e i d )

C o n s o l e . W r i t e L i n e ( " З н а ч е н и е и з O u t p u t F u n c t i o n = { о } " , i d . T o S t r i n g ( ) ) ;

}

// T o S t r i n g - п р о с т а я o v e r r i d e p u b l i c s t r i n g

с т р о к о в а я функция T o S t r i n g ( )

{

r e t u r n " T y p e U n i f i c a t i o n P r o g r a m " ;

Функция Main () начинается с создания объекта i типа i n t . В ней используется конструктор по умолчанию I n t 3 2 О (можно просто написать i n t О ) , который ини­ циализирует переменную i нулевым значением. Далее программа присваивает перемен­ ной i значение 1. Это несколько отличается от формата, используемого при создании структуры.

Глава 14. Интерфейсы и структуры

335

Функция Main () передает переменную i функции O u t p u t F u n c t i o n (), которая явлена как принимающая объект, реализующий интерфейс I F o r m a t t a b l e . Интерфейсом I F o r m a t t a b l e похож на интерфейс I D i s p l a y a b l e , который определялся в других про граммах. Единственным методом интерфейса I F o r m a t t a b l e является метод ToStrirqj Функция O u t p u t F u n c t i o n () выводит объект I F o r m a t t a b l e с использование строки, возвращаемой его методом T o S t r i n g ( ) . У переменной I n t 3 2 , которая реал зует этот метод, не возникает никаких проблем. Но самое интересное, что никаких про блем не возникает и при вызове O u t p u t F u n c t i o n ( 2 ) . Поскольку константа 2 имеет тип I n t 3 2 , она также реализует интерфейс I F o r m a t t a b l e . И наконец, фунция

Main ()

вызывает 3. T o S t r i n g () непосредственно. Вывод этой части функции

Main ()

имеет следующий вид:

З н а ч е н и е

из

O u t p u t F u n c t i o n = 1

З н а ч е н и е

из

O u t p u t F u n c t i o n = 2

Н е п о с р е д с т в е н н ы й вывод = 3

Далее функция Main() объявляет массив объектов типа O b j e c t и сохраняет в первом элементе массива s t r i n g , во втором— i n t , в третьем— экземпляр класса Program и т.д. Все это можно сделать, так как S t r i n g , I n t 3 2 и P r o g r a m порождены от Object.Итак массив внутри класса P r o g r a m хранит экземпляр P r o g r a m — правда, это интересно?

Затем программа проходит по всем элементам массива. Функция Main() мо жет выбрать из него все целые числа, запрашивая каждый объект, ЯВЛЯЕТСЯ ли он I n t 3 2 с помощью ключевого слова i s . Вывод этой части программы выглядит следующим образом:

Выбираем и з с п и с к а целые

Элемент

1 — 2

Элемент

3 — 4

Программа завершается демонстрацией использования того факта, что все подклассы Obj e c t — т.е. все классы — реализуют метод T o S t r i n g ( ) . Таким образом, чтобы вы вести все члены массива объектов, вам не надо беспокоиться об их типах. Функция M a i n () просто вновь проходит по массиву, вызывая метод T o S t r i n g () для каждого его элемента. В результате программа выводит на экран следующую информацию:

Вывод

в с е х

о б ъ е к т о в

и з

с п и с к а

 

 

 

 

O b j e c t s

[0]

-

о т о

с т р о к а >

 

 

 

 

O b j e c t s [ 1 ]

-

<2>

 

 

 

 

 

 

 

 

O b j e c t s [ 2 ]

- < T y p e U n i f i c a t i o n P r o g r a m >

 

 

O b j e c t s [ 3 ]

-

<4>

 

 

 

 

 

 

 

 

O b j e c t s [ 4 ]

- < 5 . 5 >

 

 

 

 

 

 

 

Нажмите

< E n t e r >

д л я

з а в е р ш е н и я

п р о г р а м м ы . . .

 

 

Для

класса P r o g r a m

реализован тривиальный

метод T o S t r i n g ( ) , просто чтобы

показать, как это работает.

 

 

 

 

 

 

 

 

Свойство T o S t r i n g ( ) , несомненно, поясняет

магию функции

Console.

 

 

W r i t e ( ) . Честно говоря, даже не смотря исходный текст, можно

поспорить,

 

 

что W r i t e ()

принимает аргументы как принадлежащие типу O b j e c t . Затем

 

 

она

просто вызывает

метод T o S t r i n g ()

для получения выводимой строки,

 

 

которая

подставляется вместо

соответствующего

элемента форматирования

 

 

{п}

в первой строке.

 

 

 

 

 

336

Часть V. За базовыми классами

Упаковка типов-значений

Что действительно делает ссылочные типы и типы-значения наподобие i n t , b o o l , char и любой структуры гражданами С# первого сорта — так это технология, назы­ ваемая упаковкой (boxing). Во многих ситуациях компилятор временно конвертирует объекты типов-значений в ссылочные объекты. Упаковка означает перемещение части данных типа-значения в объект ссылочного типа в куче. Вот пример, в котором вы­

полняется упаковка:

 

 

 

 

int i

=

9 9 9 ;

//

П р о с т о й

i n t

( т и п - з н а ч е н и е )

object

о

= i;

//

Помещаем

i в

ссылочную у п а к о в к у

int j

=

( i n t ) о;

//

Получаем

99 9

из у п а к о в к и

Все, что было упаковано, рано или поздно потребует распаковки, которая влечет за собой приведение типа. В демонстрационной программе T y p e U n i f i c a t i o n каждое присваивание o b j e c t требовало упаковки, а обратное преобразование переменной ob­ ject — распаковки.

Обе операции требуют определенного времени. Упаковка до 20 раз продолжительнее обычного присваивания, а распаковка — до 4 раз. Кроме того, упаковка требует допол­ нительной памяти для размещения объекта в куче, так что большое количество упаковок может снизить производительность вашей программы. Упаковка во многих ситуациях выполняется автоматически, включая такие ситуации, как передача аргумента, возврат значения из функции, присваивание, работа с массивами o b j e c t [ ] , вызовы W r i t e ­ Line () и многое другое. По возможности избегайте упаковки — например, вызовами ToString () для значений, передаваемых W r i t e L i n e ( ) , избегая работы с массивами object и используя новые обобщенные коллекции, рассматривающиеся в главе 15, "Обобщенное программирование".

ими классами

[лава 14. Интерфейсы и структуры

Глава 15

Обобщенное программирование

Коллекционирование: преимущества и проблемы Экономия времени и кода с помощью обобщенных коллекций

Написание собственных обобщенных классов, методов и интерфейсов

# предоставляет массу специализированных альтернатив массивам, о которых речь шла в главе 6, "Объединение данных — классы и массивы". В этой главе I будут рассмотрены списки, стеки, очереди и другие "массивоподобные" классы кол­

лекций, такие как универсальный A r r a y L i s t , который может использоваться для решения множества программистских задач. В отличие от массивов, эти коллекции не являются безопасными с точки зрения типов и могут вызвать определенные на­ кладные расходы.

Однако можно сохранить массу времени и усилий, если воспользоваться обобщенной вер­ сией. Обобщенные классы6 (generics) — новая возможность С#, появившаяся в версии 2.0. Обобщенные классы представляют собой классы, методы и интерфейсы, в которых поля ти­ пов остаются незаполненными. Чтобы понять, о чем идет речь, рассмотрим конкретный при­ мер. Так, класс L i s t < T > определяет обобщенный список, очень похожий на A r r a y L i s t . Когда вы используете этот список для создания {инстанцирования) собственного списка, на­ пример чисел типа i n t , вы заменяете параметр типа Т конкретным типом i n t :

List<int> m y L i s t = new L i s t < i n t > () ; // Список ч и с е л т и п а i n t

Универсальность такого списка состоит в том, что вы можете инстанцировать List<T> для любого единого типа данных — s t r i n g , S t u d e n t , B a n k A c c o u n t — и при этом получить такую же безопасность типов, как у массива, причем без лишних за­ трат. Это — супермассив.

Обобщенные классы в С# могут быть встроенными, такими как L i s t < T > , и пользо­ вательскими, т.е. написанными вами. После чтения этой главы вы научитесь писать соб­ ственные обобщенные классы не хуже встроенных.

°Здесь следует сделать небольшое пояснение. Дело в том, что это новая для С# возможность,

апотому русскоязычная терминология еще не устоялась. В С++, в котором обобщенное программи­ рование было реализовано существенно раньше, обобщенные, или универсальные классы, называют­ ся шаблонами. В С# такие классы именуются generic class, или просто generic. В русскоязычной лите­ ратуре встречаются такие переводы, как обобщенные классы, универсальные классы и даже термин "дженерик". В данной книге будет использоваться термин "обобщенные классы". — Примеч. ред.

Чтобы понять, что такое обобщенные классы и что в них хорошего, давайте начнем рассмотрения обычных классов-коллекций.

Массивы обеспечивают быстрый и эффективный доступ к произвольным ментам. Но зачастую массивы не удовлетворяют вашим требованиям из-за их недостатков.

Программа должна объявить размер массива при его создании. В отличие от Vi ual Basic, С# не позволяет изменять размер массива после его определения! делать, если вы не знаете заранее, массив какого размера вам потребуется?

Вставка или удаление элемента из середины массива весьма неэффективна, 1 должны сдвинуть все элементы, чтобы освободить память.

Для решения этих проблем С# предоставляет ряд необобщенных коллекций в качаз) ве альтернатив массивам. Каждая из коллекций имеет свои сильные и слабые стороны.

Необобщенные коллекции

С# предоставляет ряд хорошо спроектированных альтернатив массивам. В табл. lil описаны несколько наиболее полезных необобщенных коллекций. Вне сомнения, пол характеристикам вы всегда сможете выбрать подходящий класс для решения стояи перед вами задачи (но не спешите — еще немного, и вы познакомитесь с обобщена ми классами).

340

Часть V. За базовыми класса