Среда разработки Visual Studio.Net - это уже проверенный временем программный продукт, являющийся седьмой версией Студии. Но новинки этой версии, связанные с идеей.Net, позволяют считать ее принципиально новой разработкой, определяющей новый этап в создании программных продуктов. Выделю две важнейшие, на мой взгляд, идеи:
- открытость для языков программирования;
- принципиально новый подход к построению каркаса среды - Framework.Net.
Среда разработки теперь является открытой языковой средой. Это означает, что наряду с языками программирования, включенными в среду фирмой Microsoft - Visual C++.Net (с управляемыми расширениями), Visual C#.Net, J#.Net, Visual Basic.Net, - в среду могут добавляться любые языки программирования, компиляторы которых создаются другими фирмами-производителями. Таких расширений среды Visual Studio сделано уже достаточно много, практически они существуют для всех известных языков - Fortran и Cobol, RPG и Component Pascal, Oberon и SmallTalk. Открытость среды не означает полной свободы. Все разработчики компиляторов при включении нового языка в среду разработки должны следовать определенным ограничениям. Главное ограничение, которое можно считать и главным достоинством, состоит в том, что все языки, включаемые в среду разработки Visual Studio.Net, должны использовать единый каркас - Framework.Net. Благодаря этому достигаются многие желательные свойства: легкость использования компонентов, разработанных на различных языках; возможность разработки нескольких частей одного приложения на разных языках; возможность бесшовной отладки такого приложения; возможность написать класс на одном языке, а его потомков - на других языках. Единый каркас приводит к сближению языков программирования, позволяя вместе с тем сохранять их индивидуальность и имеющиеся у них достоинства. Преодоление языкового барьера - одна из важнейших задач современного мира. Благодаря единому каркасу, Visual Studio.Net в определенной мере решает эту задачу в мире программистов.
|
|
В каркасе Framework.Net можно выделить два основных компонента:
- статический - FCL (Framework Class Library) - библиотеку классов каркаса;
- динамический - CLR (Common Language Runtime) - общеязыковую исполнительную среду.
Понятие каркаса приложений - Framework Applications - появилось достаточно давно; по крайней мере, оно широко использовалось еще в четвертой версии Visual Studio. Важна роль библиотеки классов MFC (Microsoft Foundation Classes) как каркаса приложений Visual C. Несмотря на то, что каркас, первоначально был представлен только статическим компонентом, уже тогда была очевидна его роль в построении приложений. Уже в то время важнейшее значение в библиотеке классов MFC имели классы, задающие архитектуру строящихся приложений. Когда разработчик выбирал один из возможных типов приложения, например, архитектуру Document-View, то в его приложение автоматически встраивались класс Document, задающий структуру документа, и класс View, задающий его визуальное представление. Класс Form и классы, задающие элементы управления, обеспечивали единый интерфейс приложений. Выбирая тип приложения, разработчик изначально получал нужную ему функциональность, поддерживаемую классами каркаса. Библиотека классов поддерживала и более традиционные для программистов классы, задающие расширенную систему типов данных, в частности, динамические типы данных - списки, деревья, коллекции, шаблоны.
|
|
Обьявление и инициализация переменных:
Тип_переменной имя_переменной [=значение];
Примеры:
int x; //обьявление переменной x
x=100; //инициализация переменной x
long w,z=100; //обьявление переменных w и z и
//инициализация z
long q=100*z; //обьявление переменной с динамической
//инициализацией
Декларация классов, функций и переменных на уровне класса требует указания модификатора доступа. Впрочем, если не указывать, то будет использован стандартный модификатора, обычно private. Модификаторы доступа - это ключевые слова, определяющие, откуда можно будет получить доступ к декларированной переменной/функции и пр. Их всего несколько:
private - доступ возможен только изнутри класса, в котором объявлена.
protected - доступ возможен из этого класса и всех наследников.
internal - доступ возможен из всей assembly (сборки/библиотеки, файла короче). Также применяется для классов, enum и интерфейсов.
public - доступ возможен откуда угодно. Также применяется для классов, enum и интерфейсов.
Есть еще модификаторы состояния, определяющие принципиальное состояние функций:
static - функция статична, т.е. возможно ее исполнение без создания объекта класса. Например, функции класса System.Math - статичные, поскольку выполняются простым вызовом, без создания объекта класса Math. Также применяется для классов, тогда все входящие в него функции и переменные должны быть static.
abstract - функция только декларирована, а определение функции должно быть в классах наследниках. Используется для создания шаблона класса, все наследники которого обязательно имеют некий набор функций. Может существовать только в abstract классе. Также применяется для классов.
virtual - функцию можно переопределить в классе наследнике.
override - используется для указания, что описываемая функция переопределяет родительскую.
Модификатор доступа для функции/переменной внутри класса не может быть более доступным, нежели модификатор доступа всего класса.
Переменные, декларируемые внутри функций модификатора доступа не требуют.
Декларация переменных обязательно состоит из типа данных и имени, остальное - по ситуации и желанию.
Примеры деклараций переменных:
int i;
public double myDouble1, myDouble2;
internal static System.String const_string = "константа";
Декларация функций обязательно состоит из типа возвращаемых данных, имени и списка аргументов, остальное - по ситуации. Возращаемым типом данных может быть void - пустой - т.е. нет возвращаемых данных. Список аргументов тоже может быть пустым. Функции, в отличии от переменных, не могут быть только декларированы - они обязательно сразу определяются. Единственное исключение - тип функций abstract, они только декларируются, а определяются уже в классах наследниках.
|
|
Здесь следует учитывать важное обстоятельство! CLR не допускает использования в выражениях неинициализированных локальных переменных. В C# к таковым относятся переменные, объявленные в теле метода. Так что при разработке алгоритма следует обращать на это особое внимание.
Константы. Объявляются с дополнительным спецификатором const. Требуют непосредственной инициализации. В данном примере инициализируется литералом 3.14.
const float Pi = 3.14.
C# - язык со строгим контролем типов данных. Есть 2 основные категории встроенных типов данных в C# - простые типы и ссылочные типы. Основные простые типы данных в C# приведены в таблице 1.
Область видимости переменной в C# - блок кода (заключенный в фигурные скобки {}). Переменная создается при входе в область видимости, и уничтожаются при выходе из нее.
Если используются длинные имена, то вы должны писать System.Int32 для типа int и т. п. (т. е. приписывать слово System перед CLR-именем). Или же вы должны добавить строчку using System;
Таблица 1.
Основные простые типы данных в C#
Логический тип | |||||||
Имя типа | Системный тип | Значения | Размер | ||||
Bool | System.Boolean | true, false | 8 бит | ||||
Арифметические целочисленные типы | |||||||
Имя типа | Системный тип | Диапазон | Размер | ||||
Sbyte | System.SByte | -128 — 127 | Знаковое, 8 Бит | ||||
Byte | System.Byte | 0 — 255 | Беззнаковое, 8 Бит | ||||
Short | System.Short | -32768 —32767 | Знаковое, 16 Бит | ||||
Ushort | System.UShort | 0 — 65535 | Беззнаковое, 16 Бит | ||||
Int | System.Int32 | ≈(-2*10^9 — 2*10^9) | Знаковое, 32 Бит | ||||
Uint | System.UInt32 | ≈(0 — 4*10^9) | Беззнаковое, 32 Бит | ||||
Long | System.Int64 | ≈(-9*10^18 — 9*10^18) | Знаковое, 64 Бит | ||||
Ulong | System.UInt64 | ≈(0— 18*10^18) | Беззнаковое, 64 Бит | ||||
Арифметический тип с плавающей точкой | |||||||
Имя типа | Системный тип | Диапазон | Точность | ||||
Float | System.Single | +1.5*10^-45 - +3.4*10^38 | 7 цифр | ||||
Double | System.Double | +5.0*10^-324 - +1.7*10^308 | 15-16 цифр | ||||
Арифметический тип с фиксированной точкой | |||||||
Имя типа | Системный тип | Диапазон | Точность | ||||
Decimal | System.Decimal | +1.0*10^-28 - +7.9*10^28 | 28-29 значащих цифр | ||||
Символьные типы | |||||||
Имя типа | Системный тип | Диапазон | Точность | ||||
Char | System.Char | U+0000 - U+ffff
| 16 бит Unicode символ | ||||
String | System.String | Строка из символов Unicode | |||||
Объектный тип | |||||||
Имя типа | Системный тип | Примечание | |||||
Object | System.Object | Прародитель всех встроенных и пользовательских тип | |||||
Таким образом, следующие три объявления переменной k равносильны:
int k;
using System;
...
Int32 k;
и
System.Int32 k;
Разумеется, аналогично мы имеем дело и другими типами языка C#.
Объявление переменной можно совместить с инициализацией (заданием начального значения):
int z=88;
Набор операторов для C# достаточно стандартен +, -, *, / - действуют как и в любом другом языке. Отметим только, что / (деление) применительно к целым числам дает целую часть от деления. Так, фрагмент
int k=100999, n=1000, s;
s=k/n;
Console.WriteLine(s.ToString());
выведет на экран 100, а не 101, т. е. никакого округления не происходит.
Есть еще один оператор - %. Это - остаток от деления. Следующий фрагмент выведет на экран 999:
int k=100999, n=1000, s;
s=k%n;
Console.WriteLine(s.ToString());
Как и в других C-подобных языках, в C# существуют операторы инкремента и декремента. Так, после следующего фрагмента k увеличится на 1, а n - уменьшится на 1, т.е. реализуются выражения k=k+1, n=n-1:
k++;
n--;
Пример программы сложения двух чисел на листинге 1.
Листинге 1.
//Использовать пространство имен System необходимо
using System;
//Класс реализующий сложение двух чисел
class Class1
{
//Объявляем переменные, которые мы будем складывать
private int x, y;
//Конструктор, который присваивает значения переменным
public Class1(int intX, int intY)
{
x=intX;
y=intY;
}
//Функция, которая складывает два числа и
// выводит результат на экран
public void Add()
{
Console.WriteLine("Result: {0}",x+y);
}
}
//Класс, в котором расположена точка входа
class Class2
{
//А вот и сама точка входа - функция Main
//В качестве параметров передаются параметры
//командной строки
public static void Main(string[] args)
{
//Создаем экземпляр класса Class1
//Одновременно присваивая значения переменным
Class1 ex = new Class1(Int32.Parse(args[0]), Int32.Parse(args[1]));
//Складываем два числа и выводим
//результат на экран
ex.Add();
}
}
Проанализируем данное решение. Создали два класса: Class1 и Class2. В данной задаче, можно было бы воспользоваться и одним классом, но использование двух классов для данной задачи предпочтительно, для лучшего понимания структуры. Собственно вся работа ложится на плечи класса Class1, который и реализует главную задачу - сложение двух чисел.
Давайте подробно рассмотрим класс Class1. Все классы должны иметь строгую структуру. Подробнее о классах будет говориться в других лабораторных работах. Ее можно представить так:
class Class1
{
// Здесь располагаются свойства,
// методы данного класса и другие члены
}
Кстати, зеленным цветом выделены комментарии (обратите внимание на их оформление). Они необходимы только для вас и для тех, кто будет изучать ваш исходный код. Компилятор игнорирует комментарии, как будто их и нет. Использование комментариев никогда не бывает лишним. Старайтесь их использовать во всех ваших приложениях.
В этом же классе объявляются две переменные x и y, которые будут складываться.
private int x,y;
Слово private необходимо для того, чтобы к этим переменным нельзя было обращаться напрямую из других классов.
Ключевое слово int означает, что обе переменные будут целочисленными. В .NET существует множество встроенных типов. Число данного типа может лежать в диапазоне от -2147483648 до 2147483648. Для данной задачи данного диапазона вполне хватит. После объявления создается новый конструктор:
public Class1(int intX, int intY)
{
x=intX;
y=intY;
}
Конструктор - это особая функция, которая автоматически вызывается при создании экземпляра данного класса. Конструктор называется точно также как и сам класс, в котором он находится: Class1. Конструкторы необходимы для того чтобы произвести начальную настройку объекта при его создании, чтобы в дальнейшем этим не заниматься. Конструкторов у одного класса может быть бесчисленное множество. И у каждого класса есть по крайней мере один конструктор. Этот конструктор называется конструктором по умолчанию, при вызове данного конструктора всем объектам данного класса присваиваются значения по умолчанию, например 0. Чуть позже мы рассмотрим работу конструктора по умолчанию. Этот конструктор в описании не нуждается, он создается автоматически. Понятно, что в нашем классе он так же есть, т.е. в нашем классе имеется два конструктора.
В качестве параметров нашему конструктору передаются два параметра intX и intY. Такое название этим переменным я придумал сам, вы же может придумать свои названия. После чего переменным x и y присваиваются значения intX и intY соответственно. Это означает, что после операции x=intX переменная x будет равна intX, а после операции y=intY переменная y будет равна переменной intY.
После создания конструктора мы написали функцию Add(), которая выполняет сложение двух чисел.
public void Add()
{
Console.WriteLine("Result: {0}",x+y);
}
При этом выполняется условие задачи. Данная функция не получает ни каких параметров. Вместо нее это делает конструктор. Сложение чисел и вывод их на экран делается в нашем случае одним оператором, хотя можно было бы сделать и двумя.
Обратите внимание на ключевое слово void. Любая функция может возвращать какое либо значение. Не исключением является и функция Add(). Слово void означает, что наша функция не будет возвращать никаких значений, нам это не нужно. Если бы нам потребовалось, чтобы Add() возвращала какое-либо значение после своего завершения, а следовательно и завершения приложения, мы бы написали вместо void название какого-либо типа, например int.
А вот как может выглядеть функция, которая возвращает значение:
public int Add()
{
return x+y;
}
Команда return возвращает значение функции, в нашем случае это значение выражения x+y и это значение типа int.
Функция WriteLine из пространства имен Console выводит строку на экран. Обратите внимание на то, как вызывается эта функция: Console.WriteLine. Если написать просто WriteLine, то компилятор вернет ошибку: "The name ′WriteLine′ does not exist in the class or namespace ′Class1′", т.е. такого метода не существует.
В качестве параметров функции WriteLine передается следующая строка "Result: {0}",x+y. В данной строке две части (их может быть бесчисленное множество). В начале считается выражение x+y. После этого на экран выводится текст, находящийся между кавычек, при этом вместо {0} автоматически подставиться результат операции x+y.
Вместо цифры подставляется результат выражения, цифра соответствует порядковому номеру выражения, отсчет которых идет слева направо.
Вот простой пример: После операции:
Console.WriteLine("{0}{1}",x+y, x-y);
На экран будет выведен через пробел результат сложения и вычитания. В данном случае x+y - это нулевое выражение (отсчет в C# практически всегда начинается с 0), а x-y - это первое выражение. Надеюсь, что это вы усвоили, т.к. эти символы будут использоваться нами неоднократно.
О некоторых модификациях данной комбинации символов. В C# есть возможность использовать параметры форматирования. Вот самые популярные параметры форматирования, которые могут понадобиться:
{0:C} - денежный формат. Например число 19722.345 преобразуется в 19 722,35р. (Это зависит от того какой денежный формат установлен у вас в системе);
{0:D6} - фиксированное поле. Вместо шестерки можно подставить любое другое число, равное ширине поля. Например, при данном параметре число 457 преобразуется в 000475;
{0:E} - экспоненциальная форма;
{0:F4} - очень важный параметр, вместо четверки можно подставить любое число равное количеству символов после запятой, например число 3.234567 преобразуется в 3.2346.
Один из классов написан. Приступаем к написанию второго.
Второй класс называется Class2. В данном классе есть всего лишь одна функция Main (обязательно с заглавной буквы). Эта функция особенная. Она есть в любом приложении. Это и есть та самая входная точка. Именно с этой функции начинается работа приложения. Общий вид нашей функции Main имеет вид:
public static void Main(string[] args)
{
Class1 ex = new Class1(Int32.Parse(args[0]),Int32.Parse(args[1]));
ex.Add();
}
Слово static означает, что эта функция будет доступна тогда, когда ни создано еще не одного экземпляра класса. Мы ведь вообще не создаем экземпляр класса Class2. Если мы уберем слово static, то компилятор выдаст сообщение о том, что у нашей программы нет точки входа, т.е. она не доступна. У нашей функции Main есть параметр: string[] args.
Это массив параметров командной строки. Массив - это совокупность некоторых данных. О том, что это именно массив, говорят квадратные скобки. Слово string означает, что наш массив будет состоять из элементов типа string. Args - это название нашего массива, название можно придумать любое. В принципе у функции Main других параметров быть и не может. Рассмотрим следующую строку, в ней есть много интересного:
Class1 ex = new Class1 (Int32.Parse (args[0]), Int32.Parse (args[1]));
Итак, этой командой создается экземпляр класса Class1 (об этом говорит первое слово), который называется ex (название можно выбрать любое). Ключевое слово new означает, что создается новый объект. Далее вызывается конструктор. Там два параметра intX и intY. В данном случае эти переменные будут равны Int32.Parse(args[0]) и Int32.Parse(args[1]) соответственно. Т.е. вместо intX будет подставлен первый параметр командной строки (об этом говорит цифра 0. В C# отсчет ведется с нуля.), а вместо intY будет подставлен второй параметр. Конструкция Int32.Parse() необходима для преобразования типов. Ведь переменные intX и intY имеют тип int, а элементы массива args имеют тип string, поэтому надо преобразовать string в int. Именно это и делает функция Int32.Parse(). И, наконец, последняя команда вызывает функцию Add() класса Class1. Эта функция складывает две переменные и выводит результат на экран.
Давайте подведем итог. Итак, мы создали класс, в котором есть функция Add(), две переменные и дополнительный конструктор. В основной функции Main создается объект ex (экземпляр класса Class1), после этого о классе можно забыть, уже работаем с объектом, у которого есть свои свойства и методы. Одним из таких методов является функция Add(), которая вызывается.
Операторы языка
Операторы сравнения:
< - строго меньше. Определен для любых числовых типов (int, double, short, byte, decimal, float, bool)
> - строго больше. Аналогично предыдущему.
<= - меньше или равно. Аналогично предыдущему.
>= - больше или равно. Аналогично предыдущему.)
== - равно (эквивалентно). Определен для большинства типов и классов. Для многих классов означает именно идентичность объектов класса, а не равенство их внутренних значений.
!= - не равно. Аналогично предыдущему.
Обратите внимание: проверка на равенство обозначается двумя знаками равно! Одним знаком обозначается оператор присвоения значения.
Логические операторы:
|| - логическое ИЛИ.
&& - логическое И.
! - логическое НЕ.
Арифметические операторы:
помимо стандартных +, -, *, / есть их модификации со знаком равно: +=, -=, *=, /=. Означают "выполнить оператор и приравнять", т.е.
i += 10;
означает прибавить 10 к значению переменной i, и записать результат в нее же. Это аналогично записи:
i = i + 10;
есть еще два оператора:
++ - прибавить единицу к переменной и записать результат в нее. Инкрементный оператор.
-- - отнять единицу от значения переменной и записать результат в нее. Декрементный оператор.