Основы программирования на C#

Основы программирования на C#

Имена нынешнего поколения продуктов от Microsoft сопровождаются окончанием .Net (читается Dot Net), отражающим видение Microsoft современного коммуникативного мира. Компьютерные сети объединяют людей и технику. Человек, работающий с компьютером или использующий мобильный телефон, естественным образом становится частью локальной или глобальной сети. В этой сети используются различные специальные устройства, начиная от космических станций и кончая датчиками, расположенными, например, в гостиницах и посылающими информацию об объекте всем мобильным устройствам в их окрестности. В глобальном информационном мире коммуникативная составляющая любых программных продуктов начинает играть определяющую роль.
В программных продуктах .Net за этим именем стоит вполне конкретное содержание, которое предполагает, в частности, наличие открытых стандартов коммуникации, переход от создания монолитных приложений к созданию компонентов, допускающих повторное использование в разных средах и приложениях. Возможность повторного использования уже созданных компонентов и легкость расширения их функциональности - все это непременные атрибуты новых технологий. Важную роль в этих технологиях играет язык XML, ставший стандартом обмена сообщениями в сети.

Visual Studio .Net - открытая среда разработки
Среда разработки Visual Studio .Net - это уже проверенный временем программный продукт, являющийся седьмой версией Студии. Но новинки этой версии, связанные с идеей .Net, позволяют считать ее принципиально новой разработкой, определяющей новый этап в создании программных продуктов. Выделю две важнейшие, на мой взгляд, идеи: открытость для языков программирования;принципиально новый подход к построению каркаса среды - Framework .Net.

Создание C#
Язык C# является наиболее известной новинкой в области создания языков программирования. В отличие от 60-х годов XX века - периода бурного языкотворчества - в нынешнее время языки создаются крайне редко. За последние 15 лет большое влияние на теорию и практику программирования оказали лишь два языка: Eiffel, лучший, по моему мнению, объектно-ориентированный язык, и Java, ставший популярным во многом благодаря технологии его использования в Интернете и появления такого понятия как виртуальная Java-машина.

Общий взгляд
Знакомство с новым языком программирования разумно начинать с изучения системы типов этого языка. Как в нем устроена система типов данных? Какие есть простые типы, как создаются сложные, структурные типы, как определяются собственные типы, динамические типы, как определяются классы?

Где, как и когда выполняются преобразования типов?
Необходимость в преобразовании типов возникает в выражениях, присваиваниях, замене формальных аргументов метода фактическими. Если при вычислении выражения операнды операции имеют разные типы, то возникает необходимость приведения их к одному типу. Такая необходимость возникает и тогда, когда операнды имеют один тип, но он несогласован с типом операции. Например, при выполнении сложения операнды типа byte должны быть приведены к типу int, поскольку сложение не определено над байтами.

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

Выражения
Выражения строятся из операндов - констант, переменных, функций, - объединенных знаками операций и скобками. При вычислении выражения определяется его значение и тип. Эти характеристики однозначно задаются значениями и типами операндов, входящих в выражение, и правилами вычисления выражения.

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

Операторы языка C#
Состав операторов языка C#, их синтаксис и семантика унаследованы от языка С++. Как и положено, потомок частично дополнил состав, переопределил синтаксис и семантику отдельных операторов, постарался улучшить характеристики языка во благо программиста. Посмотрим, насколько это удалось языку C#.

Процедуры и функции - функциональные модули
Первыми формами модульности, появившимися в языках программирования, были процедуры и функции. Они позволяли задавать определенную функциональность и многократно выполнять один и тот же параметризованный программный код при различных значениях параметров. Поскольку функции в математике использовались издавна, то появление их в языках программирования было совершенно естественным. Уже с первых шагов процедуры и функции позволяли решать одну из важнейших задач, стоящих перед программистами, - задачу повторного использования программного кода.

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

Объявление массивов
Массив задает способ организации данных. Массивом называют упорядоченную совокупность элементов одного типа. Каждый элемент массива имеет индексы, определяющие порядок элементов. Число индексов характеризует размерность массива. Каждый индекс изменяется в некотором диапазоне [a,b]. В языке C#, как и во многих других языках, индексы задаются целочисленным типом. В других языках, например, в языке Паскаль, индексы могут принадлежать счетному конечному множеству, на котором определены функции, задающие следующий и предыдущий элемент.

Класс Array
Зададимся естественным вопросом: к какому или к каким классам принадлежат объекты ar1, ar2 и ar3? Ответ прост: все они принадлежат к разным классам. Переменная ar1 принадлежит к классу int[] - одномерному массиву значений типа int, ar2 - double[] - одномерному массиву значений типа double, ar3 - двумерному массиву значений типа int. Следующий закономерный вопрос: а что общего есть у этих трех объектов?

Строки С++
Строкам не повезло. По понятным причинам в первых языках программирования строковому типу уделялось гораздо меньше внимания, чем арифметическому типу или массивам. Поэтому в разных языках строки представлены по-разному и стандарт на строковый тип сложился относительно недавно



Класс String
В предыдущей лекции мы говорили о символьном типе char и строках постоянной длины, задаваемых массивом символов. Основным типом при работе со строками является тип string, задающий строки переменной длины. Класс String в языке C# относится к ссылочным типам. Над строками - объектами этого класса - определен широкий набор операций, соответствующий современному представлению о том, как должен быть устроен строковый тип.

Пространство имен RegularExpression и классы регулярных выражений
Стандартный класс String позволяет выполнять над строками различные операции, в том числе поиск, замену, вставку и удаление подстрок. Существуют специальные операции, такие как Join, Split, которые облегчают разбор строки на элементы. Тем не менее, есть классы задач по обработке символьной информации, где стандартных возможностей явно не хватает. Чтобы облегчить решение подобных задач, в Net Framework встроен более мощный аппарат работы со строками, основанный на регулярных выражениях

Классы и ООП
Объектно-ориентированное программирование и проектирование построено на классах. Любую программную систему, выстроенную в объектном стиле, можно рассматривать как совокупность классов, возможно, объединенных в проекты, пространства имен, решения, как это делается при программировании в Visual Studio .Net.

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

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

Интерфейсы
Слово "интерфейс" многозначное и в разных контекстах оно имеет различный смысл. В данной лекции речь идет о понятии интерфейса, стоящем за ключевым словом interface. В таком понимании интерфейс - это частный случай класса. Интерфейс представляет собой полностью абстрактный класс, все методы которого абстрактны. От абстрактного класса интерфейс отличается некоторыми деталями в синтаксисе и поведении.

Как определяется функциональный тип и как появляются его экземпляры
Слово делегат (delegate) используется в C# для обозначения хорошо известного понятия. Делегат задает определение функционального типа (класса) данных. Экземплярами класса являются функции. Описание делегата в языке C# представляет собой описание еще одного частного случая класса. Каждый делегат описывает множество функций с заданной сигнатурой. Каждая функция (метод), сигнатура которого совпадает с сигнатурой делегата, может рассматриваться как экземпляр класса, заданного делегатом.

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

Наследование и универсальность
До недавнего времени Framework .Net и соответственно язык C# не поддерживали универсальность. Так что те, кто работает с языком C#, входящим в состав Visual Studio 2003 и ранних версий, должны смириться с отсутствием универсальных классов. Но в новой версии Visual Studio 2005, носящей кодовое имя Whidbey, проблема решена, и программисты получили наконец долгожданный механизм универсальности

Корректность и устойчивость программных систем
Корректность и устойчивость - два основных качества программной системы, без которых все остальные ее достоинства не имеют особого смысла. Понятие корректности программной системы имеет смысл только тогда, когда задана ее спецификация. В зависимости от того, как формализуется спецификация, уточняется понятие корректности.

Организация интерфейса
Практически все проекты, построенные в наших лекциях, были консольными приложениями. В реальной жизни консольные проекты - это большая редкость. Причина, по которой из 12 возможных типов проектов мы выбирали наименее используемый, понятна. Нашей целью являлось изучение свойств языка, классов библиотеки FCL, для этих целей консольный проект вполне подходит, позволяя избегать введения не относящихся к сути дела деталей. Теперь цель достигнута - основные средства языка C# рассмотрены, учебный курс завершается.

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

Языки программирования. Практический сравнительный анализ

Естественно начать с характеристики изучаемого предмета. Но коротко охарактеризовать, что именно будем изучать, с какой целью и как, не просто (скоро станет понятно, почему). Конечно, нас будут интересовать "языки программирования" (ЯП). На сколь точно эти слова определяют сферу наших интересов? Одни скажут, что язык машин Тьюринга или алгоритмов Маркова - это ЯП, другие не согласятся с этим категорически. Одни признают язык управления заданиями в ОС ЕС языком программирования, другие приведут доводы против.
Такая ситуация на первый взгляд неприятна - собираемся изучать неизвестно что. Сделаем вывод, что нужно определить объем понятия "язык программирования" (его экстенсионал, т.е. множество обьектов, охватываемых этим понятием, множество его частных случаев).
Чтобы создать себе первую точку опоры, пойдем по простейшему пути - явно перечислим те конкретные языки, которые нас заведомо интересуют (их мы уверенно считаем "языками программирования"). Это Фортран, Паскаль, Бейсик, Лисп, Апл, Форт, Рефал, Ада. Однако вряд ли стало намного легче. Хочется иметь возможность на основе определения предсказывать новые частные случаи, в определении не перечисленные. Такое определение должно опираться на существенные свойства выбираемых для изучения языков - оно должно быть интенсиональным. Дадим одно из возможных интенсиональных определений ЯП.     

Что такое язык программирования