ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 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. Объектно-основанное программирование