ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 11.12.2025
Просмотров: 3224
Скачиваний: 1
/ / |
P a s s B y R e f e r e n c e - |
/ / |
п е р е д а ч и а р г у м е н т а |
u s i n g S y s t e m ;
п р о г р а м м а д л я д е м о н с т р а ц и и с е м а н т и к и п о с с ы л к е
n a m e s p a c e |
P a s s B y V a l u e |
{ |
|
p u b l i c |
c l a s s P r o g r a m |
{
/ / U p d a t e - ф у н к ц и я п ы т а е т с я м о д и ф и ц и р о в а т ь з н а ч е н и я / / а р г у м е н т о в , п е р е д а н н ы е е й ; о б р а т и т е в н и м а н и е , н а / / п е р е д а ч у а р г у м е н т о в к а к r e f и o u t
p u b l i c |
s t a t i c v o i d U p d a t e ( r e f i n t |
i , o u t d o u b l e d ) |
|
{ |
|
|
|
i |
= |
1 0 ; |
|
d |
= |
2 0 . 0 ; |
|
} |
|
|
|
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 = |
1 ; |
d o u b l e |
d ; |
C o n s o l e . W r i t e L i n e ( " П е р е д в ы з о в о м " + |
|
|
" U p d a t e ( r e f i n t , o u t d o u b l e ) : " ) ; |
C o n s o l e . W r i t e L i n e ( " i = " + i + |
|
|
" , d н е и н и ц и а л и з и р о в а н а " ) ; |
/ / В ы з ы в а е м ф у н к ц и ю
' U p d a t e ( r e f i , o u t d ) ;
/ / О б р а т и т е в н и м а н и е — з н а ч е н и е i р а в н о 1 0 , з н а ч е н и е d / / р а в н о 2 0 . 0
C o n s o l e . W r i t e L i n e ( " П о с л е в ы з о в а "
" U p d a t e ( r e f i n t , o u t d o u b l e ) : " ) , - C o n s o l e . W r i t e L i n e ( " i = " + i + ", d = " + d ) ;
/ / О ж и д а е м п о д т в е р ж д е н и я п о л ь з о в а т е л я
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 ( ) ;
Ключевое слово r e f указывает С#, что в функцию следует передать ссылку на i, а не просто значение этой переменной. Следовательно, изменения, выполненные с этой переменной, оказываются экспортированы обратно вызывающей программе.
Подобно этому, ключевое слово o u t говорит: "Передай ссылку на эту переменную, но можешь никак не заботиться о ее значении, поскольку оно все равно не будет исполь зоваться и будет перезаписано в процессе работы функции". Это ключевое слово годится тогда, когда переменная применяется исключительно для того, чтобы вернуть значение вызывающей программе.
158 |
Часть III. Объектно-основанное программирование |
Выполнение рассмотренной программы P a s s B y R e f е г е п с е приводит к следующе
му выводу на экран: |
|
|
|
|
|
|||
Перед |
вызовом |
U p d a t e ( r e f |
i n t , |
|
o u t d o u b l e ) |
: |
||
i = 1, d н е и н и ц и а л и з и р о в а н а |
|
|
|
|||||
После |
вызова |
U p d a t e |
( r e f |
i n t , |
o u t d o u b l e ) |
: |
||
i = 10, |
d = 20 |
|
|
|
|
|
||
Нажмите |
< E n t e r > д л я |
з а в е р ш е н и я |
п р о г р а м м ы . . . |
|||||
|
Аргумент, передаваемый как o u t , всегда считается передаваемым так же как |
|||||||
|
ref, т.е. писать |
r e f o u t — это |
тавтология. Кроме того, при передаче аргу |
|||||
|
ментов по ссылке вы должны |
всегда передавать только переменные — переда |
||||||
|
ча литеральных значений, например просто числа 2 вместо переменной типа |
|||||||
|
i n t , в этом случае приводит к ошибке. |
|
||||||
Обратите внимание, что начальные значения i и d переписываются в функции Up dated . После возврата в функцию M a i n () эти переменные остаются с измененными в функции U p d a t e () значениями. Сравните это поведение с программой P a s s B y Value, где внесенные изменения не сохраняются при выходе из функции.
Не передавайте переменную по ссылке дважды
Никогда не передавайте по ссылке одну и ту же переменную дважды в одну функцию, поскольку это может привести к неожиданным побочным эффек там. Описать эту ситуацию труднее, чем просто продемонстрировать при мер программы. Внимательно взгляните на функцию U p d a t e () в приве денном листинге.
// |
PassByRef e r e n c e E r r o r |
- д е м о н с т р а ц и я |
п о т е н ц и а л ь н о |
|||||
/ / |
ошибочной |
с и т у а ц и и |
п р и в ы з о в е ф у н к ц и и с |
п е р е д а ч е й |
||||
// а р г у м е н т о в по с с ы л к е |
|
|
|
|||||
using S y s t e m ; |
|
|
|
|
|
|
||
namespace |
P a s s B y R e f e r e n c e E r r o r |
|
|
|
||||
{ |
|
|
|
|
|
|
|
|
p u b l i c c l a s s |
P r o g r a m |
|
|
|
|
|||
{ |
|
|
|
|
|
|
|
|
|
/ / U p d a t e - э т а ф у н к ц и я п ы т а е т с я и з м е н и т ь з н а ч е н и я |
|||||||
|
/ / п е р е д а н н ы х е й а р г у м е н т о в |
|
|
|
||||
|
p u b l i c |
s t a t i c |
v o i d |
D i s p l a y A n d U p d a t e ( r e f |
i n t |
n V a r l , |
||
|
|
|
|
|
|
r e f |
i n t |
n V a r 2 ) |
|
{ |
|
|
|
|
|
|
|
|
C o n s o l e . W r i t e L i n e ( " Н а ч а л ь н о е з н а ч е н и е n V a r l - " + |
|||||||
|
|
|
|
|
n V a r l ) ; |
|
|
|
|
n V a r l |
= |
1 0 ; |
|
|
|
|
|
|
C o n s o l e . W r i t e L i n e ( " Н а ч а л ь н о е з н а ч е н и е n V a r 2 - " + |
|||||||
|
|
|
|
|
n V a r 2 ) ; |
|
|
|
|
n V a r 2 |
= |
2 0; |
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
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 ) |
|
|
|
|
{ |
|
|
|
|
|
|
|
Глава 7. Функции функций |
159 |
/ / О б ъ я в л я е м и и н и ц и а л и з и р у е м п е р е м е н н у ю
i n t |
п = 1 ; |
|
|
|
|
|
C o n s o l e . W r i t e L i n e ( " П е р е д в ы з о в о м " + |
|
|||||
|
|
" U p d a t e ( r e f |
n , |
r e f |
n ) : " ) ; |
|
C o n s o l e . W r i t e L i n e ( " n = " + n ) ; |
|
|
||||
C o n s o l e . W r i t e L i n e ( ) ; |
|
|
|
|
||
/ / В ы з ы в а е м ф у н к ц и ю |
|
|
|
|
||
D i s p l a y A n d U p d a t e ( r e f n , |
r e f |
n ) ; |
|
|
||
/ / О б р а т и т е в н и м а н и е н а т о , |
к а к и з м е н я е т с я з н а ч е н и е п |
|||||
/ / - н е т а к , |
к а к о ж и д а л о с ь о т э т о й п е р е м е н н о й и |
|||||
/ / ф у н к ц и и , |
в к о т о р у ю о н а б ы л а п е р е д а н а |
|||||
C o n s o l e . W r i t e L i n e ( ) ; |
|
|
|
|
||
C o n s o l e . W r i t e L i n e ( " П о с л е в ы з о в а " |
+ |
|
||||
|
|
" U p d a t e ( r e f |
n , |
r e f |
n ) : " ) ; |
|
C o n s o l e . W r i t e L i n e ( " n = " + n) ; |
|
|
||||
/ / |
О ж и д а е м п о д т в е р ж д е н и я |
п о л ь з о в а т е л я |
|
|||
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 ( ) ; |
|
|
|
|
||
} |
|
|
|
|
|
|
} |
|
|
|
|
|
|
В этом примере функция U p d a t e ( r e f |
i n t , r e f |
i n t ) |
объявлена как функцию |
|||
с двумя целыми аргументами, передаваемыми по ссылке — ив этом нет ничего некор ректного или необычного. Проблема возникает тогда, когда в функцию передается одна
ита же переменная как в качестве первого, так и второго аргумента. Внутри функции происходит изменение переменной n V a r l , которая ссылается на переменную п, от ее
начального значения 1 до значения 10. Затем происходит изменение переменной nVar которая тоже ссылается на переменную п, от ее начального значения 1 до значения 20:
ипобочное действие заключается в том, что переменная п теряет ранее присвоенное значение 10 и получает новое значение 20.
Это видно из приведенного ниже вывода программы на экран: П е р е д в ы з о в о м U p d a t e ( r e f n , r e f n ) :
n = 1
Н а ч а л ь н о е з н а ч е н и е n V a r l |
- |
1 |
Н а ч а л ь н о е з н а ч е н и е n V a r 2 |
- |
1 0 |
П о с л е в ы з о в а U p d a t e ( r e f n , |
r e f n ) : |
|
n = 2 0 |
|
|
Н а ж м и т е < E n t e r > д л я з а в е р ш е н и я п р о г р а м м ы . . .
Понятно, что ни программист, который писал функцию U p d a t e ( ) , ни про граммист, ее использовавший, не рассчитывали на такой экзотический результат. Вся проблема оказалась в том, что одна и та же переменная была передан в одну и ту же функцию по ссылке больше одного раза. Никогда так не посту пайте, если только вы не абсолютно уверены в том, чего именно вы хотите до биться таким действием.
160 |
Часть III. Объектно-основанное программированы |
Вы можете передавать одно и то же значение в функцию сколько угодно раз, если передаете его по значению.
Почему некоторые аргументы используются только для возврата значений?
С# по мере возможности старается защитить программиста от всех глупостей, которые он может вольно или невольно сделать. Одна из этих глупостей — программист может забыть проинициализировать переменную перед ее первым применением (особенно час то это случается с переменными-счетчиками). С# генерирует ошибку, когда вы пытае тесь использовать объявленную, но не инициализированную переменную:
i n t n V a r i a b l e ; |
|
|
C o n s o l e . W r i t e L i n e ( " Э т о о ш и б к а |
" |
+ , n V a r i a b l e ) ; |
n V a r i a b l e = 1; |
|
|
C o n s o l e . W r i t e L i n e ( " А э т о - н е т |
" |
+ n V a r i a b l e ) ; |
Однако C# не в состоянии отслеживать переменные в функции: |
||
void S o m e F u n c t i o n ( r e f i n t n V a r i a b l e ) |
||
{
C o n s o l e . W r i t e L i n e ( " О ш и б к а и л и н е т ? " + n V a r i a b l e ) ;
} ,
Откуда функция S o m e F u n c t i o n () может знать, была ли переменная n V a r i a b l e инициализирована перед вызовом функции? Это невозможно. Вместо этого С# отсле живает переменные при вызове функции — например, вот такой вызов функции при ведет к сообщению об ошибке:
i n t n U n i n i t i a l i z e d V a r i a b l e ;
S o m e F u n c t i o n ( r e f n U n i n i t i a l i z e d V a r i a b l e ) ;
Если бы C# позволил осуществить такой вызов, то функция S o m e F u n c t i o n () полу чила бы ссылку на неинициализированную переменную (т.е. на мусор (garbage)) в па мяти. Ключевое слово o u t позволяет функции и вызывающему ее коду договориться о том, что передаваемая по ссылке переменная может быть не инициализирована — функция обещает не использовать ее значение до тех пор, пока оно не будет какимлибо образом присвоено самой функцией. Следующий фрагмент исходного текста компилируется без каких-либо замечаний:
i n t n U n i n i t i a l i z e d V a r i a b l e ;
S o m e F u n c t i o n ( o u t n U n i n i t i a l i z e d V a r i a b l e ) ;
Передача инициализированной переменной как out-аргумента также является кор ректным действием:
i n t n l n i t i a l i z e d V a r i a b l e = 1 ;
S o m e F u n c t i o n ( o u t n l n i t i a l i z e d V a r i a b l e ) ;
В этом случае значение переменной n l n i t i a l i z e d V a r i a b l e будет просто проиг норировано функцией S o m e F u n c t i o n ( ) , но никакой опасности для программы это не представляет.
Глава 7. Функции функций |
161 |