ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 11.12.2025
Просмотров: 3207
Скачиваний: 1
Многие реальные операции создают некоторые значения, которые должны быть воз вращены тому, кто вызвал эту операцию. Например, функция s i n () получает аргумент и возвращает значение тригонометрической функции "синус" для данного аргумент Функция может вернуть значение вызывающей функции двумя способами. Наиболее распространенный — с помощью команды r e t u r n ; второй способ использует возмож ности передачи аргументов по ссылке.
Возврат значения оператором return
Приведенный далее фрагмент исходного текста демонстрирует небольшую функцию возвращающую среднее значение переданных ей аргументов,
p u b l i c c l a s s E x a m p l e |
|
|||
{ |
|
|
|
|
p u b l i c |
s t a t i c |
d o u b l e A v e r a g e ( d o u b l e d l , |
d o u b l e d 2 ) |
|
{ |
|
|
|
|
d o u b l e d A v e r a g e = ( d l + d 2 ) / 2 ; |
|
|||
r e t u r n |
d A v e r a g e ; |
|
||
} |
|
|
|
|
p u b l i c |
s t a t i c |
v o i d T e s t O |
|
|
{ |
|
|
|
|
d o u b l e |
v l |
= 1 . 0 ; |
|
|
d o u b l e v 2 |
= 3 . 0 ; |
|
||
d o u b l e d A v e r a g e V a l u e = A v e r a g e ( v l , |
v 2 ) ; |
C o n s o l e . W r i t e L i n e ( " С р е д н е е д л я " |
+ v l |
+ " и " + v2 + " р а в н о "
+d A v e r a g e V a l u e ) ;
/ / Т а к о й м е т о д т а к ж е в п о л н е р а б о т о с п о с о б е н C o n s o l e . W r i t e L i n e ( " С р е д н е е д л я " + v l
+ " и " + v2 + " р а в н о " + A v e r a g e ( v l , v 2 ) ) ;
}
}
Прежде всего обратите внимание, что функция объявлена как p u b l i c s t a t i c double A v e r a g e () — тип d o u b l e перед именем функции указывает на тот факт, что функция Av e r a g e () возвращает вызывающей функции значение типа d o u b l e .
Функция A v e r a g e () использует имена dl и d2 для значений, переданных ей в ка честве аргументов. Она создает переменную d A v e r a g e , которой присваивает среднее значение этих переменных. Затем значение, содержащееся в переменной dAverage, возвращается вызывающей функции.
Программисты иногда говорят, что "функция возвращает d A v e r a g e " . Это не корректное сокращение. Говорить, что передается или возвращается dAver a g e или иная переменная — неточно. В данном случае вызывающей функции возвращается значение, содержащееся в переменной d A v e r a g e .
Вызов A v e r a g e () из функции T e s t () выглядит точно так же, как и вызов любой другой функции; однако значение типа d o u b l e , возвращаемое функцией A v e r a g e d , сохраняется в переменной d A v e r a g e V a l u e .
162 |
Часть III. Объектно-основанное программирование] |
Функция, которая возвращает значение (как, например, A v e r a g e ()), не может завершиться просто по достижении закрывающей фигурной скобки, поскольку С# совершенно непонятно, какое же именно значение должна будет вернуть эта функция? Для этого обязательно наличие оператора r e t u r n .
Возврат значения посредством передачи по ссылке
Функция может также вернуть одно или несколько значений вызывающей программе с помощью ключевых слов r e f или o u t . Рассмотрим пример U p d a t e () из раздела "Передача по ссылке" данной главы:
//Update - функция пытается модифицировать значения //аргументов, переданные ей; обратите внимание, на
//передачу аргументов как r e f и o u t
public static void Update (ref int i, out double d)
{
i = 10; d = 20.0;
}
Эта функция объявлена как v o i d , так как она не возвращает никакого значения вы зывающей функции. Однако поскольку переменная i объявлена как r e f , а переменная d— как o u t , любые изменения значений этих переменных, выполненные в функции Update (), сохранятся при возврате в вызывающую функцию. Другими словами, значе ния этих переменных вернутся вызывающей функции.
Когда какой метод использовать
Вы можете задуматься: "Функция может возвращать значение как с использованием оператора r e t u r n , так и посредством переменных, переданных по ссылке. Так какой же метод мне лучше применять в своих программах?" В конце концов, ту же функцию Av erage () вы могли написать и так:
{public c l a s s E x a m p l e
// Примечание: параметр, передаваемый как ' o u t ' , лучше
// сделать последним в списке |
|
|
|
||
p u b l i c s t a t i c v o i d A v e r a g e ( d o u b l e |
1 , |
d o u b l e d 2 , |
|||
|
|
out double dResults) |
|||
{ |
|
|
|
|
|
dResults = (dl + d2) / 2; |
|
|
|
|
|
} |
|
|
|
|
|
p u b l i c s t a t i c |
v o i d T e s t ( ) |
|
|
|
|
{ |
|
|
|
|
|
d o u b l e v l |
= 1 . 0 ; |
|
|
|
|
d o u b l e v 2 = 3 . 0 ; |
|
|
|
|
|
d o u b l e d A v e r a g e V a l u e ; |
|
|
|
|
|
A v e r a g e ( d A v e r a g e V a l u e , |
v l , |
v 2 ) ; |
|
||
C o n s o l e . W r i t e L i n e ( " С р е д н е е " + vl |
|
||||
|
+ " |
и " |
+ v2 |
+ " |
равно " |
+d A v e r a g e V a l u e ) ;
}
}
Глава 7. Функции функций |
163 |
Обычно значение вызывающей функции возвращается с помощью оператЛ r e t u r n , а не посредством out-аргумента, хотя обосновать преимущество такого по; хода очень трудно.
• ^ S ^ Возврат значения посредством передачи аргумента по ссылке иногда требу! дополнительных действий, которые будут описаны в главе 14, "Интерфейсы! структуры". Однако обычно эффективность — не главный фактор при прин| тии решения о способе возврата значения из функции.
Как правило, "метод o u t " используется, если требуется вернуть из функции несши ко значений — например, как в следующей функции:
p u b l i c c l a s s E x a m p l e
{ |
|
p u b l i c |
s t a t i c |
v o i d A v e r a g e A n d P r o d u c t ( d o u b l e d l , o u t d o u b l e o u t d o u b l e
d o u b l e d 2 , d A v e r a g e ,
d P r o d u c t )
{
d A v e r a g e } d P r o d u c t
}
= ( d l + d 2 ) / 2 ; = d l * d 2 ;
Возврат из функции нескольких значений встречается не так часто, как мож» показаться. Функция, которая возвращает несколько значений, обычно дела» это путем возврата одного объекта класса, который инкапсулирует несколы; значений, или путем возврата массива значений. Оба способа приводят к бол* ясному и понятному исходному тексту.
Нулевая ссылка и ссылка на ноль
Ссылочные переменные, в отличие от переменных типов-значений, при создании ини циализируются значением по умолчанию n u l l . Однако нулевая ссылка (т.е. ссылка, инициализированная значением n u l l ) — это не то же, что ссылка на ноль. Например, две следующие ссылки совершенно различны:
c l a s s E x a m p l e
{
i n t n V a l u e , -
}
/ / С о з д а н и е н у л е в о й с с ы л к и r e f l E x a m p l e r e f l ;
/ / С о з д а н и е с с ы л к и н а н у л е в о й о б ъ е к т E x a m p l e r e f 2 = n e w E x a m p l e О ;
r e f 2 . n V a l u e = 0 ;
Переменная r e f l пуста, как мой бумажник. Она указывает в "никуда", т.е. не указы вает ни на какой реальный объект. Ссылка же r e f 2 указывает на вполне конкретный объект, значение которого равно нулю.
Возможно, эта разница станет понятнее после следующего примера:
s t r i n g |
s i ; |
s t r i n g |
s 2 = " " ; |
164 |
Часть III. Объектно-основанное программирована |
fj |
По сути, возникает аналогичная ситуация— si указывает на нулевой объект, в то время как s2 — на пустую строку (на сленге программистов пустая строка иногда называется нулевой строкой). Это очень существенное отличие, как становится ясно из следующего исходного текста:
// T e s t - namespace
т е с т о в а я п р о г р а м м а T e s t
(
u s i n g S y s t e m ;
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 [ ] |
s t r i n g s ) |
{
C o n s o l e . W r i t e L i n e ( " Э т а п р о г р а м м а и с с л е д у е т " + " ф у н к ц и ю T e s t S t r i n g ( ) " ) ;
C o n s o l e . W r i t e L i n e ( ) ;
E x a m p l e e x a m p l e O b j e c t = n e w E x a m p l e ( ) ;
C o n s o l e . W r i t e L i n e ( " П е р е д а ч а |
н у л е в о г о о б ъ е к т а : " ) ; |
||
s t r i n g s = |
n u l l ; |
|
|
e x a m p l e O b j e c t . T e s t S t r i n g ( s ) ; |
|
|
|
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 ( " П е р е д а ч а п у с т о й с т р о к и : " ) ; |
|||
e x a m p l e O b j e c t . T e s t S t r i n g ( " " ) ; |
|
|
|
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 ( " П е р е д а ч а р е а л ь н о й с т р о к и : " ) ; |
|||
e x a m p l e O b j e c t . T e s t S t r i n g ( " t e s t |
s t r i n g " ) ; |
||
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 ( " Н а ж м и т е < E n t e r > д л я " + |
|||
|
" з а в е р ш е н и я п р о г р а м м ы . . . ") ; |
||
C o n s o l e . R e a d () ,- |
|
|
|
c l a s s E x a m p l e |
|
|
|
{ |
|
|
|
p u b l i c v o i d |
T e s t S t r i n g ( s t r i n g |
s T e s t ) |
|
{
/ / |
П р о в е р к а , н е н у л е в о й л и о б ъ е к т ( э т а п р о в е р к а д о л ж н а |
/ / |
б ы т ь п е р в о й ! ) |
i f ( s T e s t = = n u l l )
{
C o n s o l e . W r i t e L i n e ( " s T e s t = = n u l l " ) ; r e t u r n ;
}
/ / М ы з н а е м , ч т о s T e s t н е у к а з ы в а е т н а н у л е в о й о б ъ е к т , / / н о в с е е щ е м о ж е т у к а з ы в а т ь н а п у с т у ю с т р о к у .
/ / П р о в е р я е м , н е у к а з ы в а е т л и s T e s t н а н у л е в у ю
/ / |
( п у с т у ю ) с т р о к у |
i f |
( S t r i n g . C o m p a r e ( s T e s t , " " ) = = 0 ) |
{ |
|
|
C o n s o l e . W r i t e L i n e (11 s T e s t - с с ы л к а н а п у с т у ю с т р о к у " ) ; |
|
r e t u r n ; |
Глава 7. Функции функций |
165 |
{
// Строка не пустая, выводим ее
} C o n s o l e . W r i t e L i n e ( " s T e s t у к а з ы в а е т н а : ' " + s T e s t + " ' " ) ;
}
}
Функция T e s t S t r i n g O использует сравнение s T e s t = = n u l l для проверки, не на нулевой ли объект указывает ссылка. Для проверки, не указывает ли ссылка на пустую строку, функция T e s t S t r i n g () использует функцию C o m p a r e () (функция Com p a r e () возвращает 0, если переданные ей строки равны. В главе 9, "Работа со стро ками в С # " , вы более детально познакомитесь со сравнением строк).
Вот как выглядит вывод этой программы на экран:
Э т а п р о г р а м м а и с с л е д у е т ф у н к ц и ю T e s t S t r i n g O П е р е д а ч а н у л е в о г о о б ъ е к т а :
s T e s t = = n u l l
П е р е д а ч а п у с т о й с т р о к и :
s T e s t - с с ы л к а н а п у с т у ю с т р о к у П е р е д а ч а р е а л ь н о й с т р о к и :
s T e s t у к а з ы в а е т н а : ' t e s t s t r i n g '
Н а ж м и т е < E n t e r > д л я з а в е р ш е н и я п р о г р а м м ы . . .
Определение функции без возвращаемого значения
Выражение p u b l i c s t a t i c d o u b l e A v e r a g e О объявляет функцию A v e r a g e d как возвращающую значение типа d o u b l e . Однако бывают функции, не возвращающие ничего. Ранее вы сталкивались с примером такой функции— A v e r a g e A n d D i s p l a y О, которая выводила вычисленное среднее значение на экран, ничего не возвращая вызываю щей функции. Вместо того чтобы опустить в объявлении такой функции тип возвращаемо го значения, в С# указывается v o i d :
p u b l i c v o i d A v e r a g e A n d D i s p l a y ( d o u b l e , |
d o u b l e ) |
Ключевое слово v o i d , употребленное вместо имени типа, по сути, означает отсут ствие типа, т.е. указывает, что функция A v e r a g e A n d D i s p l a y () ничего не возвраща ет вызывающей функции. (В С# любое объявление функции обязано указывать возвра щаемый тип, даже если это v o i d . )
Функция, которая не возвращает значения, программистами называется void- функцией, по использованному ключевому слову в ее описании.
Функции, не являющиеся void-функциями, возвращают управление вызывающей функции при выполнении оператора r e t u r n , за которым следует возвращаемое вызы вающей функции значение. Поскольку void - функция не возвращает никакого значе ния, выход из нее осуществляется посредством оператора r e t u r n без какого бы то ни было значения либо (по умолчанию) при достижении закрывающей тело функции фи гурной скобки.
Рассмотрим следующую функцию D i s p l a y R a t i o ( ) : p u b l i c c l a s s E x a m p l e
{
166 |
Часть III. Объектно-основанное программирование |