Все классы (и структуры) наследуют один тип 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. За базовыми класса |