Теоретические сведения

Лабораторная работа №1

Тема: «Основы языка С#, знакомство со средой Microsoft Visual Studio 2008, введение в объектно-ориентированное программирование»

Цель работы: Изучить теоретический материал, научиться создавать консольные приложения в среде Microsoft Visual Studio 2008, реализовать примеры, приведенные в работе. Выполнить задания согласно вариантам по номеру в журнале.

 

Теоретические сведения

Главное в языке С# - реализация принципов объектно-ориентированного программирования (ООП). Объектно-ориентированная методика неотделима от С#, и все С# - программы в какой-то степени имеют объектную ориентацию.

ООП – это мощный «рычаг», позволяющий усовершенствовать процесс программирования. С момента изобретения компьютера методы программирования менялись много раз, и причем коренным образом, но в основном с целью адаптации к непрерывному повышению сложности программ. Например, программирование для первых компьютеров осуществлялось посредством набора машинных инструкций (в двоичном коде) на передней панели компьютера. Этот метод работал до тех пор, пока длина программы не превышала несколько сот инструкций. С ростом программ был изобретен язык assembler, который позволил программисту писать гораздо большие и более сложные программы, используя символическое представление машинных инструкций. По мере роста программ появились языки высокого уровня (например, Fortran и Cobol), которые позволили программистам справляться с возрастающей сложностью программ. Когда эти первые компьютерные языки начали приближаться к критическому состоянию, было изобретено структурное программирование.

Каждая веха в развитии программирования характеризовалась созданием методов и средств, позволяющих программисту писать все более сложные программы. С каждым шагом на этом пути изобретался новый метод, который, опираясь на самые удачные элементы предыдущих методов, вносил что-то свое, осуществляя, таким образом, прогресс в области программирования в целом. Примерно по такой схеме развития инструментария для программистов «дошло дело» и до объектно-ориентированного программирования. Его появлению способствовал тот факт, что реализация новых проектов начала серьезно стопориться, поскольку структурный подход уже не справлялся с поставленными задачами. Нужен был новый способ преодоления сложности программ, и решением этой проблемы стало объектно-ориентированное программирование.

Объектно-ориентированное программирование вобрало в себя лучшие идеи структурного программирования и объединило их с новыми концепциями. В результате появился более совершенный способ организации программы. Если говорить в самых общих чертах, программу можно организовать одним из двух способов: опираясь либо на код (т.е. на действия, или на то, что происходит в программе), либо на данные (т.е. на то, что подвергается определенному воздействию). При использовании исключительно методов структурного программирования программы обычно организовывались с опорой на действия. Такой подход можно представить себе в виде кода, воздействующего на данные.

Объектно-ориентированные программы работают совсем по-другому. Они организованы вокруг данных, а ключевой принцип такой организации гласит: именно данные должны управлять доступом к коду. В объектно-ориентированном языке программист определяет данные и код, который разрешен для выполнения действий над этими данными. Таким образом, тип данных точно определяет операции, которые могут быть к ним применены.

Для поддержки принципов объектно-ориентированного программирования все ООП – языки, включая С#, имеют три характерных черты: инкапсуляцию, полиморфизм, наследование.

Инкапсуляция – это механизм программирования, который связывает код (действия) и данные, которыми он манипулирует, и при этом предохраняет их от вмешательства извне и неправильного использования. В объектно-ориентированном языке код и данные можно связать таким образом, что будет создан автономный черный ящик. Внутри этого ящика находятся все необходимые данные и код. При таком связывании кода и данных создается объект. Другими словами, объект – это элемент, который поддерживает инкапсуляцию.

Код, данные или обе эти составляющие объекта могут быть закрытыми внутри него или открытыми. Закрытый код или закрытые данные известны лишь остальной части этого объекта и доступны только ей. Это означает, что к закрытому коду или данным не может получить доступ никакая другая часть программы, существующая вне этого объекта. Если код или данные являются открытыми, к ним (несмотря на то, что они определены внутри объекта) могут получить доступ другие части программы. Как правило, открытые части объекта используются для обеспечения управляемого интерфейса с закрытыми элементами.

Основной единицей инкапсуляции в С# является класс. Класс определяет форму

объекта. Он задает как данные, так и код, который будет оперировать этими данными. В С# класс используется для создания объектов. Объекты — это экземпляры класса. Таким образом, класс - это по сути набор шаблонных элементов, которые показывают, как построить объект. Код и данные, которые составляют класс, называются членами класса. Данные, определенные в классе, называются переменными экземпляра (instance variable), а код, который оперирует этими данными, - методами-членами (member method), или просто методами. «Метод» - это термин, применяемый в С# для обозначения подпрограммы. Если вы знакомы с языками С или C++, то, вероятно, догадываетесь о том, что то, что С# программист называет методом, С/С++ программист назовет функцией. А поскольку С# - прямой потомок C++, термин "функция" также приемлемо использовать, когда речь идет о С# методе.

Полиморфизм (от греческого слова polymorphism, означающего "много форм") – это качество, которое позволяет одному интерфейсу получать доступ к целому классу действий. Простым примером полиморфизма может послужить руль автомобиля. Руль (интерфейс) остается рулем независимо от того, какой тип рулевого механизма используется в автомобиле. Другими словами, руль работает одинаково в любом случае: оснащен ли ваш автомобиль рулевым управлением прямого действия, рулевым управлением с усилителем или реечным управлением. Таким образом, поворот руля влево заставит автомобиль поехать влево независимо от типа используемого в нем рулевого управления. Достоинство такого единообразного интерфейса состоит, безусловно, в том, что, если вы знаете, как обращаться с рулем, вы сможете водить автомобиль любого типа. Тот же принцип можно применить и к программированию. Рассмотрим, например, стек (stack), т.е. область памяти, функционирующую по принципу "последним пришел - первым обслужен". Предположим, вы пишете программу, для которой нужно организовать три различных типа стека. Один стек предназначен для целочисленных значений, второй - для значений с плавающей точкой, а третий - для символов. В этом случае для реализации каждого стека используется один и тот же алгоритм, несмотря на различие в типах сохраняемых данных. В случае не объектно-ориентированного языка вам пришлось бы создать три набора "стековых" подпрограмм, имеющих различные имена. Но благодаря полиморфизму в среде С# можно создать один общий набор "стековых" подпрограмм, который обрабатывает все три

типа стека. Иными словами, зная, как использовать один стек, можно использовать все остальные. Концепцию полиморфизма часто выражают такой фразой: "один интерфейс -

много методов". Это означает, что для выполнения группы подобных действий можно разработать общий интерфейс. Полиморфизм позволяет понизить степень сложности программы, предоставляя программисту возможность использовать один и тот же интерфейс для задания общего класса действий. Конкретное (нужное в том или ином случае) действие (метод) выбирается компилятором. Программисту нет необходимости делать это вручную. Его задача - правильно использовать общий интерфейс.

Наследование - это процесс, благодаря которому один объект может приобретать

свойства другого. Благодаря наследованию поддерживается концепция иерархической классификации. В виде управляемой иерархической (нисходящей) классификации организуется большинство областей знаний. Например, яблоки Красный Делишес являются частью классификации яблоки, которая в свою очередь является частью класса фрукты, а тот - частью еще большего класса пища. Таким образом, класс пища обладает определенными качествами (съедобность, питательность и пр.), которые применимы и к подклассу фрукты. Помимо этих качеств, класс фрукты имеет специфические характеристики (сочность, сладость и пр.), которые отличают их от других пищевых продуктов. В классе яблоки определяются качества, специфичные для яблок (растут на деревьях, не тропические и пр.). Класс Красный Делишес наследует качества всех предыдущих классов и при этом определяет качества, которые являются уникальными для этого сорта яблок. Если не использовать иерархическое представление признаков, для каждого объекта пришлось бы в явной форме определить все присущие ему характеристики. Но благодаря наследованию объекту нужно доопределить только те качества, которые делают его уникальным внутри его класса, поскольку он (объект) наследует общие атрибуты своего родителя. Следовательно, именно механизм наследования позволяет одному объекту представлять конкретный экземпляр более общего класса.

Пример программы:

using System;

class Example

{

/* Пример многострочного комментария */

public static void Main() //объявление члена класса (метода)

{

Console.WriteLine("Программа на языке С#");

Console.ReadKey();

}

}

Несмотря на миниатюрные размеры, программа Example.cs включает ряд ключевых средств, которые применимы ко всем С# программам.

В отличие от некоторых языков программирования (например, java), в которых имя программного файла имеет очень большое значение, С# - программа может иметь любое имя (например, Sample.cs, Test.cs, First.cs и т.д.).

По соглашению для исходных файлов С# - программ используется расширение .cs, и этому соглашению необходимо следовать безоговорочно. Многие программисты называют файл программы по имени основного класса, определенного в этом файле. В примере это класс Example. Далее построчно рассмотрим код программы:

Строка using System; - эта строка означает, что программа использует пространство имен System. В С# пространство имен (namespace) определяет декларативную область. Пространство имен System позволяет хранить одно множество имен отдельно от другого. Другими словами, имена, объявленные в одном пространстве имен, не будут конфликтовать с такими же именами, объявленными в другом. В данной программе используется пространство имен System, которое зарезервировано для элементов, связанных с библиотекой классов среды .Net Framework, используемой языком С#. Ключевое слово using – это своего рода заявление о том, что программа использует имена в заданном пространстве имен.

Строка class example {

В этой строке используется ключевое слово class, которое объявляет об определении нового класса. Как упоминалось выше, в С# класс – это базовая единица инкапсуляции. example – имя определяемого класса. Определение класса заключено между открывающей ({) и закрывающей (}) фигурными скобками. Таким образом, элементы, расположенные между этими двумя фигурными скобками, являются членами класса. В С# работа программы протекает именно внутри класса. Это одна из причин, по которой все С# - программы являются объектно-ориентированными.

Строка public static void Main(){

В этой строке начинается определение метода Main(). В С# подпрограмма называется методом (method). Все С# - приложения начинают выполняться с вызова метода Main(). Ключевое слово public представляет собой спецификатор доступа (access specifier). Спецификатор доступа определяет, как другие части программы могут получать доступ к члену класса. Если объявление члена класса включает ключевое слово public, значит, к этому члену можно получить доступ с помощью кода, расположенного вне класса, в котором этот член объявлен. (Противоположным по значению ключевому слову public является слово private, которое не допускает использования соответствующего члена класса кодом, определенным вне его (члена) класса.) В данном случае метод Main() объявляется как public-метод, поскольку при запуске этой программы он будет вызываться внешним (по отношению к его классу) кодом (а именно операционной системой).

Ключевое слово static позволяет реализовать вызов метода Main() еще до создания объекта соответствующего класса. Это очень важный момент, поскольку метод Main() вызывается при запуске программы. Ключевое слово void просто сообщает компилятору о том, что метод Main() не возвращает значения. Как будет показано выше, методы могут возвращать значения. Пустые круглые скобки после имени Main() говорят о том, что методу не передается никакой информации. Как будет показано выше, методу Main() (или любому другому) можно передавать данные, которые будут им обрабатываться. Рассматриваемую строку венчает символ открывающей фигурной скобки ({), который служит признаком начала тела метода Main(). Между открывающей и закрывающей фигурными скобками и должен находиться весь код, составляющий тело метода.

Строка Console.WriteLine("Программа на языке С#");

Здесь реализован вывод на экран текстовой строки " Программа на языке С#" и следующего за ней символа новой строки. Сам вывод осуществляется встроенным методом WriteLine(). В данном случае на экране будет отображена строка, переданная методу. Передаваемая методу информация называется аргументом. Помимо текстовых строк, метод WriteLine () может отображать и данные других типов. Console – это имя встроенного класса, который поддерживает консольные операции ввода-вывода данных. Связав класс Console с методом WriteLine (), вы тем самым сообщаете компилятору, что WriteLine() - член класса Console. Тот факт, что в С# для определения консольного вывода данных используется некоторый объект, является еще одним свидетельством объектно-ориентированной природы этого языка программирования. Обратите внимание на то, что инструкция, содержащая вызов метода WriteLine(), завершается точкой с запятой, как и рассмотренная выше инструкция программы using System. В С# точкой с запятой завершаются все инструкции. Если же вы встречаете строки программы, которые не оканчиваются точкой с запятой, значит, они попросту не являются инструкциями. Первая в программе закрывающая фигурная скобка (}) завершает метод Main(), а вторая –определение класса Example. И еще. В языке С# различаются прописные и строчные буквы. Игнорирование этого факта может вызвать серьезные проблемы. Например, если случайно вместо

имени Main ввести имя main или вместо WriteLine ввести writeline, то рассмотренная ниже программа сразу же станет некорректной. Более того, хотя С# компилятор компилирует классы, которые не содержат метода Main(), у него нет возможности выполнить их. Поэтому, даже если вы введете имя Main с опечаткой (main), компилятор все равно скомпилирует программу. Но затем вы получите сообщение об ошибке, уведомляющее о том, что в файле Example.exe не определена точка входа.

Задание:Введите, скомпилируйте и выполните рассмотренную выше программу.

Пример 2

class Example

{

/* Пример многострочного комментария */

public static void Main() //объявление члена класса (метода)

{

System.Console.WriteLine("Программа на языке С#");

System.Console.ReadKey();

}

}

Задание:Введите, скомпилируйте и выполните рассмотренную выше программу (пример 2). Какие отличия в ней от первого примера, необходимо также разъяснить их.

Пример 3

using System;

class Example2

{

public static void Main() //объявление члена класса (метода)

{

int x; //здесь объявляется переменная целочисленного типа int

int y; //здесь объявляется переменная целочисленного типа int

x = 100; //здесь переменной х присваивается значение 100

Console.WriteLine(" переменная х содержит: "+ x);

y = x / 2;

Console.Write(" переменная y содержит результат выражения х/2=");

Console.WriteLine(y);

Console.ReadKey();

}

}

 

Задание:Введите, скомпилируйте и выполните рассмотренную выше программу, объясните каждую строку кода.

Другие типы данных

Для обработки чисел с дробной частью в С# предусмотрены два типа данных с плавающей точкой, float и double, которые представляют значения с обычной и удвоенной точностью, соответственно. (Тип double пользуется у программистов "повышенным спросом".)

Для объявления переменной типа double используйте инструкцию, подобную следующей:

double result;

Здесь result - это имя переменной типа double. Поскольку переменная result имеет тип double, она может хранить такие значения, как 122,23, 0,034 или -19,0.

Чтобы лучше понять различие между типами данных int и double, рассмотрим следующую программу:

using System;

class Example3

{

public static void Main() //объявление члена класса (метода)

{

int ivar; //здесь объявляется переменная целочисленного типа int

double dvar; //здесь объявляется переменная целочисленного типа double

ivar = 100;

dvar = 100.0;

 

Console.WriteLine(" исходное значение переменной ivar: " + ivar);

Console.WriteLine(" исходное значение переменной dvar: " + dvar);

Console.WriteLine();//вывод пустой строки

ivar = ivar / 3;

dvar = dvar / 3;

Console.WriteLine("ivar после деления: " + ivar);

Console.WriteLine("dvar после деления: " + dvar);

Console.ReadKey();

}

}

Как видите, при делении переменной ivar на 3 выполняется операция целочисленного деления, результат которой равен 33, т.е. дробная часть отбрасывается. Но при делении переменной dvar на 3 дробная часть сохраняется. Итак, если нужно определить в программе значение с плавающей точкой, необходимо включить в его представление десятичную точку. Если этого не сделать, оно будет интерпретироваться как целое число. Например, в С# число 100 рассматривается как целое, а число 100.0 - как значение с плавающей точкой. Обратите внимание на то, что для вывода пустой строки достаточно вызвать метод WriteLine() без аргументов.

Задание:Введите, скомпилируйте и выполните рассмотренную выше программу, объясните каждую строку кода.

Тип данных с плавающей точкой обычно используется при работе с реальными значениями, т.е. когда необходимо учитывать дробную часть каждого числа. Например, следующая программа вычисляет площадь круга, используя для значение 3,1416.

using System;

class Circle

{

static void Main() //объявление члена класса (метода)

{

double radius;

double area;

radius = 10.0;

area = radius * radius * 3.1416; //формула площади круга S=Pi*R*R

Console.WriteLine("Площадь круга равна: "+area);

Console.ReadKey();

}

}

Задание:Введите, скомпилируйте и выполните рассмотренную выше программу, объясните каждую строку кода.

Инструкции управления

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

Инструкция if

С помощью инструкции if можно организовать избирательное выполнение части программы. Действие инструкции if в С# во многом подобно действию одноименной инструкции в любом другом языке программирования. Что касается языков С, C++ и Java, то здесь налицо полная идентичность. Вот как выглядит простейшая форма записи этой инструкции:

if (условие) инструкция;

Здесь элемент условие представляет собой булево выражение (которое приводится к значению ИСТИНА или ЛОЖЬ). Заданная инструкция будет выполнена, если условие окажется истинным. В противном случае (если условие окажется ложным) заданная инструкция игнорируется. Рассмотрим следующий пример:

if (10 < 11) Console.WriteLine("10 меньше 11");

В данном случае число 10 действительно меньше 11, т.е. условное выражение истинно, поэтому метод WriteLine () будет вызван. Рассмотрим другой пример:

if(10 < 9) Console.WriteLine("Этот текст выведен не будет.");

Здесь же число 10 никак не меньше 9, поэтому вызов метода WriteLine () не произойдет.

В С# определен полный комплект операторов отношения, которые можно использовать в условных выражениях. Вот их список:

< Меньше;

<= Меньше или равно;

> Больше;

>= Больше или равно;

= = Равно;

! = Не равно.

Следующая программа иллюстрирует использование инструкции if.

using System;

class ifDemo

{

public static void Main() //объявление члена класса (метода)

{

int a, b, c;

a = 2;

b = 3;

if (a < b) Console.WriteLine("а меньше b");

//Следующая инструкция выполнена не будет

if (a == b) Console.WriteLine("Этого текста никто не увидит");

Console.WriteLine();

c = a - b;

Console.WriteLine("c содержит значение -1");

if (c >= 0) Console.WriteLine("Значение с неотрицательно!");

if (c < 0) Console.WriteLine("Значение с отрицательно!");

Console.WriteLine();

c = b - a;

Console.WriteLine("с содержит 1");

if (c >= 0) Console.WriteLine("Значение с неотрицательно!");

if (c < 0) Console.WriteLine("Значение с отрицательно!");

Console.ReadKey();

}

}

Задание:Введите, скомпилируйте и выполните рассмотренную выше программу, объясните каждую строку кода.

 

Цикл for

 

Чтобы многократно выполнить последовательность программных инструкций, не-

обходимо организовать цикл. В языке С# циклические конструкции представлены в богатом ассортименте. Сейчас мы рассмотрим цикл for. Если вы знакомы с С, C++ или Java, то вам будет приятно узнать, что цикл for в С# работает точно так же, как в этих языках. Простейшая форма записи цикла for имеет следующий вид:

for{инициализация; условие; итерация) инструкция;

В самой общей форме элемент инициализация устанавливает управляющую переменную цикла равной некоторому начальному значению. Элемент условие представляет собой булево выражение, в котором тестируется значение управляющей переменной цикла. Если результат этого тестирования истинен, цикл for выполняется еще раз, в противном случае его выполнение прекращается. Элемент итерация – это выражение, которое определяет, как изменяется значение управляющей переменной цикла после каждой итерации. Рассмотрим небольшую программу, в которой иллюстрируется цикл for.

using System;

class forDemo

{

public static void Main() //объявление члена класса (метода)

{

int count;

for (count = 0; count < 10; count++)

Console.WriteLine("Счет: "+count);

Console.ReadKey();

}

}

Задание:Введите, скомпилируйте и выполните рассмотренную выше программу, объясните каждую строку кода.

В этой программе управляющей переменной цикла является count. В выражении инициализации цикла for она устанавливается равной нулю. В начале каждой итерации (включая первую) выполняется проверка условия count < 10. Если результат этой проверки окажется истинным, выполнится инструкция вывода строки WriteLine (), а после нее - итерационное выражение цикла. Этот процесс будет продолжаться до тех пор, пока проверка условия не даст в результате значение ЛОЖЬ, после чего выполнение программы возобновится с инструкции, расположенной за циклом. С# включает специальный оператор инкремента, который позволяет более эффективно выполнить операцию увеличения значения на единицу. Оператор инкремента обозначается двумя последовательными знаками "плюс" (++). В С# также предусмотрен оператор декремента (--). Нетрудно догадаться, что этот оператор уменьшает значение операнда на единицу.

Таблица 1 - Задание по вариантам

№ вар. Выражения
1. Y=A*X3+B*X2+C*X+D если A>B, иначе Y=2*A*X2+4*B*X2+8*C*X2+D
2. Y=2*A*X4+B*X3+C*X2+2*D, если A>=B, иначе Y=10*A*X+4*B*X2+8*C*X3+D
3. Y=A+B+C*X2+D3, если A!=B, иначе Y=A*X4+B*X+C*X3+D
4. Y=A*X+B*X+C*X4+D2, если A<B, иначе Y=(A+B)*X3+5*C*X3+D
5. Y=A2*X+B*X2+C*X3+D, если A<C, иначе Y=A3*X+2*B2*X2+C*X3+D
6. Y=(A+B)*X2+(C +D) *X3, если A<B, иначе Y=(A-B)*X2+(C +D) *X3
7. Y=(A+B)*X2+(C +D) *X4, если C<D, иначе Y=(A+B)*X2+(C -D) *X4
8. Y=(A-B-C) *X+D, если A>(B+C), иначе Y=(A+B+C) *X3+D
9. Y=A*X4+(B-C-D)*X2, если B>(C+D), иначе Y= A*X4+(B+C+D)*X2
10. Y=A*X4+B*X2+C*X+D, если A<B, иначе Y=2*A *X2+4*B*X2+C*X3+D4
11. Y=A*X2-B2*X3+C*X-D, если A>B, иначе Y=4*A *X2 +7*B*X2-C*X3+D4
12. Y=A*X4+(B+C-D)*X2, если B>(C+D), иначе Y= A*X4+(B-C-D)*X2

 

На выполнение лабораторной работы отводится четыре часа (две пары). Лабораторная работа должна быть оформлена в виде отчета, в котором должны быть исходные коды всех программ согласно вариантам. Все программы должны быть работоспособны, не содержать синтаксических и логических ошибок в алгоритмах. Все программы студент должен продемонстрировать на ПК, что они работают. После этого можно оформлять отчет. Отчет по лабораторной работе студент должен защитить не позднее следующей пары отведенной для данной лабораторной работы.

 

Литература

 

  1. Герберт Шилдт «Полный справочник по С#», стр. 1-50
  2. В.В. Лабор «С# создание приложений для Windows»