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

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

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

в зависимости от того, истинно или ложно некоторое условие. Любой язык программи­ рования должен обеспечивать такую возможность управления потоком выполнения.

Основой возможности принятия решения в С# является оператор if: iif (Условие)

II Этот код выполняется, если Условие истинно

}

//Этот код выполняется вне зависимости от

//истинности Условия

Непосредственно за оператором if в круглых скобках содержится некоторое услов­ ное выражение типа b o o l (см. главу 4, "Операторы"), после чего следует код, заклю­ ченный в фигурные скобки. Если условное выражение истинно (имеет значение true), программа выполняет код, заключенный в фигурных скобках. Если нет — этот код про­

граммой опускается.

 

 

Работу оператора if проще понять, рассматривая конкретный пример:

//

Гарантируем,

что а - неотрицательно:

//

Если

а

меньше

0 . . .

i f

(а <

0)

 

 

{

 

 

 

 

 

//

... присваивае м это й переменной значение 0

}

а =

0;

 

 

 

 

 

 

 

В этом фрагменте исходного текста проверяется, содержит ли переменная а отрица­

тельное значение, и если это так, переменной а присваивается значение 0.

 

Если в фигурных скобках заключена только одна инструкция, то их можно не

 

использовать, т.е. в приведенном выше фрагменте можно было бы написать

 

 

if

(а<0)

а = 0,-. Но на мой взгляд, для большей удобочитаемости лучше все­

гда использовать фигурные скобки.

О п е р а т о р if

Рассмотрим небольшую программу, вычисляющую проценты. Пользователь вводит вклад и проценты, и программа подсчитывает сумму, получаемую по итогам года (это не слишком сложная программа). Вот как такие вычисления выглядят на С#:

// Вычисление суммы вклада и процентов

decima l m l n t e r e s t P a i d ;

 

m l n t e r e s t P a i d = m P r i n c i p a l * ( m l n t e r e s t / 1 0 0 ) ;

// Вычисление

общей суммы

 

decima l mTotal

= m P r i n c i p a l

+ m l n t e r e s t P a i d ;

В первом уравнении величина

вклада m P r i n c i p a l умножается на величину про­

центной ставки m l n t e r e s t (деление на 100 связано с тем, что пользователь вводит ве­

личину ставки в процентах).

Получившаяся величина

увеличения вклада

сохраняется

в переменной m l n t e r e s t P a i d ,

а затем суммируется с

основным вкладом

и сохраняет­

ся в переменной mTotal.

 

 

 

86

Часть II. Основы программирования в С#

Программа должна предвидеть, что данные вводит всего лишь человек, ко­ торому свойственно ошибаться. Например, ошибкой должны считаться от­ рицательные величины вклада или процентов (конечно, в банке хотели бы, чтобы это было не так...), и в приведенной далее программе C a l c u l a t e - I n t e r e s t , имеющейся на прилагаемом компакт-диске, выполняются соот­ ветствующие проверки.

// C a l c u l a t e l n t e r e s t

 

 

// Вычисление

величины начисленных процентов для данного

// вклада.

Если

процентная ставка или вклад отрицательны,

// генерируется сообщение об ошибке.

 

using System;

 

 

 

 

namespace

C a l c u l a t e l n t e r e s t

 

 

(

 

 

 

 

 

publi c

c l a s s

Program

 

 

{

 

 

 

 

 

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 )

{

 

 

 

 

 

 

//

Приглашение для ввода вклада

 

C o n s o l e . W r i t e ( " В в е д и т е сумму

в к л а д а : " ) ;

 

s t r i n g s P r i n c i p a l = C o n s o l e . R e a d L i n e ( ) ;

 

decima l m P r i n c i p a l

=

 

 

 

 

C o n v e r t . T o D e c i m a l ( s P r i n c i p a l ) ;

 

//

Убеждаемся, что вклад не отрицателен

 

if

(mPrincipa l < 0)

 

 

{

 

 

 

 

 

 

 

C o n s o l e . W r i t e L i n e ( " В к л а д

не может "

 

 

 

 

"быть

отрицательным");

 

 

 

m P r i n c i p a l = 0;

 

 

}

 

 

 

 

 

//

Приглашение для ввода процентной ставки

 

C o n s o l e . W r i t e ( " В в е д и т е процентную с т а в к у : " ) ;

 

s t r i n g s l n t e r e s t =

Consol e . ReadLine О ;

 

decima l m l n t e r e s t

=

 

C o n v e r t . T o D e c i m a l ( s l n t e r e s t ) ;

//Убеждаемся, что процентная ставка не

//отрицательна

if ( m l n t e r e s t < 0)

{

 

Console . WriteLine("Процентна я ставка не "

 

"может быть отрицательна") ;

 

m l n t e r e s t = О,-

}

О

//Вычисляем сумму величины процентных

//начислений и вклада

decima l m l n t e r e s t P a i d ;

m l n t e r e s t P a i d = m P r i n c i p a l * ( m l n t e r e s t / 1 0 0 ) ;

// Вычисление

общей суммы

decima l mTotal

= m P r i n c i p a l + m l n t e r e s t P a i d ;

//Вывод результато в

C o n s o l e . W r i t e L i n e ( ) ; / / s k i p a l i n e

C o n s o l e . W r i t e L i n e ( " В к л а д = " + m P r i n c i p a l ) ;

Глава 5. Управление потоком выполнения

87

C o n s o l e . W r i t e L i n e ( " П р о ц е н т ы = " + m I n t e r e s t + " % " ) ; C o n s o l e . W r i t e L i n e ( ) ;

Console . WriteLine("Начисленны е проценты = " + m l n t e r e s t P a i d ) ;

Console . WriteLine("Обща я сумма = " + m T o t a l ) ; // Ожидание реакции пользователя

Console . WriteLine("Нажмит е <Enter> для " "завершения программы ... ") ;

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

}

}}

Программа C a l c u l a t e l n t e r e s t начинает свою работу с предложения пользовате! лю ввести величину вклада. Это предложение выводится с помощью функции Write-• Line ( ) , которая выводит значение типа s t r i n g на консоль.

Всегда точно объясняйте пользователю, чего вы от него хотите. Если возмож-В но, укажите также требуемый формат вводимых данных. Обычно на неинфор-И мативные приглашения наподобие одного символа > пользователи отвечают» совершенно некорректно.

В программе для считывания всего пользовательского ввода до нажатия клавиши! <Enter> в переменную типа s t r i n g используется функция R e a d L i n e ( ) . Поскольку! программа работает с величиной вклада как имеющей тип d e c i m a l , введенную строку! следует преобразовать в переменную типа decimal , что и делает функция Con­

v e r t . ToDecimal ( ) . Полученный результат сохраняется в переменной mPrincipal .

Команды ReadLine ( ) , WriteLin e () и ToDecimal () служат примерами вы- I

зовов функций. Вызов функции делегирует некоторую работу другой части про­ граммы, именуемой функцией. Детально вызов функций будет описан в главе 7, "Функции функций", но приведенные здесь примеры очень просты и понятны. Если же вам что-то не ясно в вызовах функций, потерпите немного, и все будет объяснено детально.

В следующей строке выполняется проверка переменной m P r i n c i p a l . Если она от­ рицательна, программа выводит сообщение об ошибке. Те же действия производятся и для величины процентной ставки. После этого программа вычисляет общую сумму так, как уже было описано в начале раздела, и выводит конечный результат посредством не­ скольких вызовов функции W r i t e L i n e ( ) .

Вот пример вывода программы при корректном пользовательском вводе:

Введите

сумму вклада: 1234

Введите процентную ставку : 21

Вклад

= 1234

 

Проценты

= 21%

 

Начисленные проценты = 2 5 9 . 1 4

Общая сумма

= 1 4 9 3 . 1 4

Нажмите

<Enter>

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

88

Часть II. Основы программирования в С#

А так выглядит вывод программы при ошибочном вводе отрицательной величины процентной ставки:

Введите

сумму вклада:

1234

Введите

процентную ставку г-12.5

Процентная ставка не может быть отрицательна

Вклад

= 1234

 

 

Проценты

= 0%

 

 

Начисленные проценты

= 0

Общая сумма

= 12 34

Нажмите

<Enter>

для

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

Отступ внутри блока if повышает удобочитаемость исходного текста. С# иг­ норирует все отступы, но для человека они весьма важны. Большинство редак­ торов для программистов автоматически добавляют отступ при вводе операто­ ра if. Для включения автоматического отступа в Visual Studio выберите ко­ манду меню ToolsOOptions, затем раскройте узел T e x t Editor, потом С#, а в конце щелкните на вкладке T a b s . На ней включите флаг Smart Indenting и установите то количество пробелов на один отступ, которое вам по душе. Ус­ тановите то же значение и в поле T a b Size.

Инструкция else

Некоторые функции должны проверять взаимоисключающие условия. Например, в приведенном далее фрагменте исходного текста в переменной max сохраняется наи­

большее из двух значений а и Ь:

 

 

 

 

// Сохраняем наибольшее из двух

значений а

и b

// в переменной max

 

 

 

 

 

int

max;

 

 

 

 

 

// Если а больше Ь . . .

 

 

 

 

if

(а >

Ь)

 

 

 

 

 

(

 

 

 

 

 

.

- '

 

//

... сохраняе м

значение

а

в

переменной

max

I

max = а,-

"

 

 

 

'

// Если а меньше или

равно Ь . . .

 

 

if

(а <= Ь)

 

 

 

 

 

{

 

 

 

 

 

 

 

 

//

... сохраняе м

значение

b

в

переменной

max

 

max = b ;

 

 

 

 

 

}

Второй оператор if является излишним, поскольку проверяемые условия взаимоис­ ключающи. Если а больше Ь, то а никак не может быть меньше или равно Ь. Для таких случаев в С# предусмотрено ключевое слово e l s e , позволяющее указать блок, который выполняется, если не выполняется блок if.

Вот как выглядит приведенный выше фрагмент кода при использовании e l s e :

// Сохраняем наибольшее из двух значений а и b // в переменной max

int max;

Глава 5. Управление потоком выполнения

89

//

Если

а больше Ь . . .

i f

(а >

Ь)

{

//

. . . с о х р а н я е м

значение а в переменной max;

//

в

противном

случае

max =

а,-

 

}

 

 

 

e l s e

 

 

 

{

 

 

 

//

. . . с о х р а н я е м

в переменной max значение b

max

=

b;

 

}

 

 

 

Если а больше Ь, то выполняется первый блок; в противном случае выполняется втс-| рой блок. В результате в переменной max содержится наибольшее из значений а и Ь.

Как и з б е ж а т ь else

При наличии многих e l s e в исходном тексте можно легко запутаться, поэтому мно| гие программисты предпочитают по возможности избегать использования e l s e , если оно приводит к ухудшению удобочитаемости исходного текста. Так, рассмотренное вы­ ше вычисление максимального значения можно переписать следующим образом:

//

Сохраняем наибольшее из

двух

значений

а и b

//

в переменной

max

 

 

 

i n t

max;

 

 

 

 

 

 

//

Начнем с

предположения,

что

а больше

b

max = а,-

 

 

 

 

 

 

//

Если

же

эт о

не так . . .

 

 

 

i f

(b >

а)

 

 

 

 

 

{

// . . .

то сохраняем в переменной max значение b

max =

b ;

}

 

Другие программисты бегут от такого стиля написания программ, как от чумы, и ml можно понять. Это не значит, что следует поступать так же, как они, но оправдать их! можно. Как поступать вам — дело ваше. В реальных программах встречаются оба стиля.

В л о ж е н н ы е о п е р а т о р ы if

Программа C a l c u l a t e l n t e r e s t предупреждает пользователя о неверном вводе, но при этом продолжает вычисление начисленных процентов, несмотря на некоррект­ ность введенных значений. Вряд ли это правильное решение. Оно, конечно, не вызывает особых потерь процессорного времени, но только в силу простоты выполняемых про­ граммой подсчетов, в более же сложном случае это может привести к большим затратам. Кроме того, какой смысл запрашивать величину процентной ставки, если величина вкла­ да уже введена неверно? Все равно результат придется проигнорировать, какое бы зна­ чение процентной ставки не было введено.

Программа должна запрашивать у пользователя величину процентной ставки только тогда, когда величина вклада введена верно, выполнять вычисления тогда и только тогда, когда оба введенных значения корректны. Для этого необходимы две конструкции if — одна внутри другой.

90

Часть II. Основы программирования в С#

Оператор if, находящийся в теле другого оператора if, называется встро­ енным (embedded) или вложенным (nested).

Приведенная далее программа C a l c u l a t e l n t e r e s t W i t h E m b e d d e d - T e s t использует вложенный оператор if для того, чтобы избежать лишних вопросов при обнаружении некорректного ввода пользователя.

// CalculateInterestWithEmbeddedTes t

 

//

Вычисление величины начисленных процентов для данного

//

вклада. Если процентная ставка

или вклад отрицательны,

//

генерируется сообщение об ошибке и вычисления не

//

выполняются.

 

using

System;

 

namespace

C a l c u l a t e I n t e r e s t W i t h E m b e d d e d T e s t

{

 

 

 

public c l a s s Program

 

{

 

 

 

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

args )

{

 

 

 

 

// Определяем максимально возможное значение

 

//

процентной ставки

 

 

i n t

nMaximumlnterest = 5 0 ;

 

//Приглашение пользователю ввести величину исходног о

//вклада

C o n s o l e . W r i t e ( " В в е д и т е сумму в к л а д а : " ) ;

s t r i n g s P r i n c i p a l = C o n s o l e . R e a d L i n e О ;

decima l m P r i n c i p a l

= C o n v e r t . T o D e c i m a l ( s P r i n c i p a l ) ;

// Если исходный

вклад о т р и ц а т е л е н . . .

I

{if (mPrincipa l

< 0)

 

 

 

II...генерируем

сообщение

об

ошибке .. .

 

C o n s o l e . W r i t e L i n e ( " В к л а д

не

может быть отрицателен") ;

 

}

 

 

 

 

e l s e

 

 

 

I

{

з

 

 

// . . . в противном случае просим ввести процентную

//ставку

C o n s o l e . W r i t e ( " В в е д и т е процентную с т а в к у : " ) ; s t r i n g s l n t e r e s t = C o n s o l e . R e a d L i n e О ;

decima l

m l n t e r e s t =

C o n v e r t . T o D e c i m a l ( s l n t e r e s t ) ;

//

Если

процентная

ставка отрицательна или слишком

//

велика . . . -

 

if

( m l n t e r e s t < 0

| m l n t e r e s t > nMaximumlnterest)

{

//. . . генерируем сообщение об ошибке

Console . WriteLine("Процентна я ставка не может " "быть отрицательна " +

Глава 5. Управление потоком выполнения

91

"или превышать "

+ nMaximumlnterest) ;

m l n t e r e s t = 0;

}

e l s e

{

// И величина вклада, и процентная ставка

//корректны — можно приступить к вычислению

//вклада с начисленными процентами

decima l m l n t e r e s t P a i d ;

m l n t e r e s t P a i d = m P r i n c i p a l * ( m l n t e r e s t / 1 0 0 ) ;

//Вычисляем общую сумму

decima l mTotal = m P r i n c i p a l + m l n t e r e s t P a i d ;

//Выводим результа т

C o n s o l e . WriteLin e () ,- // s k i p a l i n e C o n s o l e . W r i t e L i n e ( " В к л а д = "

+ m P r i n c i p a l ) ; Console . WriteLine("Процент ы = "

+ m l n t e r e s t + "%") ;

C o n s o l e . W r i t e L i n e ( ) ;

Console . WriteLine("Начисленны е проценты = " + m l n t e r e s t P a i d ) ;

Console . WriteLine("Обща я сумма = "

+ mTotal) ,- // Ожидаем подтверждения пользователя

Console . WriteLine("Нажмит е <Enter> для " "завершения программы.. . ") ;

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

}

}

}

Программа начинает со считывания введенной пользователем величины исходного вклада. Если это значение отрицательно, она выводит сообщение об ошибке и завершает работу. Если же величина вклада не отрицательна, управление переходит к блоку e l s e .

Проверка величины процентной ставки в этой программе немного усовершенствова­ на. Программа требует не только неотрицательности введенного значения, но и чтобы оно было меньше некоторого максимального значения. Применяемый в программе опе­

ратор if использует следующий составной

тест:

if ( m l n t e r e s t < 0

|| m l n t e r e s t >

nMaximumlnterest)

Выражение истинно,

если m l n t e r e s t

меньше 0 или больше значения nMaximu­

m l n t e r e s t . Обратите внимание, что значение nMaximumlnterest объявлено в нача­ ле программы, а не жестко закодировано в виде константы в исходном тексте условия.

Определяйте важные константы в начале программы с использованием сим­ вольных имен.

92

Часть II. Основы программирования в С#

Такое кодирование констант в виде переменных служит следующим целям.

Дает каждой константе поясняющее имя. nMaximumlnterest более понятно, чем 50.

Облегчает поиск константы, если вам потребуется изменить ее.

Облегчает процесс изменения константы. Обратите внимание, что та же пере­ менная nMaximumlnterest используется в сообщении об ошибке. Изменение nMaximumlnterest на, например, 60, приведет к корректной модификации как проверяемого условия, так и сообщения об ошибке.

Более подробно о константах будет рассказано в главе 6, "Объединение данных — классы и массивы".

Ввод корректной величины вклада и некорректной — процентной ставки, приводит к следующему выводу программы:

Введите

сумму вклада :123

4

 

Введите

процентную ставку

: - 1 2 . 5

Процентная ставка не может быть

отрицательна или превышать 5 0 .

Нажмите <Enter> для завершения

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

Только при вводе корректных значений и вклада, и процентной ставки программа приступит к вычислениям и выведет интересующий результат:

Введите

сумму вклада :123

4

Введите

процентную ставку

: 1 2 . 5

Вклад = 1234 Проценты = 12 . 5%

Начисленные проценты = 1 5 4 . 2 5 0 Общая сумма = 13 8 8 . 2 50

Нажмите <Enter> для завершения программы...

Циклы

Конструкция i f

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

сти от результата

вычисления значения типа b o o l . Ее наличие обеспечивает возмож­

ность создания программ существенно более интересных, чем те, которые могут быть написаны без использования if. Еще одним применением машинной команды условно­ го перехода является возможность итеративного выполнения блока кода.

Рассмотрим еще раз программу C a l c u l a t e l n t e r e s t из раздела "Оператор if данной главы. Такие простые вычисления проще выполнить с помощью карманного калькулятора, чем писать для этого специальную программу.

Но что, если вы захотите вычислить проценты по вкладу для нескольких лет? Такая программа будет намного полезнее (конечно, простой макрос в Microsoft Excel все равно гораздо проще, чем требующаяся вам программа, но не стоит мелочиться).

Итак, нам надо выполнить некоторую последовательность инструкций несколько раз подряд. Это и называется циклом (loop).

Цикл while

Наиболее фундаментальный вид цикла создается с помощью ключевого слова w h i l e следующим образом:

Глава 5. Управление потоком выполнения

93

while{Условие)

{

II

Код,

повторно выполняемый до те х пор,

//

пока

Условие не стане т ложным

}

При первом обращении к циклу вычисляется условие в круглых скобках после клю­ чевого слова w h i l e . Если оно истинно, выполняется следующий за ним блок кода — те­ ло цикла. По окончании выполнения тела цикла программа вновь возвращается к началу цикла и вычисляет условие в круглых скобках, и все начинается сначала. Если же в ка­ кой-то момент условие становится ложным, тело цикла не выполняется, и управление передается коду, следующему за ним.

Если при первом обращении к циклу условие ложно, тело цикла не выполня­ ется ни разу.

Программисты зачастую косноязычны и могут не совсем корректно выра­ жаться. Например, говоря о цикле w h i l e , они могут сказать, что тело цикла выполняется до тех пор, пока условие не станет ложным. Я считаю, что та­ кое определение некорректно, так как можно решить, что выполнение цикла прервется в тот же момент, как только условие станет ложным. Это не так, Программа не проверяет постоянно справедливость условия; проверка про­ изводится только тогда, когда управление передается в начало цикла.

Цикл w h i l e можно использовать для

создания программы C a l c u l a t e l n -

t e r e s t T a b l e , являющейся версией

программы C a l c u l a t e l n t e r e s t

сприменением цикла. Она вычисляет таблицу величин вкладов по годам.

// C a l c u l a t e l n t e r e s t T a b l e

//

Вычисление

величины начисленных процентов для данного

//

вклада

за

определенный период времени

u s i n g System ;

 

namespace

C a l c u l a t e l n t e r e s t T a b l e

{

 

 

 

 

u s i n g System ;

 

p u b l i c

c l a s s Program

 

{

 

 

 

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

nMaximumlnterest = 5 0 ;

// Приглашение пользователю ввести величину исходного

//вклада

C o n s o l e . W r i t e ( " В в е д и т е сумму в к л а д а : " ) ; s t r i n g s P r i n c i p a l = C o n s o l e . R e a d L i n e ( ) ;

d e c i m a l m P r i n c i p a l = C o n v e r t . T o D e c i m a l ( s P r i n c i p a l ) ;

// Если исходный вклад о т р и ц а т е л е н . . .

if ( m P r i n c i p a l < 0)

{

94

Часть И. Основы программирования в С#

II...генерируем сообщение об ошибке .. .

Console . WriteLine("Вкла д не может быть отрицателен") ;

}

 

 

 

e l s e

 

 

 

{

 

 

 

//

. . . в противном случае просим ввести процентную

//

ставку

 

Console . Write("Введит е процентную с т а в к у : " ) ;

s t r i n g s l n t e r e s t = C o n s o l e . R e a d L i n e ( ) ;

decimal

m l n t e r e s t =

C o n v e r t . T o D e c i m a l ( s l n t e r e s t ) ;

//

Если

процентная

ставка отрицательна или слишком

// велика. . .

 

if

( m l n t e r e s t < О

I m l n t e r e s t > nMaximumlnterest)

{

//. . . генерируем сообщение об ошибке

Console . WriteLine("Процентна я ставка не может " + "быть отрицательна " + "или превышать " +

n M a x i m u m l n t e r e s t ) ;

m l n t e r e s t = 0;

}

e l s e

{

/ / И величина вклада, и

процентная

ставка

//

корректны — запрашиваем у пользователя срок,

//

для которого следуе т

вычислить

величины вкладов

//с начисленными процентами

C o n s o l e . W r i t e ( " В в е д и т е количество л е т : " ) ; s t r i n g s D u r a t i o n = C o n s o l e . R e a d L i n e ( ) ;

i n t nDuratio n = C o n v e r t . T o I n t 3 2 ( s D u r a t i o 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 ( " В к л а д = "

 

 

 

 

 

+ m P r i n c i p a l ) ;

 

 

Console . WriteLine("Процент ы = "

 

 

 

 

 

+ m l n t e r e s t +

"%") ;

 

C o n s o l e . W r i t e L i n e ( " С р о к

= "

 

 

 

 

 

+ nDuratio n +

" y e a r s " ) ;

 

C o n s o l e . W r i t e L i n e ( ) ;

 

 

 

 

//

Цикл

по

указанному

пользователем количеству лет

 

i n t

nYear

=

1;

 

 

 

 

w h i l e ( n Y e a r

<= nDuration )

 

 

 

{

 

 

 

 

 

 

 

// Вычисление вклада с начисленными процентами

 

decima l m l n t e r e s t P a i d ;

 

 

 

m l n t e r e s t P a i d = m P r i n c i p a l * ( m l n t e r e s t / 1 0 0 ) ;

 

// Вычисляем новое

значение вклада

 

m P r i n c i p a l = m P r i n c i p a l + m l n t e r e s t P a i d ;

в C#

^ава 5. Управление потоком выполнения

 

95