C# для вундеркиндов. Часть 3. Язык C

advertisement
C# для вундеркиндов. Часть 3. Язык C#
Февраль 2007 г.
Чтобы научиться читать и писать на новом языке, человеку обычно приходится изучить следующие его
аспекты:

Словарь — слова языка

Грамматика — правила согласования слов в допустимой форме. На данном этапе также необходимо
изучить правильную структуру предложений и пунктуацию.

Осмысление — понимание значения написанного. Осмысливать означает понимать.
Примерно то же самое справедливо при обучении чтению и письму на языке программирования. Существуют
основные слова и другие компоненты, образующие создаваемые программы. Эти элементы соединяются
определенным образом и образуют нечто похожее на предложения со знаками препинания. Задачей такого
предложения является передача определенного значения компьютеру.
Мы не станем разбивать наши занятия в точности по приведенным выше заголовкам, но некоторые аспекты
будут рассмотрены в следующих главах.
Как и в естественных языках, в C# существует определенное количество слов, которые непосредственно
образуют язык. Но также существуют и дополнительные слова, которые допускается брать извне.
По-русски можно написать «Горилла по имени Жужа живет в угандских джунглях». Большая часть этих слов
русские и их можно найти в словаре. Но слова «Жужа» и «угандский» не являются русскими — это имена
собственные. Означает ли это, что предложение неверно? Нет, правила допускают использование слов из
разных списков:

имена людей и прозвища животных

официальные названия стран

... и многих других списков слов
Подобным образом мы будем рассказывать о словах, непосредственно принадлежащих языку C#. Но это
совсем не означает, что это единственные слова, которые можно использовать в своих программах. В
зависимости от того о чем идет речь, вы вполне вероятно будете употреблять много дополнительных слов,
заимствованных из других списков, библиотек и т.д. В частности, в Microsoft создана огромная библиотека
кодов .NET Framework Class Library, с которой вам определенно придется работать при написании программ
на языке C#. Библиотека содержит имена классов, полей и методов, которые не являются частью языка C#,
но их безусловно можно применять в программах на C#.
Вы также будете самостоятельно определять новые классы, поля и методы и называть их по своему —
впоследствии они станут словами, которые можно будет на законных основаниях использовать в программах
C#. Это похоже на процесс образования нового прозвища для вашего любимца, такого как «Быстрыш»,
которое вы затем сможете по праву использовать в русских предложениях.
Ниже представлен список некоторых «родных» слова языка, которые нужно знать для написания простых
программ. Обо всех этих словах рассказывается в этой книге.

class

do

else

false

for

if

int

new

null

private

protected

public

return

static

string

this

true

using

void

while
Список неполный, но не волнуйтесь, в нем недостает не так много слов C#. Языки программирования
склонны иметь меньше слов, чем естественные языки.
Что можно делать со словами языка? Из них можно образовывать хорошо структурированные предложения по
определенным правилам. Это называется грамматикой. Именно об этом и будет рассказано далее.
В этой главе мы рассмотрим некоторые общие сведения из грамматики C#. Говоря точнее – о том, что обычно
называют «синтаксисом».
Язык C# чувствителен к регистру. Другими словами, должен строго соблюдаться порядок использования
строчных букв (также называемых букв нижнего регистра) и прописных букв (букв верхнего регистра).
Встроенные слова
Написание ключевых слов, перечисленных в предыдущей главе, должно всегда быть таким, как было
показано. Возможно, вы заметили, что все слова набраны в нижнем регистре.
Поэтому если вы напишите слово «If» или «IF» вместо «if», компьютер просто откажется выполнять код,
поскольку все написанное не по правилам не будет понято.
Не следует относиться к этому слишком строго. Язык обладает преимуществами там, где у вас есть
недостатки. Например, попытайтесь за долю секунды вспомнить все, что вам говорили за последние 10 лет.
Получается? Хм, не очень, да? В любом случае, мы деградируем, так что давайте мириться с этим.
Собственные имена
А как насчет слов, создаваемых самим пользователем? Предложим, например, вы создали класс под
названием «myClass» с полем «numberOfSpots».
class myClass
{
int numberOfSpots;
}
Есть ли разница между заглавными и строчными буквами? Ответ на самом деле достаточно очевиден — Да.
При каждом упоминании этих имен в программе C# их необходимо указывать в точности так, как они были
определены изначально. Например, выполнение следующего кода завершится ошибкой.
class myClass
{
// Поле
int numberOfSpots;
// Метод
public void Main()
{
MyClass x = new MyClass();
x.NUMBEROFSPOTS = 365;
}
}
А следующий фрагмент будет выполнен правильно:
class myClass
{
// Поле
int numberOfSpots;
// Метод
public void Main()
{
myClass x = new myClass();
x.numberOfSpots= 365;
}
}
Хотя имя класса/имя поля/имя метода и т.д. можно написать вперемежку со строчными и заглавными буквами
(NUMBEROFSPOTS или numberofspots или NuMbErOfSpOtS и т.д.), важно и далее писать это имя именно так во
всей программе.
На русском мы говорим предложениями, выражениями, фразами и т.д. Все это разные способы группировки
слов. Каждое такое предложение, выражение или фраза оканчивается определенным знаком препинания. В
конце предложения ставится точка или многоточие (...).
В C# все это немного проще. Мы говорим выражениями, которые, как правило, завершает точка с запятой.
В следующем примере отрывок кода содержит 4 выражения:
string x;
x = "Война без победителей";
myClass m = new myClass();
m.numberOfSpots = 3;
Вы скажите, что в этом коде определенно 4 строки. Но компьютер не рассматривает код в виде строк, как это
делаем мы. Компьютер было бы без разницы, если бы мы написали все четыре выражения в одну строку.
string x; x = "Война без победителей"; myClass m = new
myClass(); m.numberOfSpots = 3;
Именно здесь важную роль играет точка с запятой. Компьютер понимает, что мы написали 4 разных
выражения, потому что в конце каждого из них поставили точку с запятой. Кстати, не советуем писать
слишком много выражений в одну строку — люди привыкли к разделению строк, а код желательно делать
максимально легкочитаемым для человека.
Готов поспорить, что многие ошибки в ваших программах будут возникать из-за того, что вы будете забывать
ставить точку с запятой в конце выражений, но после пятитысячной ошибки приучите себя. К счастью, Visual
C# Express достаточно умен, чтобы понять, что что-то не так, и подчеркнет ошибку красной волнистой
линией или иным образом укажет на нее, показав как глупо вы поступили.
В русском языке для
группировки
связанных между
собой выражений мы
используем абзацы.
if ( userAnswer ==
correctAnswer )
class MyClass
class MyClass
{
{
int
numberOfSpots;
int
numberOfSpots;
{
Console.WriteLine(
"Правильно!" );
}
score = score + 1;
А
public void
Main()
}
AskNextQuestion();
В языке C# мы
используем фигурные
скобки «{» и «}»
подобным образом.
Такие скобки
используются в
начале и в конце
блока, который
объединяет группу
выражений.
Рассмотрим пример.
Допустим, есть
программа, которая
задает вопросы
пользователям и
проверяет их ответы.
Предположим, что
только в случае
правильного ответа
будут выполняться
два действия. Можно
написать следующий
код:
Два
выражения в фигурных
скобках будут
выполняться, если
пользователь дает
правильный ответ,
поэтому они были
сгруппированы в один
блок.
при написании
метода в классе
его выражения
также
группируются при
помощи фигурных
скобок:
{
MyClass x = new
MyClass();
x.numberOfSpots
= 365;
}
}
В этой книге вам уже
встретилось много других
примеров с фигурными
скобками. Каждый раз при
определении класса весь его
код помещается в фигурные
скобки:
Во многих книгах можно увидеть примечания или комментарии на полях или внизу страниц. Такие
комментарии не являются частью основного текста, и, как правило, служат дополнениями, задачей которых
является дать пояснение к основному тексту.
Интересно, а можно ли то же самое сделать в компьютерных программах? Да, конечно. Скорее всего, вам
часто нужно будет включать комментарии для себя или других программистов, чтобы дать пояснение к
своему коду, что считается хорошей привычкой. Само собой, программист должен уметь сам понимать
программу, но зачем тратить чужое время, когда краткий комментарий на русском даст быстрое пояснение к
вашему коду.
А если вы думаете, что код никто кроме вас читать не будет, то поверьте, когда через несколько месяцев вы
вернетесь к своей программе, то задумаетесь о том, что и к собственному коду надо было писать
комментарии.
Поскольку комментарии предназначаются людям, а не компьютеру, нужно каким-то образом сообщить
машине, что все написанное в разделе комментариев нужно пропускать.
Для этого существует два способа.

Комментарии, умещаемые в одну строку, можно просто обозначить символом двойной косой черты
(«//») в начале.

Многострочные комментарии можно скрыть от компьютера при помощи символов «/*» в начале и
«*/» в конце.
В приведенном ниже тексте кода показаны оба типа комментариев, обозначенных по-разному.
void DrawCircleInSquare( int left, int top, int size)
/*
Данный метод рисует красную окружность.
Подстановка размера окружности в параметр «size».
Подстановка координат рисования в параметры «left» и
«top»..
*/
{
Graphics g = this.CreateGraphics(); // Подготовка области
рисования
Pen redPen = new Pen(Color.Red, 3); // Использование
красной ручки
// Рисование квадрата (прямоугольник, у которого все
стороны равны)
g.DrawRectangle( redPen, left, top, size, size );
// Рисование окружности (эллипс, вписанный в квадрат)
g.DrawEllipse( redPen, left, top, size, size );
// Очистка
g.Dispose();
}
Встречая символ «//», компьютер пропускает всю строку. Но когда встречается символ «/*», пропускается
весь текст до следующего символа «*/».
Как вы наверное уже заметили, мы старались придерживаться отступов кода, например:
if ( userAnswer == correctAnswer )
{
Console.WriteLine( "Правильно!" );
score = score + 1;
if ( score > 10 )
{
Console.WriteLine( "Тест пройден!" );
}
else
{
Console.WriteLine( "Плохо! Продолжайте." );
}
}
вместо того, чтобы смешивать все:
if ( userAnswer == correctAnswer )
{
Console.WriteLine( "Правильно!" );
score = score + 1;
if ( score > 10 )
{
Console.WriteLine( "Тест пройден!" );
}
else
{
Console.WriteLine( "Плохо! Продолжайте." );
}
}
Структурирование кода необходимо для того, чтобы можно было четко видеть, где начинается, а где
заканчивается блок кода. По мере того, как ваши программы будут становиться длиннее, начало и конец
блока будет все сложнее найти. Структурирование намного упрощает чтение кода для его понимания.
Однако, отсутствие отступов не нарушает код, поскольку структурирование не является грамматическим
требованием, но считается хорошей практикой и это нужно взять в привычку.
Для создания отступа текста кода в C# Express можно выделить одну или несколько строк кода и нажать
клавишу TAB на клавиатуре. Чтобы отменить структурирование, удерживайте нажатой клавишу «SHIFT» и
нажмите «TAB». Кроме того, можно воспользоваться кнопками
на панели инструментов.
Слово «переменный» означает «изменяемый». Значение переменной может изменяться.
Вот типичный пример возможности использования переменной. В этом случае мы вызываем переменную
«theAnswer», так как нам необходимо, чтобы она содержала результат суммы, хотя можно выбрать любое
другое имя.
int addPositiveNumbers( int x, int y )
{
int theAnswer;
if ( (x>0) && (y>0) )
// Если x и y положительные
числа
{
theAnswer = x + y;
// Сложение чисел и помещение суммы в
ответ
}
else
// В противном случае
{
theAnswer
= 0;
// Результат — ноль
}
return theAnswer;
}
В этом примере переменная «theAnswer» используется для хранения суммы любых чисел, подставляемых в
параметры x и y. В конце мы возвращаем значение, хранящееся в theAnswer.
Следует отметить, что переменная «theAnswer» на самом деле всего лишь область в памяти компьютера.
Когда компьютер встречает строку «int theAnswer», он находит свободную ячейку в памяти и называет ее
«theAnswer». При достижении строки «return theAnswer» число, хранящееся в переменной «theAnswer»
извлекается из памяти. В приведенном выше примере память будет очищена для других целей, поскольку
ответ на вопрос был получен.
Все вполне естественно
В процессе мышления люди тоже используют участки памяти для хранения ответов, но это происходит
самопроизвольно. Предположим что вам нужно:

сложить числа 10, 20 и 50

затем умножить результат на 2.
Вероятно, логика решения будет следующей:

Сложение чисел 10 и 20. Запоминание результата (30).

Сложение чисел 30 и 50. Теперь запоминание этого результата (80).

Вычисление значения выражения 80 x 2. Запоминание результата до того момента, когда его нужно
будет сообщить тому человеку, который задал эту задачу.

После того, как будет сделано все, что от вас требовалось, вы перестаете прилагать усилия к
запоминанию — результат более не имеет значения и память необходимо освободить для других
целей.
Так что мы не так уж и отличаемся в этом отношении от своих цифровых друзей.
Переменные всегда имеют определенный тип
Переменная на самом деле похожа на поле или параметр, за исключением того, что она не имеет никакого
прямого отношения к определенному классу или объекту. Нам необходима всего лишь временная область для
хранения значения, чтобы с ним можно было работать.
Переменные, как и поля (которые, фактически, являются разновидностью переменных), всегда имеют
определенный тип. Например.
string myString;
int theAnswer;
bool isFinished;
(Если вы еще не прочитали главу «Поля и типы полей», рекомендуется сделать это, чтобы больше узнать о
типах.)
Допустим, в своей программе вы используете следующий код:
int theAnswer = x + y;
и еще где-то пишете
int theAnswer = x - y;
В первом случае вы используете символ для сложения, а во втором — для вычитания. Такие действия с
числами называются операциями а их символы «+» и «-» называются операторами и они выполняют
операции с объектами. Оператор берет один или более объектов, выполняет с ними операции и выдает
некоторый результат.
На следующем рисунке показана операция с оператором плюса для двух чисел. В этом примере
принимаются значения 5 и 2 и выдается значение 7
А оператор минуса принимает те же значения, но выдает другой результат:
Все языки программирования имеют, по меньшей мере, несколько операторов и очень важно их знать.
Давайте рассмотрим те, которые часто встречаются в языке C#.
Симв
ол
Операц
ия
Описание
+
сложени 
е2
объекто
в
При
использован
ии типов
чисел
решение
выполняется
как в
математике.
Например,
25 + 5 = 30.

При
использован
ии строк они
«стыкуются»
.
Например,
результатом
сложения «как»
+ «поживаете»
+ «?» будет
более длинная
строка «как
поживаете?».
-
вычитан 
ие двух
объекто
в
Выполн
яется как в
математике.
Например,
25 - 5 = 20
/
деление 
Поскол
ьку на
клавиатуре
отсутствует
клавиша
«÷», символ
косой черты
означает
«делить».
Например,
20 / 5 = 4.
*
умножен 
ие
Умноже
ние
выполняется
как в
математике.
Например,
25 * 5 = 125
>
Знак
больше

Пример
1.
Результатом
выражения 5
> 2 будет
«истина»

Пример
2.
Результатом
выражения 5
> 17 будет
«ложь»
<
Знак
меньше

Пример
1.
Результатом
выражения 2
< 3 будет
«истина»

Результ
атом
выражения
12 < 11
будет
«ложь»
=
Знак

равенств
а
Этот
знак
используется
для
приравниван
ия
переменной
к какомулибо
значению.

Пример
1. int x =
512;

Пример
2. string y =
«Привет, как
дела?»;
==
Знак

проверк
и
условия
равенств
а
Исполь
зуется для
проверки
равенства
двух
объектов.

Пример
1. Значением
13 == 70
очевидно
будет
«ложь»

Пример
2. Значением
x == 15
будет
«истина»,
если x имеет
значение 15

Пример
3. «ПРИВЕТ»
=
«привет».To
UpperCase()
даст
результат
«истина»
<=
Знак
меньше
или
равно

Пример
1.
Результатом
выражения 2
<= 3 будет
«истина»

Пример
2.
Результатом
выражения 2
<= 2 будет
«истина»

Пример
3.
Результатом
выражения 2
<= 1 будет
«ложь»
>=
Знак

Пример
больше
или
равно
1.
Результатом
выражения
23 >= 23
будет
«истина»

Пример
2.
Результатом
выражения
23 >= 2
будет
«истина»

Пример
3.
Результатом
выражения
23 >= 33
будет
«ложь»
!
Не

Пример
: !( 5 > 17 )
означает «в
этом случае
5 не больше
17»?
Результатом
будет
«истина»,
поскольку 5
не больше
17.
!=
Знак

неравен
ства
Этот
знак
позволяет
легко
проверить
«неравенств
о» объектов.

Пример
:
Результатом
5 != 12
будет
«истина»,
поскольку 5
не равно 12.
&&
Логичес 
кое И
Это
выражение
позволяет
проверить
истинность
нескольких
объектов. В
следующем
примере
проверяется
правильность
пароля и
имени
пользователя
.
||
Логичес 
кое ИЛИ
Символ
«||» (или)
позволяет
проверить
истинность
любого
if ( ( pwd
== 'Pass')
&& (user ==
'jim') )
return true;
Можно также
легко
проверить два
условия, так
как
ограничение
на количество
символов &&
в выражении
отсутствует.
if ( (
favcolor ==
'green') ||
(age < 12) )
return true;
объекта из
группы
объектов. В
следующем
примере
выполняется
проверка
является ли
зеленый цвет
любимым
цветом ИЛИ
значение
возраста
больше 12.
++
инкреме 
нт
Инкрем
ент означает
увеличение
на 1

В
следующем
примере на
экран
сначала
выводится
число 15,
int x = 15;
x++;
Console.Write x = x + 1;
Line( x );
Также можно
написать
Console.Write «++x»
Line( x );
(префиксная
нотация)
x++;
вместо «x++»
Console.Write (постфиксная
нотация), но
Line( x );
x++;
int x = 15;
Console.WriteLin
e(x++);
//
выводится x с
последующим
приращением
Console.WriteLin
e(x);
//
выводится x
Console.WriteLin
e(++x);
//
1
5
1
6
1
7
1
7
затем 16 и
далее 17.
Это
происходит
потому, что x
начинается
со значения
15, но затем
увеличиваетс
я на 1
каждый раз
при
выполнении
строки x++.
--
декреме 
нт
Декрем
ент означает
уменьшение
на 1

В этом
примере на
экран
сначала
выводится
число 15,
затем 14 и
далее 13.
Это
происходит
потому, что x
начинается
со значения
15, но затем
уменьшается
на 1 каждый
раз при
выполнении
строки x--.
приращение x с
эти две
нотации могут последующим

выводом на экран
Использова действовать
по-разному.
Console.WriteLin
ние
e(x);
//
Различие
символов
выводится
x
между ними
«++»
аналогично продемонстри Результаты
ровано в
использован
приведенного
следующем
ию «+ 1».
выше кода будут
примере:
Следующие
следующими:
две строки
выполняют
одно и то же
действие:
int x = 15;
x--;
Console.Write x = x - 1;
Line( x );
Как и в случае
с оператором
Console.Write «++», вместо
Line( x );
«x--» можно
также
x--;
использовать
Console.Write «--x». В
следующем
Line( x );
примере
продемонстри

Использова рована разница
между двумя
ние
символов «-- нотациями.
»
аналогично
использован
ию «-1».
Следующие
две строки
выполняют
одно и то же
действие:
x--;
int x = 15;
Console.WriteLin
e(x--);
//
выводится x с
последующим
уменьшением
Console.WriteLin
e(x);
//
выводится x
Console.WriteLin
e(--x);
//
уменьшение x с
последующим
выводом на экран
Console.WriteLin
e(x);
//
выводится x
Результаты
приведенного
выше кода будут
следующими:
Ну и в заключение рассмотрим еще один вариант с оператором «--». В этом случае оператор принимает
только одно число и выдает также одно число. Выдаваемое число на 1 меньше, чем исходное.
1
5
1
4
1
3
1
3
Допустим, мы включили следующий код в программу:
// Объявление некоторых переменных
int x;
string y;
int z;
// Подстановка значений в x и y
x = 5;
y = "17";
// Вычисление произведения x и y и подстановка результата в
z
z = x * y;
Последняя строка в приведенном выше примере вызовет ошибку. Причина заключается в том, что умножение
строк не допускается, а «y» имеет строковый тип. Написание такого кода это то же самое как вопрос
«Сколько будет 5 умноженное на веселый?» Вычисление попросту невозможно. Строки не могут принимать
значения числовых типов и математические операции с ними выполнять нельзя.
К счастью, строки можно преобразовать в числа. В приведенном далее примере показано как можно решить
описанную проблему, поскольку строку «17» можно разумно преобразовать в число 17. Нужно просто
немного изменить последнюю строку программы.
z = x * Convert.ToInt32( y );
Мы использовали класс Microsoft «сonvert» и вызвали его метод «ToInt32», который выполняет
преобразование в один из типов целых чисел. Теперь, когда значение «y» преобразовано в целое число,
компьютер успешно перемножит два числа.
В классе «сonvert» доступно несколько методов, но чаще всего вам потребуются следующие:

Convert.ToInt32()

Convert.ToString()

Convert.ToBoolean()
Важно помнить, насколько чувствительны компьютеры к типам данных.
Приведение типов
Другим способом изменения типов данных является так называемое их приведение. Приведение объекта
означает его преобразование в другой тип, но в отличие от примеров с «сonvert» выше, оно работает только
в тех случаях, когда изменяемый тип очень похож на целевой. Приведение помогает, например, при
преобразовании между двумя числовыми типами данных, а для преобразования между числовыми и
строковыми типами данных не имеет смысла. Порядок написания приведения также сильно отличается от
показанных выше примеров. Перед преобразуемой переменной необходимо в круглых скобках указать в
какой тип выполняется преобразование.
Прежде чем мы приведем пример, необходимо познакомить вас с другим числовым типом — «double». Тем из
вас, кому по школьному курсу математики или естественных наук знакомо экспоненциальное представление
чисел, известно, что типы «double» и «float» очень похожи на это — они позволяют работать с десятичными
числами с «плавающей» десятичной запятой. Например 5,0x103 это то же самое число, что и 50,0x102 или
0,50x104 и так далее.
int x;
double y;
int theAnswer;
x = 10;
y = 15;
theAnswer = x + (int) y;
Код (int) y выполняет преобразование «y» в целое число.
Кстати, определенное приведение типов будет выполняться, только если значение «y» можно правильно
преобразовать в целое число. То есть в показанных выше примерах преобразование будет выполнено, но
если «y» будет иметь значение 15,5, код выполнен не будет. В реальной программе вы возможно дополните
код элементом Math.Round(y), чтобы сначала происходило округление «y» до целого числа.
Возможно, вам не потребуется использовать приведение типов в своих первых программах, но вы будете
замечать их в программах других людей при просмотре их кода. Но, по крайней мере, сейчас вы будете
знать, что к чему.
Часто, когда необходимо, чтобы программа выполняла определенное действие, выполняемая следующей
строка зависит от определенного условия. Программа должна направляться по одной «ветви» в одном
случае, и другой «ветви» в другом случае. Для этого в C# существует две структуры ветвления: выражение if
и выражение switch . В этой главе мы не станем обсуждать выражение switch, поскольку оно более сложное,
а того же результата можно добиться при помощи выражения if .
Выражение if очень просто для понимания. Оно позволяет проверить истинность определенного факта, и
если он является истинным, компьютер выполняет код в соответствующем блоке. В противном случае,
осуществляется переход к следующему блоку для его проверки. Переход по блокам продолжается до тех пор,
пока не будет найден истинный факт или до конца всего блока if.
if ( UserAnswer == "Белоголовый орлан" )
{
Console.WriteLine("Да, вы абсолютно правы!");
}
else if ( UserAnswer == "Орел" )
{
Console.WriteLine("Не совсем. Правильный ответ —
Белоголовый орлан.");
}
Часто конечный блок «else» тоже нужно будет размещать в конце, так чтобы в случае ложности всех условий
предыдущих блоков выполнялся код в блоке «else».
if ( UserAnswer == "Белоголовый орлан" )
{
Console.WriteLine("Да, вы абсолютно правы!");
}
else if ( UserAnswer == "Орел" )
{
Console.WriteLine("Не совсем. Правильный ответ —
Белоголовый орлан.");
}
else
{
Console.WriteLine("Вы ошиблись. Попробуйте снова.");
}
Что если некоторые действия необходимо повторить несколько раз? Например, вам нужно написать числа от
1 до 10. Было бы неразумным делать это следующим образом:
Console.WriteLine("Number " + 1 );
Console.WriteLine("Number " + 2 );
Console.WriteLine("Number " + 3 );
Console.WriteLine("Number " + 4 );
Console.WriteLine("Number " + 5 );
Console.WriteLine("Number " + 6 );
Console.WriteLine("Number " + 7 );
Console.WriteLine("Number " + 8 );
Console.WriteLine("Number " + 9 );
Console.WriteLine("Number " + 10 );
И это было бы ЕЩЕ БОЛЕЕ неразумным, если бы потребовалось написать числа от 1 до 15000!
Вот где нам пригодятся циклы! Для многократного выполнения одних и тех же операций нужно совсем
немного кода. В C# существует несколько типов циклов, но мы рассмотрим только два из них.
Циклы For обычно используются для целей счета. Цикл FOR можно представить следующим образом:

задается некоторое значение счетчика (например, 0)

начинается отсчет до определенного значения (например, 11)

каждый раз счетчик выполняет определенное действие (например, прибавляет 1)
Следующий отрывок кода состоит из всего лишь 3 строк и делает то же самое, что и 10 строк кода выше.
for ( int x = 0; x < 11; x = x + 1 )
{
Console.WriteLine( "Number " + x );
}
Кстати, очень часто приведенный в предыдущем примере цикл можно увидеть в следующей форме:
for ( int x = 0; x < 11; x++ )
{
Console.WriteLine( "Number " + x );
}
Нотация вида «x++» — «ленивый» (хотя аккуратный и короткий) вариант написания «x = x + 1».
Циклы «for» можно также использовать для обратного отсчета. Для этого счетчик должен просто выполнять
вычитание вместо сложения.
for ( int x = 11; x > 0; x-- )
{
Console.WriteLine( "Number " + x );
}
Здесь говорится: «отсчет начинается с x равным 11, и до тех пор пока x больше или равен нулю, из него
вычитается 1».
Цикл «while» можно представить следующим образом: «пока сохраняется истинность какого-либо условия,
этот блок кода продолжает выполняться».
При помощи циклов «while» можно добиться тех же результатов, что и с циклом «for», описанным выше, но в
следующем примере счетчик не используется. Данный код просит пользователя набрать слово «дымчатый»
на клавиатуре. Только когда пользователь набирает слово правильно, цикл прекращается и выдается
сообщение «Спасибо!». Обратите внимание, что каждый раз проверяется условие «s != дымчатый», что
означает «пока набираемое слово не равно «дымчатый».
string s = "";
while ( s != "дымчатый" )
{
Console.WriteLine("Наберите слово «дымчатый»: ");
s Console.ReadLine()
}
Console.WriteLine("Спасибо!");
В следующем примере цикл «while» делает то же, что и цикл «for», как было показано в примере ранее. Мы
просто включаем переменную (x в данном случае) для использования в качестве счетчика.
int x = 0;
while ( x < 11 )
{
WriteLine( "Number (число) " + x );
x = x + 1;
}
Как видно, x начинается с нуля и 1 добавляется при каждом прохождении цикла. При этом компьютер снова
и снова проверяет условие «x по-прежнему меньше одиннадцати?» В итоге x становится равным 11, и цикл
прекращается.
Бесконечные циклы
Хотите попробовать кое-что действительно глупое? Исключите строку x = x + 1. Таким образом, значение x
НИКОГДА не будет увеличиваться, и, следовательно, ВСЕГДА будет меньше 11, а цикл будет повторяться
БЕСКОНЕЧНО или, по меньшей мере, до тех пор, пока компьютер не выдаст сообщение об ошибке о нехватке
памяти. При каждом написании бесконечного цикла вы будете несколько озадачены.
Введение
В предыдущих главах мы рассмотрели определенные понятия и увидели, как их можно передать компьютеру.
Но мы не затронули вопросы структуры программы. С чего нужно начинать программу, и какие части должны
присутствовать в ней, чтобы она работала.
Итак, в этой главе мы рассмотрим основную структуру программы на языке C#. Главная задача не запутаться
в деталях, а просто понять основную структуру программы — ее скелет.
Различные типы программ C#
Если вы отправитесь в горы на выходные, то там соорудите себе палатку, а не дом для которого необходим
прочный фундамент. Вы будете использовать конструкцию, приемлемую в окружающих вас условиях.
Палатки и дома, в принципе, одно и то же, но палатки специально предназначены для туристических целей.
Подобным образом структуру C# и .NET можно использовать для создания приложений для различных сред.
В каждом случае используется один и тот же язык, но структурирование программы имеет некоторые
определенные отличия в зависимости от среды. Вот несколько примеров различных типов программ C#.

Приложения Windows Forms

Библиотеки классов

Службы Windows

Консольные приложения

Веб-приложения ASP.NET
В рамках этой книги нас интересуют только два типа программ — консольные приложения и приложения
Windows Forms. Но знания, полученные при работе в этих двух средах, также пригодятся при разработке
других типов приложений.
Структура консольных приложений
Консольное приложение способно только отображать и считывать текст без изображений, графиков и т.д.
Если вы хоть раз открывали командную строку и набирали команду типа DIR для просмотра списка файлов,
значит, вам уже приходилось работать с консольным приложением. Если вам необходимо что-то быстро
попробовать или вы хотите написать программу, от которой не требуется ничего, кроме текста, то вашим
выбором станет консольное приложение, поскольку это самый простой тип программы, которую можно
написать на C#.
Вот пример простого, но законченного консольного приложения:
1. using System;
2.
3. class PleaseSayYo
4. {
5.
static void Main()
6.
{
7.
Console.WriteLine("Yo!");
Console.ReadLine();
8.
}
9. }
И вот что вы увидите на экране при выполнении программы. Это будет просто строка текста:
Программа совсем небольшая, правда? Но давайте разобьем ее на части и обсудим структуру.

Строка 1 говорит компьютеру, что далее в нашей программе будет использоваться некоторый класс
из пространства имен «System». Определенный класс, чей код будет использоваться это «Console».
Этот класс написан разработчиками Microsoft и содержит все необходимые элементы для консольных
приложений. Чтобы не писать много строк кода для выполнения какого-либо простого действия,
например вывода слова на экран, мы просто вызываем метод «WriteLine» из класса System.Console.

В строках с 3 по 9 определяется класс. В него мы включаем свою программу путем указания свойств
и методов. В этом конкретном классе нет свойств (просто они не нужны), но присутствует один
метод.

В строках с 5 по 8 мы определяем метод. Этот метод очень похож на те, которые мы уже обсуждали в
этой книге, но есть одна особенность: его имя ДОЛЖНО быть «Main» и мы не можем выбирать
собственное имя. Когда система получит запрос на выполнение программы C#, ей потребуется знать
с чего начать выполнение. Нас учили, что для программ на C# программист всегда использует метод
«Main» и именно здесь начинается выполнение программы — в точке входа. Этот метод можно
разместить в любом месте класса (в начале, в конце или где угодно) и система всегда найдет его по
имени «Main».

В строке 7 мы вызываем метод «WriteLine» из класса System.Console, который выводит указанный
нами текст.
Возможности консольных приложений безусловно гораздо шире, чем мы показали в этом примере, и они, как
правило, написаны с большим количеством кода, но обычно начинаются с основной структуры, как было
продемонстрировано в двух примерах выше.
Статические методы
Вам может показаться странным слово «static» в программе выше. Чтобы объяснить смысл этого слова,
давайте сначала рассмотрим немного более сложный пример консольного приложения. Внимательно
прочитайте метод «Main». Понимаете, какое действие он выполняет?
1. using System;
2.
3. class SimpleConsoleApp
4. {
Public
6.
Sub MySimpleMethod()
{
7.
8.
Console.WriteLine("Yo!");
}
9.
10.
static void Main()
11.
{
12.
SimpleConsoleApp s;
13.
s = new SimpleConsoleApp();
14.
s.MySimpleMethod();
15.
}
16. }
В данном примере объектно-ориентированный подход действительно раскрывается лучше, чем в
предыдущем. Вместо написания кода непосредственно в методе «Main», в строках 12 и 13 мы объявили и
построили объект, являющийся экземпляром данного класса. Затем в строке 14 мы вызвали метод этого
объекта.
Вы заметите, что в методе «MySimpleMethod» отсутствует слово «static» в начале, в то время как в методе
«Main» оно есть. И вот почему.

Слово «static» добавляется в начало определения метода, если этот метод не предполагается
использовать для выполнения действий с определенным объектом.

Теперь, поскольку метод «Main» является «точкой входа», он вызывается перед построением
любого объекта, поэтому его необходимо определить как «static».
Рассмотрим другой пример для объяснения концепции «static». Обратите особое внимание на текст,
выделенный полужирным шрифтом.
using System;
class SchoolTest
{
public string testName;
public decimal total;
public decimal myScore;
// Метод-конструктор этого класса
public SchoolTest(string tn, int s, int tot)
{
this.testName = tn;
this.myScore = s;
this.total = tot;
}
// Метод STATIC для расчета процентной доли ЛЮБЫХ двух
чисел
public static decimal CalculateAnyPercentage(decimal
numerator, decimal denominator)
{
decimal percentage = (numerator / denominator) *
100;
return percentage;
}
// Метод INSTANCE для расчета процентной доли экземпляра
SchoolTest
public decimal CalculateThisPercentage()
{
decimal percentage = (this.myScore / this.total)
* 100;
return percentage;
}
static void Main()
{
// Использование метода «static» для расчета процентной
доли без какого-либо экземпляра
Console.WriteLine("123/200 = " +
SchoolTest.CalculateAnyPercentage(123, 200));
// Создание нового экземпляра SchoolTest, подстановка в
результаты
SchoolTest t = new SchoolTest("Geography", 12, 60);
// Использование метода «instance» для расчета процентной
доли этого экземпляра
Console.WriteLine( "Percentage for test = " +
t.CalculateThisPercentage() );
// Ожидаем нажатия клавиши ВВОД
Console.ReadLine();
}
}
Обратите внимание, мы применили два очень похожих метода. Оба они рассчитывают процентные доли, но
используются по-разному. Метод со словом «static» можно использовать без объявления экземпляра new
SchoolTest() , в то время как другой может работать ТОЛЬКО с экземпляром. В приведенном выше примере
наш экземпляр имеет имя «t».
Можно сказать, что методы «static» работают где угодно, в то время как методы с экземплярами могут
действовать только при наличии фактического объекта, и более того, только внутри него.
Структура приложений Windows Forms
Теперь, когда вы узнали об общей структуре консольных приложений, вам будет легче перейти к более
сложным типам программ, поскольку основная структура остается прежней. Перед вами пример простого
приложения Windows Forms.
using System.Windows.Forms;
class SimpleWindowsApp : Form
{
// Метод-конструктор
public SimpleWindowsApp()
{
this.Text = "Очень простая форма";
}
// Точка входа для программы
static void Main()
{
Application.Run( new SimpleWindowsApp() );
}
}
В этом примере использовались два новых элемента:
1.
Часть «: Form»
Здесь говорится: «мой класс наследует все объекты из класса Form». Этот очень важный секрет
раскрывается в главе «Наследование». Разработчиками корпорации Microsoft написан большой
набор классов, которым известно как создавать кнопки, меню, рамки изображений, независимые
кнопки и другие элементы, которые можно использовать в приложениях. Путем простого добавления
«: Form» ваш собственный класс сразу получает доступ ко всем таким элементам.
2.
Строка «Application.Run». Это обычный способ запуска приложений форм Windows. Этот метод
«выполняет» приложение. В него подставляется новый экземпляр вашего класса.
В реальном мире библиотека — это место, где находится огромное количество книг и других источников
информации. Когда людям требуется информация, им не приходится делать повторные открытия и писать
собственные книги, они могут просто найти нужные, сохранив тем самым массу времени и усилий.
Точно также разными людьми по всему миру написаны огромные библиотеки кода на языке C#. Поэтому
имеет смысл использовать для программы другие библиотеки помимо собственных.
Для этого придется исследовать библиотеку и понять, какие части могут оказаться полезными вам, но это
того стоит, поскольку позволяет сконцентрироваться над тем, что должна делать ваша программа, а не терять
массу времени на написание второстепенного кода.
Наиболее важная библиотека по C# это библиотека классов Microsoft «.NET Framework Class Library». Любую
полезную программу не напишешь без использования этой библиотеки. Часть IV нашей книги посвящена
исключительно ей. При установке .NET Framework на компьютере она загружается автоматически и
становится доступной для ваших программ. Нужно научиться пользоваться библиотекой и использовать ее в
своих программах.
Пример
Раздел «System.Drawing» библиотеки классов .NET Framework Class Library содержит много полезных классов
для работы с изображениями. Давайте посмотрим, что можно взять из него, чтобы продемонстрировать
возможность использования чужого кода в своей программе.
Класс System.Drawing.Image имеет метод под названием RotateFlip, который позволяет вращать
(поворачивать) или переворачивать (отражать) любое подставляемое изображение. Допустим, вы решили
использовать этот метод в своей программе. Программа должна загружать файл изображения с диска,
переворачивать его по горизонтали и сохранять копию перевернутого изображения обратно на диск.
Рассмотрим один из возможных способов. Ниже приводится законченная, рабочая программа. (Если будете
экспериментировать, обратите внимание, что программа 9 из набора примеров к этой книге, содержит
аналогичный код.)
class PhotoSizer
{
public PhotoSizer()
{
// Загрузка фотографии с диска в память компьютера
System.Drawing.Image img;
img = new System.Drawing.Bitmap(@"d:\samples\myDog.jpg");
// Переворачивание изображения по горизонтали
img.RotateFlip(
System.Drawing.RotateFlipType.RotateNoneFlipX );
// Сохранение перевернутой фотографии в другой файл на
диске
img.Save( @"d:\samples\myDogFlipped.jpg" );
}
static void Main()
{
PhotoSizer p = new PhotoSizer();
}
}
Небольшое примечание к символу «@»:
Символ @ в языке C#, использованный выше, можно добавлять в начало строки для «подстановки» или
пропуска символов обратной косой черты, если в указании пути содержатся специальные символы, такие как
обратная косая черта. Символы обратной черты могут нарушить выполнение кода C#, поскольку имеют
особое значение. Обычно путь указывается с помощью двойной обратной косой черты
(d:\\samples\\myDog.jpg), а символ «@» позволяет избежать этого.)
В приведенном выше примере мы использовали класс «Image» из библиотеки «System.Drawing».
После создания объекта Image мы вызываем два метода класса изображения. Названия методов RotateFlip и
Save.
Более простой вариант
Можно заметить, что каждый раз, когда необходимо описать что-то в пространстве System.Drawing, требуется
снова писать эти длинные слова. Чтобы этого избежать можно в начале программы при помощи ключевого
слова «using» один раз сообщить о том, что из пространства имен System.Drawing будут использоваться
несколько элементов, а также несколько элементов из пространства имен System.Drawing.Imaging.
using System.Drawing;
using System.Drawing.Imaging;
class PhotoSizer
{
public PhotoSizer()
{
// Загрузка фотографии с диска в память компьютера
Image img = new Bitmap(@"d:\samples\myDog.jpg");
// Переворачивание изображения по горизонтали
img.RotateFlip( RotateFlipType.RotateNoneFlipX );
// Сохранение перевернутой фотографии в другой файл на
диске
img.Save( @"d:\samples\myDogFlipped.jpg" );
}
static void Main()
{
PhotoSizer p = new PhotoSizer();
}
}
Замечание о ссылках в C# Express
При создании проекта в C# Express необходимо создать так называемую «ссылку» на файл библиотеки
классов с кодом библиотеки, который требуется использовать (эти файлы имеют расширение «.dll» —
Dynamic Link Library). К счастью, наиболее распространенные ссылки добавляются автоматически.
Например, на рисунке ниже показаны ссылки, добавляемые при создании проекта «Windows Application».
Visual C# Express выбирает разделы библиотеки, которые предположительно могут использоваться для
такого приложения.
В приведенном выше примере можно заметить, что классы пространства имен System.Drawing хранятся в
файле System.Drawing.dll.
Если ссылка на раздел библиотеки, который вы планируете использовать, не была включена автоматически,
ее нужно добавить самостоятельно. Допустим, вы нашли пример кода с классом System.Web.HttpRequest для
получения некоторой информации с веб-сервера и хотите проверить его. Нужно щелкнуть References
(«Ссылки»), выбрать Add reference(«Добавить ссылку») и затем выбрать раздел библиотеки System.Web.
Теперь вы обнаружите, что классы библиотеки можно использовать в своем коде.
Заключение
Итак, использовать код из библиотеки очень просто. Сложнее узнать какие классы, методы и прочие
элементы можно использовать из этой обширной библиотеки.
Именно поэтому в IV части книги будет рассказано о некоторых полезных разделах библиотеки классов
Microsoft .NET Framework.
Download