Объектно-ориентированный подход к программированию
© Учебный Центр безопасности информационных технологий Microsoft Мос...
60 downloads
325 Views
7MB Size
Report
This content was uploaded by our users and we assume good faith they have the permission to share this book. If you own the copyright to this book and it is wrongfully on our website, we offer a simple DMCA procedure to remove your content from our site. Start by pressing the button below!
Report copyright / DMCA form
Объектно-ориентированный подход к программированию
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Предлагаем Вашему вниманию продолжение курса лекций, посвященного современным языкам программирования. Изучение языков программирования базируется на теоретическом фундаменте современных подходов и математических формализаций, принятых в мировом computer science. В качестве технологической основы и инструментальной платформы для исследования языков программирования предлагается новейшая разработка корпорации Microsoft – уникальный по идеологии и широте поддержки языков программирования комплекс программного обеспечения на основе так называемой методологии .NET. В первой части курса обсуждались основы программирования и теоретическое введение в computer science. Вторая часть курса посвящена теории и практике реализации гетерогенных программных систем на более профессиональном уровне. При этом существенно используется объектно-ориентированный подход к программированию, введение в проблематику которого и является темой настоящей лекции.
Современные языки программирования и .NET: II семестр Лекция 1: Объектно-ориентированный подход к программированию
Содержание лекции 1. 2. 3. 4. 5. 6. 7. 8.
Современные подходы к программированию Особенности декларативного подхода Особенности императивного подхода Особенности функционального подхода Основные понятия ООП Абстракция, инкапсуляция, наследование и полиморфизм Преимущества и недостатки ООП Библиография © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Коротко о содержании лекции. Прежде всего, необходимо напомнить слушателям классификацию языков программирования, кратко рассмотреть историю их развития и основные подходы к разработке программных систем, сфокусировав внимание на преимуществах и недостатках каждого из языков и подходов. При этом особое внимание будет уделено различиям между основными классами языков программирования, а именно, императивными и декларативными. Затем речь пойдет об отличительных особенностях программирования и функциональном подходе в целом.
языков
функционального
Основная часть лекции будет посвящена концепциям объектно-ориентированного программирования, а именно, наследования, инкапсуляции и полиморфизма. По традиции, примеры программ (на языке программирования C#, самом популярном для платформы .NET) будут сопровождаться теоретическими аналогиями из computer science. Исследование эволюции языков программирования данного класса будет сопровождаться примерами. Наконец, для желающих глубже исследовать предмет будут представлены ссылки на важнейшие работы теоретического и практического плана по теме лекции.
Современные языки программирования и .NET: II семестр Лекция 1: Объектно-ориентированный подход к программированию
Подходы к программированию Основные подходы к программированию: • структурный, модульный; • функциональный; • логический; • объектно-ориентированный (ООП); • смешанный (комбинированный, интегрированный); • компонентно-ориентированный (.NET); • чисто объектный © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Прежде всего, напомним слушателям итоги построения классификации языков и подходов к программированию, разработанной нами в первой части курса. Кратко перечислим основные подходы к программированию: • ранние неструктурные подходы; • структурный или модульный подход (задача разбивается на подзадачи, затем на алгоритмы, составляются их структурные схемы и происходит реализация); • функциональный подход; • логический подход; • объектно-ориентированный подход; • смешанный подход (некоторые подходы возможно комбинировать); • компонентно-ориентированный (программный проект рассматривается как множество компонент, такой подход принят, в частности, в .NET); • чисто объектный подход (идеальный с математической точки зрения вариант, который пока не реализован практически). Заметим, что приведенную классификацию не следует считать единственно верной и абсолютной, поскольку языки программирования постоянно развиваются и совершенствуются, и недавние недостатки устраняются с появлением необходимых инструментальных средств или теоретических обоснований.
Современные языки программирования и .NET: II семестр Лекция 1: Объектно-ориентированный подход к программированию
Декларативные языки программирования (1) Время появления: 1960-е г.г. Краткая характеристика: программа – описание действий, которые необходимо осуществить Преимущества: • простота верификации и тестирования программ; • строгость математической формализации; • высокая степень абстракции
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Остановимся несколько подробнее на языках и подходах к программированию, которые наиболее существенны для целей данного курса. Напомним, что в 60-х г.г. возникает новый подход к программированию, который до сих пор успешно конкурирует с императивным (т.е. основанным на командах, директивах или операторах и включающим процедуры и функции), а именно, декларативный подход. Суть подхода состоит в том, что программа представляет собой не набор команд, а описание действий, которые необходимо осуществить. Этот подход, как показали результаты предыдущего курса, существенно проще и прозрачнее формализуем математическими средствами. Отсюда следует тот факт, что программы проще проверять на наличие ошибок (тестировать), а также на соответствие заданной технической спецификации (верифицировать). Высокая степень абстракции также является преимуществом данного подхода. Фактически, программист оперирует не набором инструкций, а абстрактными понятиями, которые могут быть достаточно обобщенными.
Современные языки программирования и .NET: II семестр Лекция 1: Объектно-ориентированный подход к программированию
Декларативные языки программирования (2) Недостатки: • сложность эффективной реализации; • необходимость фундаментальных математических знаний Примеры: LISP (Interlisp, Common Lisp, Scheme), SML, Haskell, Prolog
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду На начальном этапе развития декларативным языкам программирования было сложно конкурировать с императивными в силу объективных трудностей при создании эффективной реализации трансляторов. Программы работали медленнее, однако, они могли решать с меньшими трудозатратами более абстрактные задачи. В частности, язык SML, который мы продолжаем изучать в данном курсе вместе с языком C#, был разработан как средство доказательства теорем. Различные диалекты языка LISP (основные из них представлены на слайде), возникли потому, что ядро и идеология этого языка оказались весьма эффективными при реализации символьной обработки (анализе текстов). Другие характерные примеры декларативных языков программирования приведены на слайде.
Современные языки программирования и .NET: II семестр Лекция 1: Объектно-ориентированный подход к программированию
Императивные (процедурные) языки программирования (1) Время появления: 1950-е г.г. Краткая характеристика: программа – последовательность инструкций-операторов, включающих блоки типичных действий – процедуры или функции Преимущества: • более высокий уровень абстракции; • меньшая машинная зависимость; • более широкая совместимость © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду 50-е годы ХХ века ознаменовались появлением языков программирования так называемого «высокого уровня», по сравнению с ранее рассмотренными нами низкоуровневыми языками. При этом различие состоит в повышении эффективности труда разработчиков за счет абстрагирования или отвлечения от конкретных деталей аппаратного обеспечения. Одна инструкция (оператор) языка высокого уровня соответствовала последовательности из нескольких низкоуровневых инструкций, или команд. Исходя из того, что программа, по сути, представляла собой набор директив, обращенных к компьютеру, такой подход к программированию получил название императивного. Еще одной особенностью языков высокого уровня была возможность повторного использования ранее написанных программных блоков, выполняющих те или иные действия, посредством их идентификации и последующего обращения к ним, например, по имени. Такие блоки получили название функций или процедур, и программирование приобрело более упорядоченный характер.
Современные языки программирования и .NET: II семестр Лекция 1: Объектно-ориентированный подход к программированию
Императивные (процедурные) языки программирования (2) Преимущества: • содержательная значимость текстов программ; • унификация программного кода; • повышение производительности труда программистов Недостатки: • большие трудозатраты на обучение; • меньшая эффективность программного кода Примеры: Fortran, ALGOL, PL/1, APL, BPL, COBOL, Pascal, C, Basic © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Кроме того, с появлением языков высокого уровня зависимость реализации от аппаратного обеспечения существенно уменьшилась. Платой за это стало появление специализированных программ, преобразующих инструкции возникших языков в коды той или иной машины, или трансляторов, а также некоторая потеря в скорости вычислений, которая, впрочем, компенсировалась существенным выигрышем в скорости разработки приложений и унификацией программного кода. Нужно отметить, что операторы и ключевые слова новых языков программирования были более осмысленны, чем безликие цифровые последовательности машинных кодов, что также обеспечивало повышение производительности труда программистов. Естественно, для обучения новым языкам программирования требовались значительные затраты времени и средств, а эффективность реализации на прежних аппаратных возможностях снижалась. Однако трудности эти носили временный характер, и, как показала практика программирования, многие из первых языков высокого уровня оказались настолько удачно реализованными, что активно используются и сегодня. Одним из таких примеров является язык Fortran, реализующий вычислительные алгоритмы. Другой пример - язык APL, трансформировавшийся в BPL и затем в C. Основные конструкции последнего остаются неизменными вот уже несколько десятилетий и присутствуют в языке C#, который нам предстоит изучать в курсе объектно-ориентированного программирования. Примеры других языков программирования: ALGOL, COBOL, Pascal, Basic.
Современные языки программирования и .NET: II семестр Лекция 1: Объектно-ориентированный подход к программированию
Функциональные языки программирования (1) Время появления: 1960-е г.г. Краткая характеристика: программа – функция, аргументы которой, возможно, также являются функциями Преимущества: • полностью автоматическое управление памятью компьютера («сборка мусора»); • простота повторного использования фрагментов кода; • расширенная поддержка функций с параметрическими аргументами (параметрический полиморфизм); © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Одним из путей развития декларативного стиля программирования стал функциональный подход, возникший с появлением и развитием языка LISP. Отличительной особенностью данного подхода является то обстоятельство, что любая программа, написанная на таком языке, может интерпретироваться как функция с одним или несколькими аргументами. Такой подход дает возможность прозрачного моделирования текста программ математическими средствами, а, значит, весьма интересен с теоретической точки зрения. Сложные программы при таком подходе строятся посредством агрегирования функций. При этом текст программы представляет собой функцию, некоторые аргументы которой можно также рассматривать как функции. Таким образом, повторное использование кода сводится к вызову ранее описанной функции, структура которой, в отличие от процедуры императивного языка, прозрачна математически. Более того, типы отдельных функций, используемых в функциональных языках, могут быть переменными. Таким образом обеспечивается возможность обработки разнородных данных (например, упорядочение элементов списка по возрастанию для целых чисел, отдельных символов и строк) или полиморфизм. Еще одним важным преимуществом реализации языков функционального программирования является автоматизированное динамическое распределение памяти компьютера для хранения данных. При этом программист избавляется от рутинной обязанности контролировать данные, а при необходимости может запустить функцию «сборки мусора» – очистки памяти от тех данных, которые больше не потребуются программе (обычно этот процесс периодически инициируется компьютером).
Современные языки программирования и .NET: II семестр Лекция 1: Объектно-ориентированный подход к программированию
Функциональные языки программирования (2) Преимущества: • абстрагирование от машинного представления данных; • прозрачность реализации самоприменяемых (рекурсивных) функций; • удобство символьной обработки данных (списки, деревья) Недостатки: • нелинейная структура программы; • относительно низкая эффективность Примеры: LISP, SML, CaML, Haskell, Miranda, Hope © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Таким образом, при создании программ на функциональных языках программист сосредотачивается на области исследований (предметной области) и в меньшей степени заботится о рутинных операциях (обеспечении правильного с точки зрения компьютера представления данных, «сборке мусора» и т.д.). Поскольку функция является естественным формализмом для языков функционального программирования, реализация различных аспектов программирования, связанных с функциями, существенно упрощается. В частности, интуитивно прозрачным становится написание рекурсивных функций, т.е. функций, вызывающих самих себя в качестве аргумента. Кроме того, естественной становится и реализация обработки рекурсивных структур данных (например, списков – базовых элементов, скажем, для семейства языков LISP, деревьев и др.) Благодаря реализации механизма сопоставления с образцом, такие языки как ML и Haskell весьма хорошо применимы для символьной обработки. Естественно, языки функционального программирования не лишены недостатков. Часто к ним относят нелинейную структуру программы и относительно невысокую эффективность реализации. Однако, первый недостаток достаточно субъективен, а второй успешно преодолен современными реализациями, в частности, рядом последних трансляторов языка SML, включая и компилятор для среды Microsoft .NET. Характерные примеры функциональных языков программирования приведены на слайде.
Современные языки программирования и .NET: II семестр Лекция 1: Объектно-ориентированный подход к программированию
Объектно-ориентированные языки программирования (1) Время появления: 1970-е г.г. Краткая характеристика: программа – описание объектов, их совокупностей, отношений между ними и способов их взаимодействия Преимущества: • интуитивная близость к произвольной предметной области; • моделирование сколь угодно сложных предметных областей; • событийная ориентированность; © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Важнейшим шагом на пути к совершенствованию языков программирования стало появление объектно-ориентированного подхода к программированию (или, сокращенно, ООП) и соответствующего класса языков. Именно исследование теории и практики проектирования и реализации программных систем по принципам ООП и является основной целью данного курса. При объектно-ориентированном подходе программа представляет собой описание объектов, их свойств (или атрибутов), совокупностей (или классов), отношений между ними, способов их взаимодействия и операций над объектами (или методов). Несомненным преимуществом данного подхода является концептуальная близость к предметной области произвольной структуры и назначения. Механизм наследования атрибутов и методов позволяет строить производные понятия на основе базовых и таким образом создать модель сколь угодно сложной предметной области с заданными свойствами. Еще одним теоретически интересным и практически важным свойством объектноориентированного подхода является поддержка механизма обработки событий, которые изменяют атрибуты объектов и моделируют их взаимодействие в предметной области.
Современные языки программирования и .NET: II семестр Лекция 1: Объектно-ориентированный подход к программированию
Объектно-ориентированные языки программирования (2) Преимущества: • высокий уровень абстракции; • повторное использование описаний; • параметризация методов обработки объектов Недостатки: • сложность тестирования и верификации программ Примеры: C++, Visual Basic, C#, Eiffel, Oberon © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Перемещаясь по иерархии классов от более общих понятий предметной области к более конкретным (или от более сложных – к более простым) и наоборот, программист получает возможность изменять степень абстрактности или конкретности взгляда на моделируемый им реальный мир. Использование ранее разработанных (возможно, другими коллективами программистов) библиотек объектов и методов позволяет значительно сэкономить трудозатраты при производстве программного обеспечения, в особенности, типичного. Объекты, классы и методы могут быть полиморфными, что делает реализованное программное обеспечение более гибким и универсальным. Сложность адекватной (непротиворечивой и полной) формализации объектной теории порождает трудности тестирования и верификации созданного программного обеспечения. Пожалуй, это обстоятельство является одним из самых существенных недостатков объектно-ориентированного подхода к программированию. Наиболее известным примером объектно-ориентированного языка программирования является язык C++, развившийся из императивного языка С. Его прямым потомком и логическим продолжением является язык С#, который исследуется в качестве образца в данном курсе. Другие примеры объектно-ориентированных языков программирования представлены на слайде.
Современные языки программирования и .NET: II семестр Лекция 1: Объектно-ориентированный подход к программированию
Принципы объектно-ориентированного программирования: 1. Абстракция данных 2. Наследование конкретных атрибутов объектов и функций оперирования объектами на основе иерархии 3. Инкапсуляция (свойства и методы «спрятаны» внутри объекта) 4. Полиморфизм (функции с возможностью обработки данных переменного типа) © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Переход от структурно-процедурного подхода к программированию к объектноориентированному, подобно переходу от низкоуровневых языков программирования к языкам высокого уровня, требует значительных затрат времени и сил на обучение. Естественно, что платой за полученные знания является повышение производительности труда программистов при проектировании и реализации программного обеспечения. Другим преимуществом, которое дает ООП перед императивным подходом, является относительно более высокий процент повторного использования уже разработанного программного кода. При этом, в отличие от предыдущих подходов к программированию, объектноориентированный подход требует глубокого понимания основных принципов, или, иначе, концепций, на которых он зиждется. К числу основополагающих понятий ООП обычно относят абстракцию данных, наследование, инкапсуляцию и полиморфизм. Зачастую в практических и учебных курсах по программированию слушатели не имеют четкого математического основания для формирования достаточно полного и ясного представления об основах ООП. Преимуществом предлагаемого курса является то обстоятельство, что уже изученные в первой части курса разделы computer science (такие как, например, ламбда-исчисление и комбинаторная логика) позволяют сформировать глубокое и точное понимание фундаментальных понятий объектно-ориентированного программирования. В частности, понятие абстракции – основной операции ламбдаисчисления – для нас является уже хорошо знакомым. Поясним на качественном уровне другие фундаментальные принципы ООП. Так, наследование конкретных атрибутов объектов и функций оперирования объектами основано на иерархии. Инкапсуляция означает «сокрытие» свойств и методов внутри объекта. Полиморфизм, как и в функциональном программировании, понимается как наличие функций с возможностью обработки данных переменного типа.
Современные языки программирования и .NET: II семестр Лекция 1: Объектно-ориентированный подход к программированию
Абстракция и методы ее моделирования Вообще говоря, под aбстракцией понимается выражение языка программирования, отличное от идентификатора. Значение функции или переменной может быть присвоено абстракции и является значением последней. Поведение абстракции заключается в приложении функции к аргументу. Абстракция адекватно моделируется ламбда-исчислением (а именно, посредством операции абстракции). © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Рассмотрим более подробно такой фундаментальный ориентированного подхода к программированию, как абстракция.
принцип
объектно-
В разделах математики, исследующих моделирование процесса создания программ, под абстракцией принято понимать произвольное выражение языка программирования, которое является отличным от идентификатора. Важнейшей операцией, которая была исследована нами в первой части курса, является операция вычисления значения выражения или команды, т.е. операция означивания (в частности, функция вычисления значения явно используется при построении семантики языка программирования). В этой связи важно установить, что является значением абстракции. Будем считать, что значение функции или переменной может быть присвоено абстракции и является значением последней. В объектно-ориентированном программировании каждый объект является принципиально динамической сущностью, т.е. изменяется в зависимости от времени (а также от воздействия внешних по отношению к нему факторов). Иначе говоря, объект обладает тем или иным образом поведения. В отношении абстракции как объекта, поведение заключается в приложении функции к аргументу. Как мы уже отмечали, концепция абстракции в объектно-ориентированном программировании адекватно моделируется посредством ламбда-исчисления. Точнее говоря, операция абстракции в полной мере является моделью одноименного понятия ООП.
Современные языки программирования и .NET: II семестр Лекция 1: Объектно-ориентированный подход к программированию
Наследование и методы его моделирования Вообще говоря, под наследованием понимается свойство производного объекта сохранять поведение (атрибуты и операции) базового (родительского). В языках программирования понятие наследование означает применимость (некоторых) свойств или методов базового класса для классов, производных от него (а также для их конкретизаций). Наследование моделируется (иерархическим) отношением частичного порядка и адекватно формализуется посредством: 1) фреймовой нотации Руссопулоса (N.D. Roussopulos); 2) диаграмм Хассе (Hasse) © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Другой фундаментальной составляющей концепции объектно-ориентированного программирования является интуитивно ясное понятие наследования. В неформальной постановке под наследованием понимается свойство того или иного объекта, который является производным от некоего базового, сохранять поведение (а именно, атрибуты и операции над ними), характерное для родительского объекта. С точки зрения языков программирования понятие наследования означает применимость всех или лишь некоторых свойств и/или методов базового (или родительского) класса для всех классов, производных от него. Кроме того, сохранение свойств и/или методов базового класса должно обеспечиваться и для всех конкретизаций (т.е. конкретных объектов) любого производного класса. В математике концепцию наследования принято моделировать, например, отношением частичного порядка (которое представляет собой вид иерархии). Концепцию наследования можно адекватно формализуется математически посредством одной из следующих нотаций: 1) фреймовой нотации Руссопулоса (названной так по имени своего создателя, N.D. Roussopulos); 2) диаграмм Хассе (получивших название по имени ученого, который впервые предложил этот способ наглядного представления наследования Helmut Hasse).
Современные языки программирования и .NET: II семестр Лекция 1: Объектно-ориентированный подход к программированию
Пример единичного наследования на C# (1) class A { // базовый класс int a; public A() {...} public void F() {...} } class B : A { // подкласс (наследует свойства класса A, расширяет класс A) int b; public B() {...} public void G() {...} } © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Рассмотрим пример программы на языке программирования C#, иллюстрирующий концепцию наследования: class A { // базовый класс int a; public A() {...} public void F() {...} } class B : A { // подкласс (наследует свойства класса A, расширяет класс A) int b; public B() {...} public void G() {...} }
Пример представляет собой описание базового класса A и производного от него класса B. Класс A содержит целочисленный атрибут (т.е. переменную) a, а также два метода (т.е. функции) A(…) и F(…). Класс B содержит целочисленный атрибут (т.е. переменную) b, а также два метода (т.е. функции) B(…) и G(…). Двоеточие B:A в описании класса B означает наследование. Отметим, что в заголовок слайда вынесен простейший случай наследования, а именно, единичное наследование. Язык программирования C# позволяет реализовать механизмы, поддерживающие и более сложный случай наследования, а именно, множественное наследование.
Современные языки программирования и .NET: II семестр Лекция 1: Объектно-ориентированный подход к программированию
Пример единичного наследования на C# (2)
B наследует свойство a и метод F(), добавляя b и G(): - конструкторы не наследуются; - наследуемые методы могут игнорироваться (см. далее) Единичное наследование: подкласс может наследовать свойства единственного базового класса, однако может при этом реализовывать множественные интерфейсы. Класс может наследовать свойства класса, но не структуры. Структура не может наследовать свойства другого типа данных, однако может при этом реализовывать множественные интерфейсы. Подкласс с неявным базовым классом наследует свойства класса объект (object). © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Рассмотрим более подробно, особенности наследования, которые реализует данный пример программы на языке C#. Производный класс B наследует от базового класса А свойство a и метод F(). При этом к классу В добавляются собственные свойство b и метод G(). Заметим, что в отношении операции наследования справедливы следующие ограничения: 1) конструкторы (т.е. функции создания и инициализации классов) не наследуются; 2) в языке C# существует возможность замещения наследуемых методов (этот языковой аспект будет рассмотрен более подробно в ходе дальнейших лекций). Отметим также, что наиболее простым случаем наследования является так называемое единичное наследование. При таком наследовании производный класс (или, иначе, подкласс) может наследовать свойства только одного базового класса. Однако при этом производный класс может этом реализовывать множественные интерфейсы (т.е. использовать описания объектов и методов других классов, напрямую минуя механизм наследования). Один класс языка программирования C# может наследовать лишь свойства другого класса (но не структуры – типа данных, аналогичного кортежу языка программирования SML). Структура не может наследовать свойства другого типа данных, однако может при этом реализовывать как один, так и несколько интерфейсов. Подкласс с неявным базовым классом наследует свойства наиболее абстрактного класса, известного под названием «объект» (object).
Современные языки программирования и .NET: II семестр Лекция 1: Объектно-ориентированный подход к программированию
Понятие инкапсуляции в программировании Вообще говоря, под инкапсуляцией понимается доступность объекта исключительно посредством его свойств и методов. Таким образом, свойствами объекта (явно описанными или производными) возможно оперировать исключительно посредством его методов. Свойства инкапсуляции: • совместное хранение данных и функций; • сокрытие внутренней информации от пользователя; • изоляция пользователя от особенностей реализации © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Еще одним фундаментальным компонентом концепции объектно-ориентированного программирования является понятие инкапсуляции. Неформально говоря, под инкапсуляцией понимается возможность доступа к объекту и манипулирования им исключительно посредством предоставляемых именно этим объектом свойств и методов. Таким образом, свойствами объекта (безразлично, являются ли они явно описанными или производными от других объектов) возможно оперировать исключительно посредством методов, которые содержатся в описании этого объекта (или родительских по отношению к нему объектов, при условии, что эти методы унаследованы). Инкапсуляция является весьма важным свойством, поскольку обеспечивает определенную (а точнее, определяемую программистом) степень безопасности данных об объекте. Хотя инкапсуляция как таковая является фундаментальным свойством ООП, степень инкапсуляции при наследовании может варьироваться в зависимости от типа области видимости объекта, который определяется модификатором видимости. Так, используемый в предыдущем примере модификатором видимости public обеспечивает доступность свойств и методов объекта из произвольного места программы. К основным свойствам инкапсуляции относятся следующие возможности: 1) совместное хранение данных и функций (т.е. свойств и методов внутри объекта); 2) сокрытие внутренней информации от пользователя (что обеспечивает большую безопасность приложения); 3) изоляция пользователя от особенностей реализации (что обеспечивает машинную независимость и потенциально дружественный интерфейс приложений).
Современные языки программирования и .NET: II семестр Лекция 1: Объектно-ориентированный подход к программированию
Понятие полиморфизма в программировании Вообще говоря, под полиморфизмом понимается возможность оперировать объектами, не обладая точным знанием их типов. Рассмотрим пример полиморфной функции: void Poly(object o) { Console.WriteLine(o.ToString()); }
а также вариантов ее использования: Poly(25); Poly(“John Smith”); Poly(3.141592536m); Poly(new Point(12,45)); © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Как нам уже известно, важной позитивной особенностью языка программирования SML является то обстоятельство, что в нем поддерживается так называемая полиморфная типизация, суть которой можно объяснить на основе следующего примера. Рассмотрим функцию обработки списка, которая упорядочивает его элементы по возрастанию. В классическом языке программирования со строгой типизацией неизбежно придется реализовать по крайней мере две функции: для случаев числовых и строковых элементов списка. В SML не возникает такой необходимости, т.к. существует возможность описания функции обработки списка с переменным типом аргументов, которая безошибочно обработает и список из чисел, и список из строк. В объектно-ориентированном программировании под полиморфизмом понимается возможность оперировать объектами, не обладая точным знанием их типов. Рассмотрим пример простейшей полиморфной функции: void Poly(object o) { Console.WriteLine(o.ToString()); }
Данная функция реализует выдачу на экран объекта (метод Console.WriteLine) с предварительным преобразованием его к строковому типу (метод ToString()) . Все приведенные на слайде варианты вызова функции: Poly(25); Poly(“John Smith”); Poly(3.141592536m); Poly(new Point(12,45));
корректно пройдут компиляцию и завершатся выдачей корректного результата.
Современные языки программирования и .NET: II семестр Лекция 1: Объектно-ориентированный подход к программированию
Библиография (1) 1.
Pratt T.W., Zelkovitz M.V. Programming languages, design and implementation (4th ed.).- Prentice Hall, 2000
2.
Appleby D., VandeKopple J.J. Programming languages, paradigm and practice (2nd ed.).- McGraw-Hill, 1997
3.
Troelsen A. C# and the .NET platform (2nd ed.).- APress, 2003, 1200 p.p.
4.
Liberty J. Programming C# (2nd ed.).- O’Reilly, 2002, 656 p.p. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду К сожалению, в рамках одной лекции невозможно в полном объеме представить глубину объектно-ориентированного подхода к программированию. Мы ограничились кратким рассмотрением ООП в системе возможных подходов, а также формированием представления об основополагающих принципах объектно-ориентированного подхода. Для более детального ознакомления с последними достижениями и проблемами в области ООП, рекомендуется следующий список литературы: 1. Pratt T.W., Zelkovitz M.V. Programming languages, design and implementation (4th ed.).Prentice Hall, 2000 2. Appleby D., VandeKopple J.J. Programming languages, paradigm and practice (2nd ed.).McGraw-Hill, 1997 3.Troelsen A. C# and the .NET platform (2nd ed.).- APress, 2003, 1200 p.p. 4. Liberty J. Programming C# (2nd ed.).- O’Reilly, 2002, 656 p.p. Кратко остановимся на источниках. В работе [1] приведен наиболее полный анализ истории развития и особенностей языков программирования с классификацией по областям применения. В работах [2-4] рассмотрены теоретические проблемы и практические аспекты реализации инновационных конструкций в языках программирования, прежде всего, в языке C#.NET, изучение основ которого планируется в данном семестре.
Современные языки программирования и .NET: II семестр Лекция 1: Объектно-ориентированный подход к программированию
Библиография (2) 5.
Landin P. The next 700 programming languages. Communications of ACM, 3, 1966
6.
Peyton Jones S.L. The implementation of functional programming languages.- Prentice Hall, 1987
7.
Gilmore S. Programming in Standard ML ’97: a tutorial introduction. http:/www.dcs.ed.ac.uk/home/stg © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Продолжим обсуждение библиографии. 5.Landin P. The next 700 programming languages. Communications of ACM, 3, 1966 6.Peyton Jones S.L. The implementation of functional programming languages.- Prentice Hall, 1987 7.Gilmore S. Programming http:/www.dcs.ed.ac.uk/home/stg
in
Standard
ML
’97:
a
tutorial
introduction.
В работе [5] исследуются современные тенденции развития языков и подходов к программированию. Работа [6] посвящена вопросам реализации языков программирования, в частности, на основе функционального подхода. Работа [7] содержит описание языка функционального программирования Standard ML (в сравнении с которым в данном курсе излагается ООП) и практике программирования на нем.
Платформа .NET и ее применение для ООП
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В данной лекции будут рассмотрены вопросы, относящиеся к идеологии, технологии и обзору практических возможностей создания объектно-ориентированных программных систем на основе наиболее современного подхода к проектированию и реализации программного обеспечения, известного под названием Microsoft .NET.
Современные языки программирования и .NET: II семестр Лекция 2: Платформа .NET и ее применение для ООП
Содержание лекции 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11.
.NET как концепция .NET как вычислительная модель .NET как технологическая платформа .NET как инструментальное средство Common Language Runtime и .NET Framework Система типов Common Type System в .NET Веб-сервисы в .NET Компонентное программирование в .NET Сравнение компонентного программирования с ООП Преимущества и недостатки .NET Библиография © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Коротко о содержании лекции. В отличие от всех предшествующих подходов, компания Microsoft предлагает наиболее развитое и комплексное решение для проектирования и реализации программного обеспечения. В частности, в данной лекции будут рассмотрены такие аспекты .NET, как: • идеология; • вычислительная модель; • технологическая платформа; • инструментальное решение; • безопасность; • интеграция приложений; • организация вычислительных сред CLR и . NET Framework; • универсальная система типов в .NET, известная как CTS; • поддержка веб-сервисов; • компонентный подход к программированию и его связь с ООП. В заключение будут проанализированы достоинства и недостатки .NET и сделаны необходимые выводы. Наконец, для желающих глубже исследовать предмет будут представлены ссылки на важнейшие работы теоретического и практического плана по теме лекции.
Современные языки программирования и .NET: II семестр Лекция 2: Платформа .NET и ее применение для ООП
Что такое .NET ? .NET включает следующие основные аспекты : 1.
Идеология проектирования и реализации программного обеспечения
2.
Модель эффективной поддержки жизненного цикла прикладных систем
3.
Унифицированная, интегрированная технологическая платформа
4.
Современный, удобный в использовании, безопасный инструментарий для создания, размещения и поддержки программного обеспечения © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Прежде всего, необходимо ответить на важный вопрос: что такое .NET? Несмотря на широкое освещение в прессе, ответить однозначно непросто, прежде всего по той причине, что ответ представляется многоаспектным. Итак, можно сказать, что .NET – это подход к проектированию и реализации программного обеспечения, включающий по меньшей мере четыре следующих компонента: 1) идеология проектирования и реализации программного обеспечения; 2) модель эффективной поддержки жизненного цикла прикладных систем; 3) унифицированная, интегрированная технологическая платформа для программирования; 4) современный, удобный в использовании, безопасный инструментарий для создания, размещения и поддержки программного обеспечения. Остановимся подробнее на каждом из этих существенных аспектов.
Современные языки программирования и .NET: II семестр Лекция 2: Платформа .NET и ее применение для ООП
.NET как идеология (vision) 1.
Легкость развертывания приложений в глобальной среде Интернет
2.
Экономичная разработка программного обеспечения
3.
«Бесшовная», гибкая интеграция программных продуктов и аппаратных ресурсов
4.
Предоставление программного обеспечения как сервиса
5.
Новый уровень безопасности и удобства использования © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Прежде всего, постараемся сформировать понимание идеологии подхода Microsoft .NET. Самой корпорацией-разработчиком сформулированы важнейшие аспекты видения (vision) идеологии .NET: 1) 2) 3) 4) 5)
приблизительно
следующие
легкость развертывания приложений в глобальной среде Интернет; экономичная разработка программного обеспечения; «бесшовная», гибкая интеграция программных продуктов и аппаратных ресурсов; предоставление программного обеспечения как сервиса; новый уровень безопасности и удобства использования.
Действительно, как мы увидим в ходе лекции, все аспекты видения .NET удалось реализовать на качественно новом уровне, обеспечив существенное продвижение вперед в направлении гибкости интеграции с программно-аппаратными ресурсами, безопасности и удобстве использования кода, а также снижении затрат на производство программного обеспечения.
Современные языки программирования и .NET: II семестр Лекция 2: Платформа .NET и ее применение для ООП
.NET как вычислительная модель 1.
Компонентный подход как развитие объектноориентированной модели
2.
Универсальная система типизации: «всякая сущность есть объект»; унификация данных и метаданных
3.
Строго иерархическая организация кода, пространств имен и классов
4.
Универсальный интерфейс .NET Framework (включая поддержку различных подходов к программированию)
5.
Высокая вариативность экземпляров реализации (в частности, на основе веб-сервисов) © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Рассмотрим подробнее, как идеология .NET претворяется в практические вопросы проектирования программного обеспечения. Корпорацией Microsoft предложен новаторский компонентно-ориентированный подход к проектированию, который является развитием объектно-ориентированного направления. Согласно этому подходу, интеграция объектов (возможно, гетерогенной природы), производится на основе интерфейсов, представляющих эти объекты (или фрагменты программ) как независимые компоненты. Такой подход существенно облегчает написание и взаимодействие программных «молекул»-компонент в гетерогенной среде проектирования и реализации. Стандартизируется хранение и повторное использование компонент программного проекта в условиях распределенной сетевой среды вычислений, где различные компьютеры и пользователи обмениваются информацией, например, взаимодействуя в рамках исследовательского или бизнес-проекта. Существенным преимуществом является и возможность практической реализации принципа «всякая сущность является объектом гетерогенной программной среды». Во многом это стало возможным благодаря усовершенствованной, обобщенной системе типизации Common Type System, или CTS, которая будет подробнее рассмотрена в одной из следующих лекций. Строгая иерархичность организации пространств для типов, классов и имен сущностей программы позволяет стандартизировать и унифицировать реализацию. Новый подход к интеграции компонент приложений в среде вычислений Интернет (или так называемые веб-сервисы), дает возможность ускоренного создания приложений для глобальной аудитории пользователей. Универсальный интерфейс .NET Framework обеспечивает интегрированное проектирование и реализацию компонент приложений, разработанных согласно различным подходам к программированию.
Современные языки программирования и .NET: II семестр Лекция 2: Платформа .NET и ее применение для ООП
.NET как технологическая платформа 1.
Многоязыковая поддержка (десятки языков программирования)
2.
Использование технологии веб-сервисов для обеспечения интероперабельности и масштабируемости в глобальной сетевой среде
3.
Унификация доступа к библиотекам API-интерфейса независимо от языка и программной модели
4.
Соответствие современным технологическим стандартам © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Говоря о .NET как о технологической платформе, нельзя не отметить тот факт, что она обеспечивает одновременную поддержку проектирования и реализации программного обеспечения с использованием различных языков программирования. При этом поддерживаются десятки языков программирования, начиная от самых первых (в частности, COBOL и FORTRAN) и заканчивая самыми современными (например, C# и Visual Basic). Ранние языки программирования до сих пор активно используются, в частности, для обеспечения совместимости с ранее созданными приложениями, критичными для бизнеса (скажем, COBOL весьма широко использовался для создания прикладных программ, поддерживающих финансовую деятельность). Применение технологии веб-сервисов – это не просто дань моде на Интернет, а реальная (и, пожалуй, наиболее приемлемая практически возможность) обеспечения масштабируемости и интероперабельности приложений. Под масштабируемостью понимают возможность плавного роста времени ответа программной системы на запрос с ростом числа одновременно работающих пользователей; в случае веб-сервисов масштабируемость реализуется посредством распределения вычислительных ресурсов между сервером, на котором выполняется прикладная программа (или хранятся данные) и компьютером пользователя. Под интероперабельностью понимается возможность интегрированной обработки гетерогенных данных, поступающих от разнородных прикладных программ. Именно благодаря интероперабельности возможна унификация взаимодействия пользователей через приложение с операционной системой на основе специализированного интерфейса прикладных программ, или API-интерфейса (Application Programming Interface). Немаловажно отметить и то обстоятельство, что новая технология .NET не только востребована мировой общественностью, но и официально признана, что отражено в соответствующих стандартах ECMA (European Computer Manufacturers Association).
Современные языки программирования и .NET: II семестр Лекция 2: Платформа .NET и ее применение для ООП
.NET - универсальное инструментальное средство 1. 2. 3. 4. 5.
Поддержка многоязыковой среды CLR (Common Language Runtime) Возможность создавать компоненты проекта в единой среде на наиболее подходящем языке программирования Доступность всех средств .NET для каждого из широкого спектра языков программирования Сервисные возможности для разработчиков, (отладка, анализ кода, …) одинаковы для всех языков Возможность облегченной самостоятельной разработки транслятора для любого языка программирования (Microsoft – VB, C#, … другие – APL, COBOL, Eiffel, Fortran, Haskell, SML, Perl, Python, Scheme, Smalltalk, …)
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Теперь рассмотрим инструментальные возможности .NET как средства проектирования и реализации программного обеспечения, т.е., собственно, программирования в широком смысле этого слова. Прежде всего, необходимо отметить поддержку многоязыковой среды разработки приложений CLR (Common Language Runtime). Эта возможность появилась благодаря универсальному межъязыковому интерфейсу Common Language Infrastructure, или CLI, который поддерживает разработку программных компонент на различных языках программирования. При этом несомненным преимуществом для программистов является то обстоятельство, что они могут разрабатывать (или дорабатывать) программное обеспечение на наиболее подходящем языке программирования. Здесь следует учитывать характер задачи (скажем, рекурсия или символьная обработка прозрачнее и с меньшими трудозатратами реализуема на языке функционального программирования, а формализация структуры предметной области – на объектно-ориентированном языке). Кроме того, необходимо принимать во внимание опыт работы программистов в команде разработчиков и тот язык программирования, на котором изначально создавалась система. Отметим еще два существенных обстоятельства. Во-первых, основные сервисные возможности для разработчиков, которые предоставляет среда .NET (отладка, анализ кода и т. д.) не зависят от конкретного языка программирования, и, следовательно, программистам нет необходимости заново постигать особенности среды разработки, если необходимо перейти с одного языка на другой. Во-вторых, несмотря на то, что еще не все языки программирования поддерживаются .NET, существует возможность самостоятельной разработки транслятора для любого языка программирования, причем его реализация не вызывает трудностей даже у программистов, практически не имеющих профессиональной подготовки в области разработки компиляторов.
Современные языки программирования и .NET: II семестр Лекция 2: Платформа .NET и ее применение для ООП
Архитектурная схема .NET Framework и Visual Studio.NET SML
C#
VB
C++
…
ASP.NET: Веб-сервисы и веб-формы
Формы Windows
ADO.NET: данные и XML Базовые классы .NET Framework
Visual Studio.NET
Common Language Specification (CLS)
Common Language Runtime (CLR) © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Кратко обсудим основные аспекты архитектурного решения Microsoft .NET Framework, отметив прежде всего то обстоятельство, что важную роль играет среда разработки Microsoft Visual Studio.NET, а первостепенное значение отводится среде выполнения программ – Common Language Runtime (CLR).Среда выполнения программ CLR реализует управление памятью, типами данных, межъязыковым взаимодействием, разворачиванием (deployment) приложений. Существенным преимуществом конструктивного решения .NET является компонентноориентированный подход к проектированию и реализации программного обеспечения, который будет подробнее рассмотрен в ходе настоящей лекции. Суть подхода состоит в принципиальной возможности создания независимых составляющих программного обеспечения с унифицированной интерфейсной частью для многократного повторного и распределенного использования. При этом продуктивность решения обусловлена многоязычностью интегрируемых программных проектов (концепция .NET потенциально поддерживает произвольный язык программирования, в числе наиболее известных языков – C#, Visual Basic, C++ и др.) В ходе компиляции программа на .NET-совместимом языке программирования трансформируется в соответствии с заранее заданной обобщенной спецификацией языка Common Type System (CTS). Система типов CTS полностью описывает все типы данных, поддерживаемые средой выполнения, определяет их взаимосвязи и хранит их отображения в систему типов .NET. Под Common Language Specification (или CLS) понимается набор правил, определяющих подмножество обобщенных типов данных, в отношении которых гарантируется, что они безопасны при использовании во всех языках .NET. Интерфейсы реализуются посредством форм Windows и ASP.NET для веб-приложений.
Современные языки программирования и .NET: II семестр Лекция 2: Платформа .NET и ее применение для ООП
Схема компиляции в Common Language Runtime Исходный текст
Компилятор
Сборка
SML, C#, C++, VB или другой ЯП для .NET
csc.exe или vbc.exe
DLL или EXE
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Как уже упоминалось, среда выполнения программ CLR реализует управление памятью, типами данных, межъязыковым взаимодействием, разворачиванием (deployment) приложений. В ходе выполнения процедуры трансляции исходный текст программы (написанный на SML, C#, Visual Basic, C++ или любом из множества других языков программирования, который поддерживается .NET) преобразуется компилятором в так называемую сборку (assembly) и сохраняется в виде файла динамически присоединяемой библиотеки (Dynamically Linked Library, DLL) или исполняемого файла (Executable, EXE). Естественно, что для каждого компилятора (будь то компилятор языка C#, csc.exe или Visual Basic, vbc.exe) средой времени выполнения производится необходимое отображение используемых типов в типы CTS, а программного кода – в код «абстрактной машины» .NET – MSIL (Microsoft Intermediate Language). В итоге программный проект формируется в виде сборки – самодостаточного компонента для разворачивания, тиражирования и повторного использования. Сборка идентифицируется цифровой подписью автора и уникальным номером версии.
Современные языки программирования и .NET: II семестр Лекция 2: Платформа .NET и ее применение для ООП
Схема выполнения CLR Исходный текст
MSIL
SML
C#
C++
Компилятор
Компилятор
Компилятор
Сборка
Сборка
Сборка
JIT-компилятор для Common Language Runtime
«Родной» код
Управляемый код CLR Services
Управляемый код
Управляемый код
Неуправляемый код
Сервисы операционной системы © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Рассмотрим достаточно обобщенный пример трансляции многокомпонентного гетерогенного программного проекта под управлением Microsoft .NET. Предположим, что компоненты проекта написаны на трех языках программирования: уже знакомого нам языка SML, изучаемого языка C#, а также языка С++, который характеризуется возможностью написания потенциально небезопасного кода (в частности, динамического распределения памяти). Исходные тексты компонент проекта транслируются соответственно компиляторами с языков SML, C# и C++ в унифицированный MSIL-код и сохраняются в файлах в виде сборок. В ходе компоновки и выполнения программного проекта Just-In-Time (JIT) компилятор среды CLR производит выполнение проекта с ленивым (по мере необходимости) означиванием оттранслированного промежуточного кода сборок. Существенно, что потенциально небезопасный код на языке C++ принципиально невыполним собственно JIT-компилятором, но исполняется посредством сервисов операционной системы. Ответственность за работоспособность программы и безопасность кода в этом случае лежит уже не на среде проектирования и разработки программного обеспечения .NET, а на программисте-разработчике.
Современные языки программирования и .NET: II семестр Лекция 2: Платформа .NET и ее применение для ООП
Универсальная система типизации (UTS) Тип
Типы-значения
Простые типы bool char
sbyte short int long
byte ushort uint ulong
Enum float double decimal
Типы-ссылки
Struct
Class
Interface
Указатели
Array
Delegate
Типы, определяемые пользователем - ISA-иерархия
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Существенным позитивным отличием Microsoft .NET от существующих аналогов на современном рынке программного обеспечения является универсальная система типизации. В ходе компиляции программа на .NET-совместимом языке программирования трансформируется в соответствии с заранее заданной обобщенной спецификацией языка Common Type System (CTS). Система типов CTS полностью описывает все типы данных, поддерживаемые средой выполнения, определяет их взаимосвязи и хранит их отображения в систему типов .NET. Система типизации Microsoft .NET представляет собой частично упорядоченное множество, которое на качественном уровне может пониматься как ISA-иерархия (ISA происходит от английских слов “is a”, которые означают «является одним из»). Так, например, высказывание STUDENT ISA PERSON означает, что тип STUDENT является подтипом типа PERSON (здесь вполне уместна аналогия с множествами и вполне точна аналогия с доменами). Таким образом, система типов Microsoft .NET образует иерархию с возрастанием общности снизу вверх (см. слайд), в которой явно выделяются две большие группы типов, а именно, типы-ссылки и типы-значения. Различие между последними определяется особенностями вызова в процедурах: по имени или по значению (call-by-name, CBN) и по ссылке (call-by-reference, CBR). Заметим также, что система типизации Microsoft .NET помимо развитой иерархии предопределенных типов позволяет пользователю создавать собственные типы (как типыссылки, так и типы-значения) на основе уже существующих.
Современные языки программирования и .NET: II семестр Лекция 2: Платформа .NET и ее применение для ООП
Веб-сервисы в .NET (1) Клиенты
Приложения
Веб-форма Протоколы: HTTP, HTML, XML, SOAP, UDDI
Внутренний веб-сервис
Веб-сервис
.NET Framework Windows
Веб-сервисы .NET
Сторонние веб-сервисы
Инстр. средства: Visual Studio.NET, Notepad
Корпоративные серверы .NET
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Изложение важнейших аспектов Microsoft .NET было бы не полным, если бы мы не упомянули о таком существенном архитектурном принципе как веб-сервисы. Значение веб-сервисов заключается в распределении возможностей разработанных прикладных систем по каналам глобальной сети Интернет. Заметим, что центральным блоком в схеме является .NET Framework, который можно рассматривать как библиотеку базовых объектов и операций над ними. В качестве среды разработки прикладных систем целесообразно использовать Microsoft Visual Studio .NET, предоставляющей целый комплекс развитых средств создания, редактирования и отладки программного кода на различных языках программирования. В случае несложных задач можно ограничиться примитивными редакторами текста программ, подобных Notepad. Интерфейсная часть прикладной программной системы в Интернет-архитектуре представлена так называемыми веб-формами, предназначенными для ввода и вывода данных в унифицированном формате. В качестве языка реализации может использоваться язык гипертекстовой разметки HTML (HyperText Markup Language). Взаимодействие между клиентом и приложением в простейшем случае осуществляется с использованием традиционного Интернет-протокола передачи данных HTTP (HyperText Transfer Protocol). Структурированные данные хранятся в формате XML (вариант HTML с более строгим синтаксисом). Заметим, что технология веб-сервисов, реализованная Microsoft, допускает интеграцию с компонентами сторонних производителей.
Современные языки программирования и .NET: II семестр Лекция 2: Платформа .NET и ее применение для ООП
Веб-сервисы в .NET (2) 1.
Программируемые компоненты приложений, доступные посредством стандартных Интернетпротоколов
2.
Центральная часть архитектуры .NET
3.
Распределяют функциональность по глобальной сети
4.
Строятся на существующих и развивающихся стандартах: HTTP, XML, SOAP, UDDI, WSDL и др. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Попытаемся сформулировать определения понятия «веб-сервис» (или, иначе, «вебслужба»). Под веб-сервисами обычно понимают программируемые компоненты прикладных программных систем, которые доступны для клиента (пользователя) посредством стандартных протоколов, применяемых для работы в Интернет-среде. Как уже упоминалось ранее, именно веб-сервисы являются одной из важнейших составляющих идеологии .NET и центральной частью данной архитектуры, поскольку предназначены для реализации декларируемого Microsoft основополагающего принципа «программное обеспечение как сервис». Смысл использования веб-сервисов состоит в возможности распределения функциональных возможностей разработанных прикладных систем по глобальной сети. Для реализации этой задачи веб-сервисы надстраиваются на прошедших долговременную апробацию, традиционных, а также на развивающихся стандартах взаимодействия приложений в Интернет, а именно: 1) HTTP – стандартный протокол обмена гипертекстовыми документами в Интернет с возможностью передачи данных посредством веб-форм; 2) XML – формат хранения структурированных данных с возможностью обмена ими по Интернет-каналам; 3) SOAP – стандартный протокол взаимодействия компонент (глобально) распределенного приложения (Simple Object Access Protocol); 4) UDDI – стандарт интеграции приложений (Universal Description, Discovery and Integration); 5) WSDL – универсальный язык описания веб-сервисов (Web Service Description Language); а также целом ряде других менее употребительных протоколов.
Современные языки программирования и .NET: II семестр Лекция 2: Платформа .NET и ее применение для ООП
Компонентное программирование в .NET (1) • Компоненты – это: – независимые повторно используемые и тиражируемые модули; – в целом более крупные, чем объект (объекты – конструкции уровня ЯП); – могут содержать множественные классы; – независимы от языка реализации. • В общем случае, разработчик и пользователь компонента территориально разделены и пользуются разными языками в единой среде. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Одним из принципиальных технологических преимуществ проектирования и реализации программного обеспечения, декларируемых Microsoft, является так называемый компонентный подход к программированию. В своей основе указанный подход совпадает с традиционным объектно-ориентированным, однако имеет ряд важных особенностей. Поскольку конечной целью данной части учебного курса является гетерогенное компонентное программирование, необходимо с самого начала уяснить смысл основных понятий, на которых зиждется компонентный подход. Центральной концепцией подхода (и это очевидно уже из названия) является понятие компонента. Под компонентом в дальнейшем будем понимать независимый модуль программного обеспечения, который возможно повторно использовать, а также тиражировать. В отличие от «традиционных» объектов ООП компоненты обладают следующими характеристическими свойствами: • в целом компонент обладает более высоким уровнем абстракции по сравнению с объектом (если под последним понимается конструкция уровня языка программирования); • компоненты могут содержать в своем составе множественные классы; • компоненты с точки зрения пользователя являются инвариантами по отношению к тому языку программирования, на котором они реализованы. Таким образом, оказывается, что в общем случае разработчик и пользователь компонента могут быть территориально разделены и могут использовать различные языки программирования в рамках единой среды разработки приложений Microsoft .NET.
Современные языки программирования и .NET: II семестр Лекция 2: Платформа .NET и ее применение для ООП
Компонентное программирование в .NET (2) • Компонентная объектная модель (COM): – основной стандарт Microsoft для компонент; – содержит протокол для инициализации и использования компонентов внутри одного процесса, между процессами или между компьютерами; – основа для ActiveX, OLE и многих других технологий; – поддерживается в Visual Basic, C++, .NET и др. • Модель Java Beans: – основной стандарт Sun Microsystems для компонент; – зависима от языка реализации. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Заметим, что попытки построения компонентных программных систем предпринимались и рядом других компаний – разработчиков программного обеспечения (в частности, технология JavaBeans производства Sun Microsystems), а также международных ассоциаций, объединяющих усилия исследователей и практиков в области объектного программирования (например, стандарт брокеров объектных запросов CORBA организации Object Management Group, или OMG). В основе таких попыток лежали варианты объектных моделей. Один из подобных вариантов, детально проработанный с математической точки зрения, а именно, модель двухуровневой концептуализации, нам предстоит рассмотреть в ходе данного курса. Сейчас же лишь кратко охарактеризуем основные отличительные особенности наиболее известных из представленных на рынке современного программного обеспечения объектных моделей. Прежде всего, охарактеризуем компонентную модель Microsoft, которая обычно именуется в литературе аббревиатурой COM (что происходит от слов Component Object Model). Компонентная объектная модель COM является основным стандартом Microsoft для компонентного проектирования и реализации программного обеспечения. На сегодня это самая развитая, и, пожалуй, самая удачная в практическом плане модель, которая практически обеспечивает возможность инициализации и использования компонентов как внутри одного процесса, так и между процессами или между компьютерами независимо от языка реализации. COM-модель поддерживается в идеологии .NET для целого ряда языков программирования (C#, SML, Visual Basic, C++ и др.), является основой для ActiveX, OLE, а также для многих других технологий Microsoft. В отличие от СОМ, модель Java Beans, базовый стандарт Sun Microsystems для компонент, оказывается зависимой от языка реализации.
Современные языки программирования и .NET: II семестр Лекция 2: Платформа .NET и ее применение для ООП
Сравнение компонентно- и объектно-ориентированного программирования 1. Основные понятия объектно-ориентированного программирования: • класс (class); • интерфейс (interface) 2. Основные понятия компонентно-ориентированного программирования: • свойство (property); • событие (event); • сборка (assembly) © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Исследовав основные особенности объектно-ориентированного и компонентного подходов к проектированию и реализации программного обеспечения, произведем краткий сравнительный анализ этих особенностей и подходов в целом. Прежде всего, перечислим основополагающие понятия, характеризующие каждый из подходов. Затем сопоставим эти подходы друг с другом с целью поиска аналогий между ними. В объектно-ориентированном подходе ключевыми являются, в частности, понятия класса и интерфейса. Заметим, что в компонентно-ориентированном подходе эти понятия также являются системообразующими. При этом под классом понимается базовая сущность, определяемая как совокупность своих элементов. Под интерфейсом понимается набор семантически связанных абстрактных элементов. Для компонентно-ориентированного подхода понятие интерфейса имеет первостепенное значение, поскольку исключительно посредством этого механизма клиент в архитектуре с моделью COM может непосредственно осуществлять взаимодействие с COM-классом. Заметим, что интерфейсы повышают безопасность кода, т.к. взаимодействие с объектом происходит не непосредственно, а через указатель (ссылку). Понятия свойства (как атрибута объекта) и метода (как операции над объектом), также как и механизма событий (соотнесений над объектами предметной области) свойственны обоим подходам. Принципиально новым является наличие в COM-модели сборок – самодостаточных единиц информации для инсталляции и распространения программных продуктов. В целом COM-подход является более удобным с практической точки зрения, хотя механизмы, реализованные в нем, принципиально сравнимы с возможностями ООП.
Современные языки программирования и .NET: II семестр Лекция 2: Платформа .NET и ее применение для ООП
.NET – наиболее существенные недостатки 1. 2. 3. 4.
Высокие требования к аппаратному обеспечению (минимум 256M RAM, 10G HDD для работы с Microsoft Visual Studio .NET) Сложности работы с некоммерческими релизами программного обеспечения (некоторая неустойчивость, отсутствие полномасштабной документации); Поддержка ряда теоретически интересных и практически полезных языков программирвоания не в полном объеме (SML для Visual Studio .NET – в процессе реализации); Инструментарий .NET (и компиляторы для языков программирования) не ратифицированы по международным стандартам. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Несмотря на перечисленные выше инновации в области теории, технологии и практической реализации, в силу масштабности идеологии и новизны исследуемой проблематики, подход .NET не лишен отдельных недостатков, большинство из которых, по-видимому, носит временный характер. Отметим, по нашему мнению, наиболее существенные из них. Во-первых, разработчики отмечают достаточно высокие требования к аппаратному обеспечению (в частности, объем оперативной памяти должен быть не менее 256 мегабайт, свободный объем жесткого диска для работы с Microsoft Visual Studio .NET – не менее 10 гигабайт). Кроме того, некоммерческие версии программных продуктов Microsoft, которые зачастую предоставляют новые существенные возможности, в недостаточной степени устойчивы в работе; документация по ряду новых функций программного обеспечения представлена не в полном объеме. Поддержка ряда теоретически интересных и практически полезных языков программирования реализована в ограниченном объеме (скажем, компилятор для языка программирования SML для Visual Studio .NET находится в процессе реализации). Поскольку целый ряд компиляторов для языков программирования предоставляется сторонними по отношению к Microsoft компаниями-разработчиками или некоммерческими учреждениями, результаты их деятельности поддаются контролю и доработке с ограничениями. Комплекс программно-инструментальных средств, реализующий подход .NET (включая и компиляторы для языков программирования) ратифицирован по международным стандартам не в полном объеме.
Современные языки программирования и .NET: II семестр Лекция 2: Платформа .NET и ее применение для ООП
Платформа .NET – выводы 1.
Стратегическая идеология и технологическая платформа Microsoft на ближайшее десятилетие 2. Несомненное качественное превосходство над аналогами (Inprise Delphi, Microsoft Visual Studio и др.) за счет: • интероперабельности и межъязыкового взаимодействия; • многоуровневой безопасности; • интеграции с веб-сервисами; • облегчения разворачивания и использования. 3. Некоторая незавершенность решения для широкого коммерческого использования в силу концептуальной новизны и грандиозности проекта. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Кратко резюмируем итоги лекции. Безусловно, .NET является выдающимся достижением современной индустрии программирования. Достаточно сказать, что корпорация Microsoft считает именно .NET своей стратегической идеологией и технологической платформой на ближайшее десятилетие. Несомненное качественное превосходство над существующими средствами автоматизированного проектирования и быстрой реализации прикладного программного обеспечения (в частности, Inprise Delphi и JBuilder, Oracle Developer, Microsoft Visual Studio и др.) достигается за счет следующих основных факторов: • интероперабельность и межъязыковое взаимодействие; • многоуровневая, гибкая и надежная политика безопасности; • интеграция с технологией веб-сервисов; • упрощение процедуры разворачивания и использования создаваемого программного обеспечения. Несмотря на некоторую незавершенность решения для широкого коммерческого использования в силу концептуальной новизны и грандиозности проекта, подход .NET, безусловно, оказывает значительное влияние на коммерческую индустрию программирования в целом и способствует радикальному совершенствованию отрасли в ходе рыночной конкуренции.
Современные языки программирования и .NET: II семестр Лекция 2: Платформа .NET и ее применение для ООП
Библиография 1. 2. 3. 4. 5.
http://msdn.microsoft.com/net Nathan A. .NET and COM: The Complete Interoperability Guide. Sams, 2002, 1608 pp. Box D. Essential .NET, Vol.1: The Common Language Runtime. Addison Wesley, 2002, 432 pp. Grimes F. Microsoft .NET for Programmers. Manning Publications, 2002, 386 pp. J. Richter. Applied Microsoft .NET Framework Programming. Microsoft Press, 2002, 556 pp.
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду К сожалению, в рамках одной лекции невозможно представить такой многоаспектный подход как .NET в полном объеме. Для более детального ознакомления с последними достижениями и проблемами в ходе развития подхода рекомендуется следующий список литературы: 1.http://msdn.microsoft.com/net 2. Nathan A. .NET and COM: The Complete Interoperability Guide. Sams, 2002, 1608 pp. 3. Box D. Essential .NET, Vol.1: The Common Language Runtime. Addison Wesley, 2002, 432 pp. 4. Grimes F. Microsoft .NET for Programmers. Manning Publications, 2002, 386 pp. 5. Richter J. Applied Microsoft .NET Framework Programming. Microsoft Press, 2002, 556 pp. Кратко остановимся на источниках. Последние сведения о .NET из первых рук доступны с Интернет-ресурса [1]. Работы [2,3] посвящены интероперабельности; в работах [4,5] рассмотрены проблемы практической реализации программного обеспечения согласно подходу .NET.
Основные понятия языка программирования C#
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В данной лекции будут рассмотрены вопросы, относящиеся к понятийному аппарату, истории развития, выразительным возможностям синтаксиса и особенностям реализации языка программирования C# в сравнении с другими объектно-ориентированными языками программирования.
Современные языки программирования и .NET: II семестр Лекция 3: Основные понятия языка программирования C#
Содержание лекции 1. 2. 3. 4. 5. 6. 7. 8.
Эволюция языка программирования C# Место C# в семействе языков программирования Сопоставление языка C# с другими языками ООП (C++ и Java) Основные возможности языка программирования C# Структура программы на языке C# Синтаксис основных конструкций языка C# Достоинства и недостатки языка C# Библиография © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Коротко о содержании лекции. Прежде всего, необходимо напомнить слушателям динамику эволюционного процесса, который привел к появлению языка программирования C#. Далее, естественно сосредоточиться на функциональных особенностях и расширенных (по сравнению с традиционными языками ООП) возможностях этого языка программирования. Таким образом, будет определено место языка программирования C# в семействе подобных ему языков и общей классификации. Отметим, что исследование языка программирования C# будет производиться в сравнении с аналогами, прежде всего, с такими хорошо известными языками программирования, как Java и Visual Basic. Первый представляет собой потенциально независимое от программной платформы (и операционной системы) средство создания программного обеспечения, а второй – относительно простой в освоении объектно-ориентированный язык программирования производства компании Microsoft. Исследование основных выразительных возможностей синтаксиса языка программирования C# будет иллюстрироваться примерами фрагментов программ с необходимыми комментариями. Особое внимание будет уделено общей структуре программы на языке C#. Сравнительный анализ языка C# в семействе современных языков ООП завершится выводами относительно преимуществ и недостатков принципов реализации и синтаксиса языка. Наконец, для желающих глубже исследовать предмет будут представлены ссылки на важнейшие работы теоретического и практического плана по теме лекции.
Современные языки программирования и .NET: II семестр Лекция 3: Основные понятия языка программирования C#
История развития языка программирования C# Язык B: 1963, К.Томпсон (Ken Thompson, MIT) • Подобен языку PL/I, однако менее громоздок, применялся для разработки операционной системы UNIX Язык C: 1972, Д.Ритчи, К.Томпсон (Dennis Ritchie & Ken Thompson, AT&T Bell Telephone Laboratories) • Язык B, расширенный типами, структурами и новыми операциями Язык С++: 1984, Б.Страуструп (Bjarne Stroustrup , Bell Labs) • Введены классы как объекты данных • Название C++ предложил Р.Маскитти (Rics Mascitti, Bell Labs) Язык C#:2000, Microsoft • «Всякая сущность есть объект»; компонентный; безопасный © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Прежде, чем перейти непосредственно к исследованию конструктивных особенностей языка программирования C#, рассмотрим историю его развития. Исторические корни возникновения основной ветви языков программирования, которая привела к появлению C#, ведут к 60-м г.г., а именно, ко времени возникновения языка B. Последний является типичным представителем ранних императивных языков программирования. Язык B был придуман в 1963 году творческим коллективом, основным создателем языка принято считать К. Томпсона из Технологического университета Массачусетса (Ken Thompson, MIT). Основной целью разработки языка была реализация операционной системы UNIX. Уже существовавший язык PL/I, применявшийся в то время для мейнфреймов производства компании IBM, был достаточно громоздким и менее подходил для поставленной задачи, чем новое, оригинальное решение ученых-практиков. Следующим шагом в «алфавите» языков программирования, ведущем к языку C#, стал язык C, который был изобретен на основе языка B в 1972 году. Авторами нового языка программирования стали уже известный нам Кен Томпсон, а также Д. Ритчи (Dennis Ritchie), которые работали в исследовательской лаборатории компании AT&T (AT&T Bell Telephone Laboratories). В варианте C язык B расширился за счет явного использования типов (напомним, что языки и теории с типами имеют существенные преимущества перед бестиповыми аналогами), структур и ряда новых операций. Дальнейшее развитие языка происходило в стенах той же организации. И снова примерно через 10 лет, в 1984 году, Б. Страуструп (Bjarne Stroustrup, Bell Labs) выступил с проектом языка С++ - ООП-расширения языка C, в котором вводится понятие класса как объекта данных. Заметим, что название C++ для нового языка предложил Р.Маскитти (Rics Mascitti, Bell Labs), представляющий ту же организацию. Наконец, уже в 2000 году, более чем через 15 лет, корпорация Microsoft выпустила в свет C++ нового поколения под названием C# («Си шарп»), основным постулатом которого является высказывание: «всякая сущность есть объект». Язык основан на строгой
компонентной архитектуре и реализует передовые механизмы обеспечения безопасности кода.
Современные языки программирования и .NET: II семестр Лекция 3: Основные понятия языка программирования C#
Основные возможности C# Подобен языкам Java, C++ и VB, однако является компонентноориентированным и более безопасным Добавлен ряд новых черт (делегаты, индексаторы, механизм (un)boxing и др.) Сходство с Java: Сходство с C++: • объектно-ориентированный (единственное наследование) • интерфейсы • исключения • нити (threads) • пространства имен • сильная (строгая) типизация • сборка мусора • отражение (reflection) • динамическая загрузка кода
• «перегруженные» операторы • арифметические операции с плавающей точкой относятся к небезопасному коду • некоторые особенности синтаксиса
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Как уже отмечалось в ходе лекции, язык программирования C# вобрал лучшие черты целого ряда своих предшественников. Кроме упомянутой ранее ветви языков B-C-C++, необходимо указать еще несколько знаковых для настоящего времени языков программирования, а именно, Java и Visual Basic. Несмотря на весьма существенные различия между компонентной объектной моделью COM (основного стандарта Microsoft для компонентного проектирования и реализации программного обеспечения) и моделью Java Beans, базовым стандарт Sun Microsystems для компонент (зависимой от языка реализации), язык программирования C# имеет довольно много общего с языком Java. Естественно, немало черт язык программирования C# унаследовал и от своего предшественника, созданного корпорацией Microsoft, языка Visual Basic. Как уже отмечалось, язык программирования C# основан на строгой компонентной архитектуре и реализует передовые механизмы обеспечения безопасности кода. Перечислим наиболее характерные черты сходства языков программирования C# и Java. Прежде всего, оба эти языка относятся к категории объектно-ориентированных и предполагают единственность наследования. Другими важными особенностями, которые сближают языки программирования C# и Java, являются механизмы интерфейсов, обработки исключительных ситуаций, нитей (threads). Сборка мусора и пространства имен реализованы в этих двух языках сходным образом. Оба языка программирования характеризуются сильной (строгой) типизацией и динамической загрузкой кода при выполнении программы. От своего прямого предшественника, языка программирования C++, языком C# унаследованы следующие механизмы: «перегруженные» операторы, небезопасные арифметические операции с плавающей точкой, а также ряд других особенностей синтаксиса.
Современные языки программирования и .NET: II семестр Лекция 3: Основные понятия языка программирования C#
Краткий список основных возможностей C# • Компонентноориентированное программирование - Свойства - События • Унифицированная система типизации (UTS) • Делегаты (Delegates)
• Индексаторы (Indexers) • Перегруженные операторы • Оператор foreach • Механизмы boxing и unboxing • Атрибуты • Прямоугольные массивы
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Несмотря на то, что целый ряд конструктивных синтаксических механизмов и особенностей реализации унаследован языком программирования C# от прародителей (C++, Visual Basic и Java), возможности этого нового языка программирования не ограничиваются суммой возможностей его исторических предшественников. На данном этапе ограничимся перечислением основных возможностей, которыми характеризуется язык программирования C#. К числу принципиально важных решений, которые реализованы корпорацией Microsoft в языке программирования C#, можно отнести следующие: компонентно-ориентированный подход к программированию (который характерен и для идеологии Microsoft .NET в целом); свойства как средство инкапсуляции данных (характерно также в целом для ООП); обработка событий (имеются расширения, в том числе в части обработки исключений, в частности, оператор try); унифицированная система типизации (соответствует идеологии Microsoft .NET в целом); делегаты (delegate – развитие указателя на функцию в языках C и C++); индексаторы (indexer – операторы индекса для обращения к элементам классаконтейнера); перегруженные операторы (развитие ООП); оператор foreach (обработка всех элементов классов-коллекций, аналог Visual Basic); механизмы boxing и unboxing для преобразования типов; атрибуты (средство оперирования метаданными в COM-модели); прямоугольные массивы (набор элементов с доступом по номеру индекса и одинаковым количеством столбцов и строк). Особенности языка программирования C#, которые в большей степени отвечают целям настоящего учебного курса, будут рассмотрены более подробно в рамках настоящей лекции, другие – в течение последующих лекций.
Современные языки программирования и .NET: II семестр Лекция 3: Основные понятия языка программирования C#
Структура программы на языке C# C#-программа
FileName1.cs
FileName2.cs
namespace A {...}
namespace B {...}
class X {...}
class Y {...}
FileName3.cs
namespace C {...}
class Z {...}
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Прежде всего, рассмотрим обобщенную структуру программы на языке программирования C#. Проиллюстрируем структуру программы показательным примером (см. схему). Заметим, что программа на C# может состоять как из одного, так и из нескольких файлов, содержащих исходный текст на языке программирования C#. Каждый такой файл имеет расширение .CS (в нашем примере файлы названы FileName1.cs, FileName2.cs и FileName1.cs). Любой файл с исходным текстом на языке программирования C# может как содержать пространства имен, так и не содержать их (в нашем примере файл названы FileName2.cs содержит три пространства имен (A, B и C), а FileName1.cs и FileName3.cs не содержат пространств имен). Наконец, каждое пространство имен может как содержать описание (одного или нескольких) классов, так и не содержать их (в нашем примере пространство имен B содержит три описания трех классов (X, Y и Z), а пространство имен А и С не содержат ни одного описания классов).
Современные языки программирования и .NET: II семестр Лекция 3: Основные понятия языка программирования C#
Сопоставление ссылочных типов и типов-значений Типы-значения
Ссылочные типы
Переменная содержит Переменная хранится Значение по умолчанию Оператор присваивания
значение в стеке 0, false, '\0' копирует значение
ссылку на значение в куче null копирует ссылку
Пример
int i = 25; int j = i;
string s = “John"; string s1 = s;
i
25
s
j
25
s1
John
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Ранее в ходе изложения настоящего курса уже обсуждались механизмы boxing и unboxing, реализованные в различных средах разработки программного обеспечения Microsoft .NET. Напомним, что эти механизмы используются для преобразования типов выражений языков программирования из ссылочных в типы-значения и обратно. Рассмотрим более подробно реализацию двух основных семейств типов данных, а именно, ссылочных типов и типов-значений, применительно к языку программирования C#. Для определенности рассмотрим случай одного из простейших объектов языка программирования C#, а именно, переменной. В соответствии с названиями, переменная в случае использования типов-значений содержит собственно значение, а при использовании ссылочных типов – не само значение, а лишь ссылку (указатель) на него. Местом хранения переменной, определенной как тип-значение, является стек, а определенной как ссылочный тип – «куча» (последнее необходимо для динамического выделения и освобождения памяти для хранения переменной произвольным образом). Значением, которым переменная инициализируется по умолчанию (необходимость выполнения этого требования диктуется идеологией безопасности Microsoft .NET) в случае определения посредством типа-значения является 0 (для целого или вещественного типа данных), false (для логического типа данных), '\0' (для строкового типа данных), а в случае определения посредством ссылочного типа – значение пустой ссылки null. При выполнении оператора присваивания в случае переменной-значения копируется значение, а в случае переменной-ссылки – ссылка. Приведенный далее пример иллюстрирует различия в реализации типов-ссылок и значений.
Современные языки программирования и .NET: II семестр Лекция 3: Основные понятия языка программирования C#
Элементарные типы языка С# (в сопоставлении с языком SML) C# sbyte byte short ushort long float double decimal bool char
CTS System.SByte System.Byte System.Int16 System.UInt16 System.Int64 System.Single System.Double System.Decimal System.Boolean System.Char
SML --byte int word --real ----bool char
Диапазон -128 .. 127 0 .. 255 -32768 .. 32767 0 .. 65535 -263 .. 263-1 ±1.5E-45 .. ±3.4E38 (32 Bit) ±5E-324 .. ±1.7E308 (64 Bit) ±1E-28 .. ±7.9E28 (128 Bit) true, false Символ (в коде unicode)
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Перейдем к более подробному рассмотрению основных типов, входящих в состав Common Type System (CTS) Microsoft .NET. При этом прикладное исследование языков программирования произведем в форме сопоставления отображений фрагментов систем типизации языков программирования SML и C# в систему типов CTS. При этом для обеспечения большей наглядности сопоставления сведем отображения в следующую таблицу: C# sbyte byte short ushort long float double decimal bool char
CTS System.SByte System.Byte System.Int16 System.UInt16 System.Int64 System.Single System.Double System.Decimal System.Boolean System.Char
SML --byte int word --real ----bool char
Диапазон -128 .. 127 0 .. 255 -32768 .. 32767 0 .. 65535 -263 .. 263-1 ±1.5E-45 .. ±3.4E38 (32 Bit) ±5E-324 .. ±1.7E308 (64 Bit) ±1E-28 .. ±7.9E28 (128 Bit) true, false Символ (в коде unicode)
Даже из предварительного анализа таблицы видно, что система типизации языка программирования С# значительно богаче по сравнению с языком программирования SML. Можно заметить, что всякому типу языка программирования SML соответствует некоторый тип языка программирования С#, и их названия зачастую совпадают или являются подобными друг другу. Наконец, отметим, что все без исключения типы обоих языков программирования однозначно отображаются в систему типизации Microsoft .NET, верхним иерархическим элементом которой является пространство имен System.
Современные языки программирования и .NET: II семестр Лекция 3: Основные понятия языка программирования C#
Оператор перечисления Список поименованных констант Описание (непосредственно в пространстве имен): enum Color {red, blue, green}
// значения: 0, 1, 2
enum Access {personal=1, group=2, all=4} enum Access1 : byte {personal=1, group=2, all=4}
Применение: Color c = Color.blue; // для перечислимых констант должно быть указано полное имя Access a = Access.personal | Access.group; if ((Access.personal & a) != 0) Console.WriteLine("access granted"); © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Кроме понятия переменной, которое уже было исследовано ранее в связи с типамизначениями и ссылочными типами, интересно провести исследование объектов-констант в языке программирования C#. Напомним, что константные объекты в комбинаторной логике можно моделировать посредством комбинатора-канцелятора К с характеристикой K x y = x. Рассмотрим ряд примеров описания констант посредством оператора перечисления (заметим, что применяемый в C# способ описания констант изначально ориентирован на написание безопасного кода, поскольку содержит обязательную инициализацию). Оператор перечисления enum языка C# представляет собой список поименованных констант. Описание производится непосредственно в пространстве имен с областью видимости, которую необходимо обеспечить для константы: enum Color {red, blue, green} enum Access {personal=1, group=2, all=4} enum Access1 : byte {personal=1, group=2, all=4} Пример использования константы после ее описания имеет следующий вид: Color c = Color.blue; Заметим, что для перечислимых констант должно быть указано полное имя : Access a = Access.personal | Access.group; if((Access.personal & a) != 0) Console.WriteLine("access granted");
Современные языки программирования и .NET: II семестр Лекция 3: Основные понятия языка программирования C#
Операторы typeof и sizeof в языке C# typeof • Возвращает для данного типа дескриптор типа Дескриптор типа для объекта o возвращается операцией o.GetType(). Type t = typeof(int); Console.WriteLine(t.Name); // Î тип данного выражения: Int32 sizeof • Возвращает размер элемента данного типа (в байтах). • Применим только к типам-значениям. • Используется только в блоках небезопасного кода (размер структур может изменяться в зависимости от среды реализации). Необходима компиляция посредством команды csc /unsafe xxx.cs unsafe { Console.WriteLine(sizeof(int)); Console.WriteLine(sizeof(MyEnumType)); Console.WriteLine(sizeof(MyStructType)); } © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Подобно языку программирования SML в языке C# реализована возможность определения типа для того или иного языкового объекта. Для реализации этой возможности используется оператор typeof, который для любого заданного типа возвращает дескриптор этого типа. Заметим, что дескриптор типа для объекта o возвращается операцией o.GetType(). Рассмотрим пример, иллюстрирующий использование оператора typeof: Type t = typeof(int); Console.WriteLine(t.Name); При выполнении данного примера тип рассматриваемого выражения будет определен системой как Int32, что вполне соответствует данным из сравнительной таблицы отображения типов языковых объектов C# и SML в систему типизации CTS Microsoft .NET. Еще одной практически важной конструкцией C#, оперирующей типами, является оператор sizeof, который возвращает размер элемента данного типа (в байтах). Данный оператор применим только к типам-значениям и используется лишь в блоках небезопасного кода (т.к. размер структур может изменяться в зависимости от среды реализации); необходима компиляция кода командой csc /unsafe xxx.cs. Приведем пример использования оператора sizeof (заметим, что блоки небезопасного C#-кода выделяются посредством ключевого слова unsafe): unsafe { Console.WriteLine(sizeof(int)); Console.WriteLine(sizeof(MyEnumType)); Console.WriteLine(sizeof(MyStructType)); }
Современные языки программирования и .NET: II семестр Лекция 3: Основные понятия языка программирования C#
Оператор struct языка C# Описание: struct Point { public int x, y; // поля public Point (int x, int y) { this.x = x; this.y = y; } // конструктор public void MoveTo (int a,int b) {x=a; y=b;} // методы }
Применение: Point p = new Point(3, 4); // конструктор инициализирует объекты стека p.MoveTo(10, 20); // вызов метода © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Одним из важнейших видов основных объектов языка программирования C# являются структуры (аналоги структур имеются и языке SML; в языках функционального программирования с примитивной системой типизации аналогами структур могут служить списки). Рассмотрим пример описания структуры Point, моделирующей точку на плоскости: struct Point { public int x, y; public Point (int x, int y) { this.x = x; this.y = y; } public void MoveTo (int a,int b) {x=a; y=b;} } Заметим, что координаты точки x, y (в простейшем случае целочисленные), которые используются для определения ее положения, являются атрибутами объекта или полями структуры. Операция Point является функцией инициализации объекта и называется конструктором. Заметим, что унаследованный от C++ указатель this является ссылкой на текущий объект. Наконец, операция (или, иначе, метод MoveTo) изменяет текущее местоположение точки на пару целочисленных координат (a,b). Для использования объекта-структуры необходимо проинициализировать объектзначение в стеке посредством конструктора. Затем можно вызвать метод MoveTo: Point p = new Point(3, 4); p.MoveTo(10, 20);
Современные языки программирования и .NET: II семестр Лекция 3: Основные понятия языка программирования C#
Область описания
Часть программы, к которой относится описание Объекты языка могут быть описаны: • в пространстве имен( классы, интерфейсы, структуры, перечисления, делегаты); • в классе, интерфейсе, структуре (поля, методы, свойства, события, индексаторы и т.д.); • в перечислении (перечисляемые константы); в блоке(локальные переменные) Контекстные соглашения: - недопустимо двукратное описание в пределах данной области описания; - последовательность описаний произвольна; - исключение: локальные переменные необходимо описать до использования Соглашения об областях видимости: - идентификатор виден лишь из своей области описания; - область видимости можно изменить посредством модификаторов (private, © Учебный Центр безопасности информационных технологий Microsoft protected). Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Мы познакомились с одним из основных видов объектов языка программирования C#, а именно, со структурами. В предыдущем примере фрагмента программы на C# дважды фигурировал идентификатор Point. В связи с этим уместно вспомнить о проблеме коллизий переменных и возможных путях ее преодоления (в предыдущей части курса для решения этой задачи использовался формализм, известный под названием чисел де Брейна). В языке программирования SML переменные могут быть описаны либо глобально (это описание распространяется на весь текст программы), либо локально в теле функции (это описание распространяется на весь текст функции). В языке программирования C#, где объекты имеют существенно более сложную структуру, вводится понятие области описания, под которой понимают фрагмент программы, к которому относится данное описание. Объекты языка программирования C# могут быть описаны: • в пространстве имен (классы, интерфейсы, структуры, перечисления, делегаты); • в классе, интерфейсе, структуре (поля, методы, свойства, события, индексаторы и т.д.); • в перечислении (перечисляемые константы); • в блоке (локальные переменные). При этом принимаются следующие контекстные соглашения. Во-первых, недопустимо двукратное описание в пределах данной области описания. Во-вторых, последовательность описаний является произвольной. Исключение составляют локальные переменные, которые необходимо описать до первого использования. Кроме того, принимаются следующие соглашения об областях видимости. Во-первых, любой идентификатор виден лишь из своей области описания. Во-вторых, область видимости можно изменить посредством модификаторов (private,protected).
Современные языки программирования и .NET: II семестр Лекция 3: Основные понятия языка программирования C#
Файл X.cs
Пространства имен Файл Y.cs
namespace A { ... class C ... ... interface I... ... struct S... ... enum e ... ... delegate d ...
}
namespace B { // полное имя: A.B ... }
namespace A { ... namespace B {...} namespace C {...} } •
Пространства имен из разных файлов, имеющие один и тот же идентификатор, составляют единую область описания. • Вложенные пространства имен составляют собственную область описания.
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В процессе изучения структуры программы на языке C# неоднократно употреблялся термин «пространство имен». В силу существования более значимых понятий объектноориентированного подхода к программированию в целом и языка программирования C# в частности приводилось лишь общее обсуждение данного термина. Рассмотрим пространства имен языка программирования C# более подробно. Рассмотрим два файла X.cs и Y.cs, содержащих исходные тексты программ на языке C#. Файл X.cs namespace A { ... class C ... ... interface I... ... struct S... ... enum e ... ... delegate d ... namespace B { // полное имя: A.B ... } }
Файл Y.cs namespace A { ... namespace B {...} namespace C {...} }
Заметим, что в файле X.cs содержатся описания пространств имен A и B, а в файле Y.cs – A, B и C, причем в обоих случаях последующие пространства имен вложены в A. При обращении к вложенному пространству имен нужно указывать его полное имя, например, A.B. Необходимо отметить, что пространства имен из разных файлов, имеющие один и тот же идентификатор, составляют единую область описания. Заметим также, что вложенные пространства имен составляют собственную (отдельную) область описания.
Современные языки программирования и .NET: II семестр Лекция 3: Основные понятия языка программирования C#
Оператор блока в C# В С# существуют различные виды блоков: void foo (int x) { // блок методов ... локальные переменные ... { // вложенный блок ... локальные переменные ... } for (int i = 0; ...) { // блок структурированных операторов ... локальные переменные ... } } © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Несмотря на то, что язык программирования C# реализует объектно-ориентированный подход к программированию, целый ряд характерных особенностей унаследован им еще от ранних процедурных прародителей, прежде всего, языка C. Одной из черт, унаследованных C# от языка программирования C, является блок операторов – последовательность операторов разделенных символами «;», ограниченная фигурными скобками «{» и «}». Аналогом оператора блока в языках функционального программирования является функция. В язык программирования С# выделяют различные виды блоков, которые наглядно демонстрируются следующим примером: void foo (int x) { // блок методов ... локальные переменные ... { // вложенный блок ... локальные переменные ... } for (int i = 0; ...) { // блок структурированных операторов ... локальные переменные ... } } Как видно из примера, блоки объединяют (структурированные) операторы и методы. Допускается использование блоков, вложенных один в другой. Для удобочитаемости текста программы глубину вложенности блока лучше сохранять в зависимости от величины табуляции.
Современные языки программирования и .NET: II семестр Лекция 3: Основные понятия языка программирования C#
Описание локальной переменной в языке C# void foo(int a) { int b; if (...) { int b; // ошибка: переменная b уже описана в другом блоке int c; // пока все в порядке, однако ... int d; ... } else { int a; // ошибка: переменная а уже описана во внешнем блоке int d; // конфликтов с переменной d из предыдущего блока нет } for (int i=0;...){...} for (int i=0;...){...} // ok: нет конфликтов с переменной i из //предыдущего цикла int c; // ошибка: c уже описана в данном пространстве имен } © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Рассмотрим подробнее особенности описания локальных программирования C# на следующем примере программы: void foo(int a) { int b; if (...) { int b; int c; int d; } else int int } for for
{ a; d;
переменных
в
языке
// ошибка: переменная b уже описана в другом блоке // пока все в порядке, однако ... ... // ошибка: переменная а уже описана во внешнем блоке // конфликтов с переменной d из предыдущего блока нет
(int i=0;...){...} (int i=0;...){...} // все в порядке: нет конфликтов с // переменной i из предыдущего цикла int c; // ошибка: c уже описана в данном пространстве имен
} Рассмотрим функцию foo с одним целочисленным аргументом a, которая не возвращает значения. Как видно из данного примера, коллизии описаний переменных возникают в случаях множественного описания внутри одного и того же блока или пространства имен. Заметим попутно, что условный оператор if…else языка C# весьма схож с подобным оператором языка SML, а оператор for является оператором цикла.
Современные языки программирования и .NET: II семестр Лекция 3: Основные понятия языка программирования C#
Пример использования других пространств имен Color.cs namespace Util { public enum Color {...} }
Figures.cs namespace Util.Figures { public class Rect {...} public class Circle {...} }
Triangle.cs namespace Util.Figures { public class Triangle {...} }
using Util.Figures; class Test { Rect r; // без указания полного имени //(т.к. используем Util.Figures) Triangle t; Util.Color c; // c указанием полного имени } © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Рассмотрим более сложный пример использования пространств имен в языке программирования C#. Пусть программный проект на языке программирования C# содержит три файла с описаниями структур данных, оформленными в виде отдельных пространств имен: Color.cs namespace Util { public enum Color {...} }
Figures.cs namespace Util.Figures { public class Rect {...} public class Circle {...} }
Triangle.cs namespace Util.Figures { public class Triangle {...} }
В данном случае при использовании полного имени пространства имен (Util.Figures) возможно обойтись без конкретизации классов (Rect), описанных внутри этого пространства имен. Однако, в случае обращения к классам вне данного пространства имен необходимо использовать полное квалификационное имя объекта (Util.Color c): using Util.Figures; class Test { Rect r; // без указания полного имени //(т.к. используем Util.Figures) Triangle t; Util.Color c; // c указанием полного имени
Современные языки программирования и .NET: II семестр Лекция 3: Основные понятия языка программирования C#
Преимущества языка программирования C# 1. 2. 3. 4. 5. 6. 7.
Подлинная объектная ориентированность (всякая языковая сущность претендует на то, чтобы быть объектом) Компонентно-ориентированное программирование Безопасный (по сравнению с языками C и C++) код Унифицированная система типизации Поддержка событийно-ориентированного программирования «Родной» язык для создания приложений в среде .NET Объединение лучших идей современных языков программирования: Java, C++, Visual Basic и др. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Проанализировав основные особенности языка программирования C#, а также исследовав структуру и принципы построения программ на этом языке, сформулируем наиболее заметные преимущества изучаемого языка программирования. Прежде всего, необходимо отметить то обстоятельство, что язык программирования C# претендует на подлинную объектную ориентированность (а всякая языковая сущность претендует на то, чтобы быть объектом). Кроме того, язык программирования C# призван практически реализовать компонентноориентированный подход к программированию, который способствует меньшей машинно-архитектурной зависимости результирующего программного кода, большей гибкости, переносимости и легкости повторного использования (фрагментов) программ. Принципиально важным отличием от предшественников является изначальная ориентация на безопасность кода (что особенно заметно в сравнении с языками C и C++). Унифицированная, максимально близкая по масштабу и гибкости к Common Type System, принятой в Microsoft .NET, система типизации является важным преимуществом языка C#. Расширенная поддержка событийно-ориентированного программирования отличает язык программирования C# от целого ряда предшественников.
выгодно
Язык программирования C# является «родным» для создания приложений в среде Microsoft .NET, поскольку наиболее тесно и эффективно интегрирован с ней. Объединение лучших идей современных языков программирования (Java, C++, Visual Basic и др.) делает язык C# не просто суммой их достоинств, а языком программирования нового поколения.
Современные языки программирования и .NET: II семестр Лекция 3: Основные понятия языка программирования C#
Недостатки языка программирования C# 1. 2. 3. 4. 5.
Довольно сложный синтаксис (75% из Java, 10% из C++, 5% из Visual Basic) Относительно немного свежих концептуальных идей (вероятно, менее чем 10% конструкций языка) Утверждение о чистой объектности C# спорно (проф. K. Гуткнехт (K.Gutknecht, ETH, Цюрих), предложил «активную» объектную модель для языка Zonnon) Относительно невысокая производительность (~ в 100 раз медленнее, чем язык C, хотя и сравнимая с языком Java) Не кросс-платформенный язык (в смысле ОС, хотя определенный прогресс в этом направлении очевиден) © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Несмотря на значительное количество принципиальных преимуществ по сравнению с существующими аналогами, язык программирования C# не лишен и отдельных недостатков, которые, весьма вероятно, носят субъективный, локальный, временный характер. Прежде всего, необходимо отметить то обстоятельство, что язык программирования C# имеет довольно сложный синтаксис (можно утверждать, что примерно 75% его синтаксических возможностей аналогичны языку программирования Java, 10% – подобны языку программирования C++, а 5% – заимствованы из языка программирования Visual Basic). Объем действительно свежих концептуальных идей в языке C# относительно невысок (по мнению некоторых исследователей, он, составляет около 10% от общего объема конструкций языка). Утверждение том, что язык программирования C# является чисто объектным, допускает неоднозначную интерпретацию. Так, например, профессор K. Гуткнехт (K.Gutknecht) из института ETH (г. Цюрих, Швейцария) предложил альтернативную (так называемую «активную») объектную модель для разработанного им языка программирования Zonnon. До настоящего времени компилятор и среда разработки программного обеспечения, поддерживающие язык C#, обладают относительно невысокой производительностью (т.е. код программы на языке C# компилируется и выполняется примерно в 100 раз медленнее, чем тот же код на языке C). Справедливости ради нужно отметить, что производительность программ на C# вполне сравнима с тем же показателем для языка Java. На сегодня программы, написанные на языке C#, не работоспособны под управлением альтернативных операционных систем (ведутся работы по обеспечению совместимости с операционными системами Linux и FreeBSD семейства UNIX).
Современные языки программирования и .NET: II семестр Лекция 3: Основные понятия языка программирования C#
Библиография 1. 2. 3. 4. 5.
Visual C#. NET Step by Step, Microsoft Press, 2003. ISBN: 0-7356-1909-3 Liberty J. Programming C#, 3d edition. O'Reilly & Associates, 2003, 710 pages. ISBN: 0596004893 Pratt T.W., Zelkovitz M.V. Programming languages, design and implementation (4th ed.).- Prentice Hall, 2000 Appleby D., VandeKopple J.J. Programming languages, paradigm and practice (2nd ed.).- McGraw-Hill, 1997 Gilmore S. Programming in Standard ML ’97: a tutorial introduction. http:/www.dcs.ed.ac.uk/home/stg © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду К сожалению, в рамках времени, отведенных на одну лекцию, можно лишь в общих чертах охарактеризовать концепцию и возможности такого объемного и многоаспектного языка программирования как C#. Для более детального ознакомления с особенностями, достижениями и проблемами в области концептуальных инноваций, синтаксиса и расширенных возможностей языка программирования C# рекомендуется следующий список литературы: 1.Visual C#. NET Step by Step, Microsoft Press, 2003. ISBN: 0-7356-1909-3. 2.Liberty J. Programming C#, 3d edition. O'Reilly & Associates, 2003, 710 pages. ISBN: 0596004893. 3.Pratt T.W., Zelkovitz M.V. Programming languages, design and implementation (4th ed.).Prentice Hall, 2000. 4.Appleby D., VandeKopple J.J. Programming languages, paradigm and practice (2nd ed.).McGraw-Hill, 1997. 5.Gilmore S. Programming in http:/www.dcs.ed.ac.uk/home/stg.
Standard
ML
’97:
a
tutorial
introduction.
Кратко остановимся на источниках. Работа [1] является энциклопедией проектирования и реализации программного обеспечения на языке программирования C# под управлением Microsoft Visual Studio .NET. В работе [2] рассматриваются вопросы, связанные с разработкой программ на языке C#. Работы [3-4] посвящены теории и практике программирования на различных языках и в рамках различных подходов. Работа [1] содержит развернутое описание синтаксиса языка функционального программирования SML.
Семантика основных конструкций языка C#
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В данной лекции будут рассмотрены вопросы, относящиеся к понятийному аппарату, истории развития, существующим подходам и выразительным возможностям семантического представления формальных теорий и языков программирования. При этом существенное внимание будет уделено сопоставлению семантики языков объектноориентированного и функционального программирования. В качестве примеров языков программирования будут выступать уже знакомый нам по предыдущему курсу язык SML и изучаемый нами язык C#.
Современные языки программирования и .NET: II семестр Лекция 4: Семантика основных конструкций языка C#
Содержание лекции 1. 2. 3. 4. 5. 6. 7. 8.
Понятие семантики в математике и программировании Типы семантик. Возможные подходы к моделированию семантики Средства формализации семантики Теория вычислений Д.Скотта. Конструкторы доменов Синтаксис основных конструкций языка C# Денотационная семантика основных конструкций C# Сходства семантики фрагментов языков SML и C# Библиография © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Коротко о содержании лекции. В ходе лекции будут рассмотрены важнейшие научные исследования, относящиеся к эволюции подходов к математическому моделированию семантического представления формальных теорий и языков программирования. При этом будет предпринята попытка классификации существующих видов семантики. Далее будет представлено неформальное введение в наиболее адекватный целям данного курса и достаточно широко распространенный на сегодня подход к семантике, а именно, так называемый денотационный подход. Теоретические рассуждения о семантике в формальных теориях (на примере теории вычислений Д.Скотта) будут проиллюстрированы представлением денотационной семантики подмножества языка программирования C#, ограниченного наиболее важными, основополагающими конструкциями. При этом существенное внимание будет также уделено сопоставлению и сравнительному анализу синтаксического и семантического аспектов наиболее важных с точки зрения программирования классов конструкций языка программирования C#. Другим аспектом сравнительного анализа будет сопоставление семантик подмножеств языков программирования SML и C# на основе общей теоретической формализации. Лекция завершится обзором литературы для более глубокого исследования материала.
Современные языки программирования и .NET: II семестр Лекция 4: Семантика основных конструкций языка C#
Важнейшие работы в области семантики (1) 1960-е – Х. Барендрегт (H. Barendregt) описал семантику ламбда-исчисления 1969 – Д. Скотт (Dana S. Scott) предложил использовать домены (особый вид множеств) для формализации денотационной семантики как функции вычисления значения синтаксически корректных конструкций языка 1979 – М. Гордон (Michael J.C. Gordon) исследовал денотационную семантику языков программирования © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Кратко остановимся на наиболее значительных (с точки зрения данного курса) этапах эволюции теории и практики семантического анализа языков программирования. В 60-х г.г. Х. Барендрегтом (H. Barendregt) была детально описана семантика ламбдаисчисления – математической формализации, поддерживающей языки функционального программирования. Позднее, в конце 60-х г.г., Д. Скоттом (Dana S. Scott) было предложено использовать для формализации семантики математических теорий так называемые домены (пока будем неформально понимать их как особый вид множеств). При этом на основе доменов Д. Скоттом был предложен так называемый денотационный подход к семантике. Такой подход предполагает анализ синтаксически корректных конструкций языка (или, иначе, денотатов) с точки зрения возможности вычисления их значений посредством специализированных функций. Далее, в 70-х г.г., М. Гордоном (Michael J.C. Gordon) был исследован аппарат денотационной семантики применительно к языкам функционального программирования и сделан вывод об адекватности и практической эффективности применения этого подхода для решения поставленной задачи.
Современные языки программирования и .NET: II семестр Лекция 4: Семантика основных конструкций языка C#
Важнейшие работы в области семантики (2) 1964 – П. Лендин (Peter J. Landin) разработал семантику модели языка программирования в форме абстрактной машины на состояниях 1969 – Ч. Хоар (Charles A.R. Hoare) создал аксиоматический метод, моделирующий операторы языка программирования 1960-е – Р. Флойд (Robert W. Floyd) создал метод индуктивных утверждений для формализации семантики протекания информации в программе (графическая иллюстрация - блок-схемы) © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Параллельным направлением изучения семантики был подход, исследовавший изменения, которые происходили в процессе работы программы на основе отслеживания смены состояний. Одним из практических результатов работ в этом направлении стала разработка П. Лендином (Peter J. Landin) семантики модели языка программирования в форме абстрактной машины, существенно использовавшей понятие состояния. Альтернативный подход к формализации семантики (который был осуществлен в рамках исследования так называемой операционной семантики языков программирования) привел к созданию Ч. Хоаром (Charles A.R. Hoare) аксиоматического метода, моделирующего отношения и причинно-следственные связи, возникающие между операторами языка программирования. Развитие операционной семантики языков программирования привело Р. Флойда (Robert W. Floyd) к созданию так называемого метода индуктивных утверждений, который использовался для формализации семантики протекания информации в программе. При этом существенным преимуществом предложенного Р. Флойдом метода стала возможность интуитивно прозрачной и наглядной графической иллюстрации, основанной на блок-схемах, формализующих последовательность протекания информации.
Современные языки программирования и .NET: II семестр Лекция 4: Семантика основных конструкций языка C#
Общие сведения о семантике (1) Семантикой называется интерпретация (т.е. смысловое значение) абстрактного синтаксиса (т.е. множества допустимых конструкций языка), выраженное в терминах той или иной математически строгой модели.
1) 2)
Основные подходы к семантике: ориентированные на компиляцию (семантика – множество преобразований над синтаксической моделью); ориентированные на интерпретацию (семантика – множество описанных на метаязыке преобразований синтаксически правильных языковых конструкций). © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду После обсуждения обобщенных и концептуально важных требований к языкам программирования в целом, перейдем к неформальному обсуждению семантического подхода, способного обеспечить реализацию этих требований. Прежде всего, расширим наивное представление о семантике языка программирования (или формальной теории) хотя и предварительным, но более конкретным определением этого понятия. Семантикой будем называть интерпретацию (или, иначе, смысловое значение) абстрактного синтаксиса (а точнее, множества допустимых видов конструкций языка), представленное в терминах той или иной математически строгой формальной модели. Как оказывается, все многообразие возможных подходов к семантике можно в основном представить всего двумя типами семантик, а именно, семантиками, ориентированными на компиляцию и семантиками, ориентированными на интерпретацию. В дальнейшем под подходами к семантике, ориентированными на компиляцию, будем понимать такие подходы, в которых семантика представляет собой множество преобразований над синтаксической моделью в той или иной форме. В отличие от предыдущего подхода, под подходами к семантике, ориентированными на интерпретацию, будем понимать такие подходы, в которых семантика представляет собой множество описанных на специально построенном метаязыке преобразований синтаксически правильных конструкций языка программирования.
Современные языки программирования и .NET: II семестр Лекция 4: Семантика основных конструкций языка C#
Общие сведения о семантике (2) Виды семантик, ориентированные на интерпретацию: 1)
2)
3)
Операционные (смысл конструкций языка в терминах переходов абстрактной машины из одного состояния в другое), например, SECD-машина П. Лендина; Пропозиционные (смысл конструкций языка в терминах множества формул, описывающих состояния объектов программы), например, подходы Хоара и Флойда; Денотационные (смысл конструкций языка в терминах абстракции функций на состояниях программы), например, теория семантических доменов Д. Скотта. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Сразу заметим, что целям нашего курса в большей степени соответствует второй подход, как более универсальный в силу того обстоятельства, что в нем используется метатеория, т.е. формализация, моделирующая преобразования текста программ. Выделим основные направления, существующие в рамках подхода к семантике, ориентированного на интерпретацию и свяжем их с рассмотренными нами в ходе лекции направлениями исследований. Оказывается, что существуют три основных вида семантик, ориентированных на интерпретацию. Во-первых, необходимо упомянуть об операционных семантиках. Значение конструкций языка в таких семантиках выражается в терминах переходов той или иной абстрактной машины из одного состояния в другое. В качестве показательных примеров абстрактных машин можно привести, в частности, так называемую SECD-машину П. Лендина, а также категориальную абстрактную машину. Другим типом семантик, ориентированных на интерпретацию, являются так называемые пропозиционные семантики. В отличие от операционных семантик, значение конструкций языка в таких семантиках выражается в терминах множества формул, описывающих состояния объектов программы. В качестве примеров можно привести, в частности, аксиоматический метод Хоара и метод индуктивных утверждений Флойда. Наконец, наиболее значимым для нас типом семантик, ориентированных на интерпретацию, являются денотационные семантики, в которых смысл конструкций языка представляется в терминах абстракции функций, оперирующих состояниями программы. В частности, данный подход иллюстрирует теория вычислений Д. Скотта, основанная на семантических доменах, которую и предлагаем вашему вниманию.
Современные языки программирования и .NET: II семестр Лекция 4: Семантика основных конструкций языка C#
Теория вычислений Д. Скотта Создана в 1969 г. для непротиворечивой формализации семантики языков на основе алгебры доменов – аналогов множеств, адекватно моделирующих самоприменимые функции и множества. 1) 2) 3)
Последовательность построения теории: перечисление стандартных (наиболее часто используемых) доменов; определение конечных доменов с явно перечисляемыми элементами; определение конструкторов (способов комбинирования) доменов. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Напомним, что теория вычислений Д. Скотта была создана до появления большинства современных языков программирования, а именно в конце 60-х г.г. Существенно, что именно эта теория (в отличие от, скажем, классической логики и ряда других формальных систем) позволяет произвести адекватную (а именно, полную и непротиворечивую) формализацию семантики языков программирования. Теория вычислений Д. Скотта основана на фундаментальном понятии домена, который будем неформально понимать как некоторый аналог множества, впрочем, в отличие от традиционных множеств, адекватно формализующий рекурсивно (т.е. на основе самоприменения) определенные функции и множества. Сформулируем последовательность изложения теории вычислений Д. Скотта. Для построения теории вычислений необходимо, во-первых, перечислить так называемые стандартные, или, точнее, наиболее часто используемые в рамках данной формализации, домены. После перечисления стандартных доменов необходимо определить так называемые конечные домены, или, точнее, домены, элементы которых возможно перечислить явным образом. Наконец, после перечисления доменов перейдем к определению конструкторов доменов, под которыми понимаются операции построения новых доменов на основе имеющихся, или, иначе, определим способы комбинирования доменов.
Современные языки программирования и .NET: II семестр Лекция 4: Семантика основных конструкций языка C#
Конструкторы доменов 1)
Функциональное пространство: [D1→D2]={f|f: D1→D2};
2)
Декартово произведение – домен всевозможных n-ок: [D1×D2×…×Dn]={(d1×d2×…×dn)|d1∈D1, d2∈D2 , dn …, ∈Dn};
3)
Последовательность D*- домен всех конечных последовательностей вида d=(d1,d2,…,dn) из элементов d1,d2,…,dn,… домена D, где n>0;
4)
Дизъюнктная сумма [D1 + D2 + … + Dn]={(di,i)| di∈Di, 00. Наконец, под дизъюнктной суммой будем [D1+D2+…+Dn]={ (di, i) | di ∈Di, 0, где: S – подмножество констант, называемых сортами; A – множество аксиом вида c:s, где с-константа, s-сорт; R – множество троек сортов, определяющих возможные функциональные пространства и их сорта для системы Приписывание ламбда-терму M типа T обозначим как #M |— T (читается: «ламбда-терм M имеет тип T») © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду При более формальном подходе к теории типов и типизации в связи с исчислением ламбда-конверсий следует определить чистую систему типов. Чистой системой типов называется семейство ламбда-исчислений, в которых каждый элемент характеризуется тройкой <S, A, R>, где: S – подмножество констант, называемых сортами; A – множество аксиом вида c : s, где с является константой, а s является сортом; R – множество троек сортов, определяющих возможные функциональные пространства и их сорта для системы. Далее введем обозначение, характеризующее то обстоятельство, что тот или иной объект является типизированным, или, иначе говоря, что тому или иному объекту приписан тип. В частности, для ламбда-терма M приписывание ему типа T обозначим как #M |— T и будем в таком случае говорить, что ламбда-терм M имеет тип T.
Современные языки программирования и .NET: II семестр Лекция 6: Теория типов и типизация в .NET
Типы в математике (2) Система типов формируется следующим образом: 1) задается множество базисных типов δ1, δ2, …; 2) всякий базисный тип считается типом; 3) если a и b считаются типами, то функция из a в b считается типом и имеет тип a→b. В основе теории типов лежит принцип иерархичности: производные типы содержат базисные как подмножества. Это справедливо и для языков программирования (аналогично строятся иерархии классов в ООП). © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду При более общем подходе (который верен и для математики, и для программирования), система типов формируется следующим образом. Во-первых, задается множество базисных типов (обозначим их символами d1, d2, и так далее). Во-вторых, примем соглашение, что всякий базисный тип считается типом. Наконец, условимся, что если a и b считаются типами, то функция из a в b также считается типом и при этом имеет тип a→b. Заметим, что в основе теории типов лежит принцип иерархичности, который заключается в том, что производные типы содержат базисные как подмножества. Этот принцип построения остается справедливым и для языков программирования. В частности, иерархии классов в объектно-ориентированных языках программирования формируются аналогично вышеприведенному построению математической системы типов.
Современные языки программирования и .NET: II семестр Лекция 6: Теория типов и типизация в .NET
Преимущества типизации Модель предметной области лучше структурирована, существует иерархия сортов элементов Манипулирование элементами более целенаправленно, разнородные элементы обрабатываются различным образом, однородные - единообразно В случае строгой типизации несоответствия типов фиксируются до выполнения программы, гарантируя отсутствие смысловых ошибок и безопасность кода
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Рассмотрев введение в математическую теорию типов и подходы к типизации в языках программирования, представим в концентрированном виде те преимущества, которые отличают языки программирования и формальные теории с типами. Прежде всего, отметим то бесспорное преимущество типизированных исчислений, что при таком подходе моделируемая предметная область области лучше структурирована, чем в том случае, если отсутствует сегментация на типы. Типизация структурирует предметную область по иерархическому принципу. Введение типизации облегчает и упорядочивает не только восприятие, но и управление предметной областью. Манипулирование типизированными элементами носит более целенаправленный характер, причем появляется возможность обрабатывать разнородные сущности предметной области различным образом, а однородные (или, точнее, однотипные) – единообразно. Перейдем к языкам программирования и практике проектирования и реализации программных систем. В случае построения языка программирования по принципу строгой типизации несоответствия типов фиксируются до начала этапа выполнения программы (на этапе контроля соответствия типов в ходе трансляции), что гарантирует отсутствие семантических (смысловых) и логических ошибок и безопасность программного кода.
Современные языки программирования и .NET: II семестр Лекция 6: Теория типов и типизация в .NET
Классификация систем типизации 1. 2. 3. 4. 5. 6.
Строгая Сильная Слабая Полиморфная С контролем соответствия типов во время компиляции С контролем соответствия типов во время выполнения
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Напомним классификацию систем типизации в языках программирования. Исторически наиболее распространенной для языков программирования является строгая типизация. При таком формировании системы типов в языке в любой момент существования любого языкового объекта существует однозначное соответствие между объектом и его типом. Другими словами, можно запрограммировать функцию, определяющую тип объекта, подобную ранее рассмотренной нами функции typeof языка программирования C#. Строго типизированными являются классические императивные языки программирования Pascal, FORTRAN, PL/1 и др. Отметим, что классический вариант языка программирования C не является строго типизированным. Сильная типизация необходима для обеспечения корректности связывания переменных со значениями до выполнения программы. Таким образом, каждое выражение языка программирования с сильной типизацией, по успешном завершении анализа корректности типизации является корректно типизированным. Примером языка программирования с сильной типизацией может служить SML. Использование механизма выводимости типов гарантирует сильную типизацию даже при отсутствии строгости. Язык программирования, не имеющий сильной системы типизации, может быть назван языком со слабой типизацией. Еще одним важным видом систем типизации языков программирования является полиморфная типизация. При таком подходе допустимы выражения переменного типа (скажем, функция упорядочения списка с неопределенным типом элементов). Процедура контроля соответствия типов (type-checking) может быть реализована как во время компиляции (compile time), т.е. более безопасным образом, так и во время выполнения (run time) программы, что потенциально менее безопасно для программного кода.
Современные языки программирования и .NET: I семестр Лекция 6: Теория типов и комбинаторная логика
Иерархия типов в .NET Общая система типов Common Type System (CTS) Типы-значения Встроенные типы-значения
Ссылочные типы Объектные типы
Интерфейсные типы
Типы указателей
Типы-значения и ссылочные типы, заданные пользователем © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Рассмотрим более подробно обобщенную систему типизации, принятую в .NET. Как очевидно из схемы, Common Type System представляет собой иерархию, в которой стрелки указывают в сторону уменьшения общности типа. Типы иерархии CTS подразделяются на ссылочные типы (reference type) и типы-значения (value type). Особенностями ссылочных типов являются необходимость использования указателей на типизированные объекты, а также централизованное хранение и освобождение памяти («сборка мусора»). Одной из характеристик типов-значений является то обстоятельство, что они не участвуют в наследовании. Кроме того, типы-значения копируются при присваивании значения. В свою очередь, ссылочные типы могут принимать одну из трех форм: 1) объектные типы (object type); 2) интерфейсные типы (interface type); 3) типы указателей (pointer type). В случае отсутствия стандартного типа нужной формы, пользователь имеет возможность конструирования собственного типа, который может быть как ссылочным типом, так и типом-значением. Система CTS обеспечивает безопасную типизацию, т.е. гарантирует отсутствие побочных эффектов (переполнение оперативной памяти компьютера, некорректное преобразование типов и т.д.).
Современные языки программирования и .NET: II семестр Лекция 6: Теория типов и типизация в .NET
Управление типами в CTS • Типы могут использоваться после инициализации (с учетом метода вызова, свойств get и set и т.д.) • Над типами могут совершаться преобразования (как явным, так и неявным образом) • Типы объединяются в совокупности (пространства имен, файлы, сборки) • Важнейшими подкатегориями системы типизации в .NET являются ссылочные типы (reference type) и типы-значения (value type) © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Исследуем особенности управления типами в системе типизации Common Type System технологии Microsoft .NET. Из соображений безопасности программного кода Microsoft .NET типы Common Type System, также как объекты и классы, могут использоваться после инициализации. При этом необходимо учитывать особенности вызывающего метода, а также определенных методов доступа get и изменения set. Подобно конкретизации значений типов при определении значения типовой переменной, над элементами типов могут осуществляться преобразования из одного типа данных в другой (например, из строки в число или наоборот). При этом такие преобразования могут инициироваться как программистом (т.е. происходить явно), так и системой программирования (т.е. происходить неявным образом). Иерархия типов в соотнесении с Microsoft .NET может быть представлена в форме той или иной совокупности (в частности, в виде пространства имен, файла или сборки). Как уже отмечалось, наиболее крупными и важными подкатегориями иерархической системы типизации в Microsoft.NET являются ссылочные типы (reference type) и типызначения (value type).
Современные языки программирования и .NET: II семестр Лекция 6: Теория типов и типизация в .NET
Ссылочные типы и типы-значения в .NET и C# (1) • Типы-значения: – непосредственно содержат объекты данных; – не могут быть пустыми (null) • Ссылочные типы: – содержат ссылки на объекты данных; – могут быть пустыми (null) Пример: int i = 25;
i
string s = “John_Smith";
s
25 "John_Smith"
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Рассмотрим более подробно особенности реализации ссылочных типов и типов-значений в языке программирования C#. Прежде всего, типы-значения, в отличие от ссылочных типов, содержат непосредственно объекты данных. Кроме того, типы-значения не могут быть пустыми (т.е. принимать значение null). Ссылочные типы, в противоположность типам-значениям, содержат не сами объекты, а лишь ссылки на них и могут принимать значение null. В качестве иллюстрации особенностей реализации ссылочных типов и типов-значений в языке программирования C# рассмотрим следующий фрагмент программ на языке C#: int i = 25; string s = “John_Smith";
В первой строке программы происходит означивание целочисленной константы (т.е. типазначения), а во второй – строковой (т.е. типа-ссылки). В результате при выполнении первой строки программы происходит связывание со значением в памяти, а во втором – со ссылкой, т.е. указателем на область памяти, как на схеме. i
s
25 "John_Smith"
Современные языки программирования и .NET: II семестр Лекция 6: Теория типов и типизация в .NET
Ссылочные типы и типы-значения в .NET и C# (2) • Типы-значения: – элементарные: int i; float x; – перечислимые: enum State { Off, On } – структурные: struct Point {int x,y;} • Ссылочные типы: – корневые: object – строковые: string – классы: class Foo: Bar, IFoo {...} – интерфейсы: interface IFoo: IBar {...} – массивы: string[] a = new string[10]; – делегаты: delegate void Empty(); © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Проиллюстрируем иерархию системы типов Common Type System программной среды Microsoft .NET примерами из языка программирования C#, конкретизирующими подтипы для типов-значений и ссылочных типов: При этом типы-значения распадаются на следующие подтипы: • элементарные (в частности, целочисленные и вещественные): int i; float x; • перечислимые (в частности, моделирующие переключатели): enum State { Off, On } • структурные (в частности, моделирующие точки на плоскости): struct Point {int x,y;} В свою очередь, ссылочные типы подразделяются на следующие подтипы: • корневой подтип (указатели на произвольные объекты в иерархии типов в Common Type System): object • строковые (указатели на строки символов): string • классы (указатели на объекты типа class): class Foo: Bar, IFoo {...} • интерфейсы (указатели на объекты типа interface): interface IFoo: IBar {...} • массивы (в частности, указатели на строки из 10 символов): string[] a = new string[10]; • делегаты (усовершенствованные указатели на функцию): delegate void Empty();
Современные языки программирования и .NET: II семестр Лекция 6: Теория типов и типизация в .NET
Сопоставление ссылочных типов и типов-значений Типы-значения
Ссылочные типы
Переменная содержит Переменная хранится Значение по умолчанию Оператор присваивания
значение в стеке 0, false, '\0' копирует значение
ссылку на значение в куче null копирует ссылку
Пример
int i = 25; int j = i;
string s = “John"; string s1 = s;
i
25
s
j
25
s1
John
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Ранее в ходе изложения настоящего курса уже обсуждались механизмы boxing и unboxing, реализованные в различных средах разработки программного обеспечения Microsoft .NET. Напомним, что эти механизмы используются для преобразования типов выражений языков программирования из ссылочных в типы-значения и обратно. Рассмотрим более подробно реализацию двух основных семейств типов данных, а именно, ссылочных типов и типов-значений, применительно к языку программирования C#. Для определенности рассмотрим случай одного из простейших объектов языка программирования C#, а именно, переменной. В соответствии с названиями, переменная в случае использования типов-значений содержит собственно значение, а при использовании ссылочных типов – не само значение, а лишь ссылку (указатель) на него. Местом хранения переменной, определенной как тип-значение, является стек, а определенной как ссылочный тип – «куча» (последнее необходимо для динамического выделения и освобождения памяти для хранения переменной произвольным образом). Значением, которым переменная инициализируется по умолчанию (необходимость выполнения этого требования диктуется идеологией безопасности Microsoft .NET) в случае определения посредством типа-значения является 0 (для целого или вещественного типа данных), false (для логического типа данных), '\0' (для строкового типа данных), а в случае определения посредством ссылочного типа – значение пустой ссылки null. При выполнении оператора присваивания в случае переменной-значения копируется значение, а в случае переменной-ссылки – ссылка. Приведенный далее пример иллюстрирует различия в реализации типов-ссылок и значений.
Современные языки программирования и .NET: II семестр Лекция 6: Теория типов и типизация в .NET
Элементарные типы языка С# (в сопоставлении с языком SML) C# sbyte byte short ushort long float double decimal bool char
CTS System.SByte System.Byte System.Int16 System.UInt16 System.Int64 System.Single System.Double System.Decimal System.Boolean System.Char
SML --byte int word --real ----bool char
Диапазон -128 .. 127 0 .. 255 -32768 .. 32767 0 .. 65535 -263 .. 263-1 ±1.5E-45 .. ±3.4E38 (32 Bit) ±5E-324 .. ±1.7E308 (64 Bit) ±1E-28 .. ±7.9E28 (128 Bit) true, false Символ (в коде unicode)
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Перейдем к более подробному рассмотрению основных типов, входящих в состав Common Type System (CTS) Microsoft .NET. При этом прикладное исследование языков программирования произведем в форме сопоставления отображений фрагментов систем типизации языков программирования SML и C# в систему типов CTS. Для обеспечения большей наглядности сопоставления сведем отображения в следующую таблицу: C# sbyte byte short ushort long float double decimal bool char
CTS System.SByte System.Byte System.Int16 System.UInt16 System.Int64 System.Single System.Double System.Decimal System.Boolean System.Char
SML --byte int word --real ----bool char
Диапазон -128 .. 127 0 .. 255 -32768 .. 32767 0 .. 65535 -263 .. 263-1 ±1.5E-45 .. ±3.4E38 (32 Bit) ±5E-324 .. ±1.7E308 (64 Bit) ±1E-28 .. ±7.9E28 (128 Bit) true, false Символ (в коде unicode)
Даже из предварительного анализа таблицы видно, что система типизации языка программирования С# значительно богаче по сравнению с языком программирования SML. Можно заметить, что всякому типу языка программирования SML соответствует некоторый тип языка программирования С#, и их названия зачастую совпадают или являются подобными друг другу. Наконец, отметим, что все без исключения типы обоих языков программирования однозначно отображаются в систему типизации Microsoft .NET, верхним иерархическим элементом которой является пространство имен System.
Современные языки программирования и .NET: II семестр Лекция 6: Теория типов и типизация в .NET
Иерархия типов языка C# (фрагмент) ТИП
ПРЕДОПРЕДЕЛЕННЫЙ
Значение
USER DEFINED
Ссылка
Перечисление (enum) Массив (int[], string[])
Встроенный
Object
Интерфейс (interface)
String
Ссылочный тип (class)
sbyte short int long byte ushort
Тип-значение (struct) Указатель на функцию (delegate)
uint ulong С плавающей точкой float double Decimal Bool Char
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Данная схема иллюстрирует перечень классов Common Type System среды проектирования и реализации программного обеспечения Microsoft .NET применительно к языку программирования C#. В частности, все многообразие типов можно разделить на предопределенные (заранее заданные системой программирования) и определенные пользователем (user defined). К последним относятся перечисления, массивы, классы, интерфейсы и делегаты (указатели на функцию). Предопределенные типы делятся на ссылочные типы (объекты и символьные строки) и типы-значения (встроенные – короткие и длинные целые со знаком и без знака, а также числа с плавающей точкой – с одинарной и двойной точностью).
Современные языки программирования и .NET: II семестр Лекция 6: Теория типов и типизация в .NET
Соглашения о преобразовании типов в .NET • Неявные преобразования (происходят автоматически, всегда успешно завершаются, без потери точности) • Явные преобразования (требуют вызова, могут завершаться ошибкой, а также приводить к потере точности) • Оба типа преобразований могут быть инициированы пользователем int x = 25; long y = x; short z = (short)x; double d = 3.141592536; float f = (float)d; long l = (long)d;
// неявное // явное // явное // явное
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Как уже отмечалось, над элементами типов могут осуществляться преобразования из одного типа данных в другой (например, из строки в число или наоборот). При этом такие преобразования могут инициироваться как программистом (т.е. происходить явно), так и системой программирования (т.е. происходить неявным образом). Неявные преобразования инициируются Common Type System и происходят автоматически. При этом результат неявного преобразования всегда успешен и не приводит к потере точности. Явные преобразования инициируются программистом или пользователем приложения, а следовательно, требуют явного вызова и при этом могут завершаться ошибкой, а также приводить к потере точности. Приведем ряд примеров преобразований типов на языке программирования C#: int x = 25; long y = x; short z = (short)x; double d = 3.141592536; float f = (float)d; long l = (long)d;
// неявное // явное // явное // явное
Заметим, что система Common Type System среды Microsoft .NET обеспечивает безопасную типизацию, т.е. гарантирует отсутствие побочных эффектов (переполнение оперативной памяти компьютера, некорректное преобразование типов и т.д.). Заметим также, что как явные, так и неявные преобразования типов могут инициироваться пользователем.
Современные языки программирования и .NET: II семестр Лекция 6: Теория типов и типизация в .NET
Пространства имен в .NET (1) • Пространство имен (namespace) предоставляет средства уникальной идентификации типа • Дает возможность логически структурировать систему типов • Пространства имен могут объединять сборки • Пространства имен могут быть вложенными • Между пространствами имен и файлами нет однозначного соответствия • Полное имя типа содержит все пространства имен © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Как показали исследования системы типизации Common Type System среды проектирования и реализации программных систем Microsoft .NET, эта иерархия имеет внушительный объем. С целью повышения эффективности организации описания типов и манипулирования ими в программном обеспечении, работающем под управлением среды Microsoft .NET, вводится понятие пространства имен (namespace). Пространством имен будем называть механизм среды Microsoft .NET, предназначенный для идентификации типов объектов языков программирования и среды реализации. Значение механизма пространств имен состоит в том, что появляется возможность логической структуризации системы типизации Common Type System в среде разработки приложений Microsoft .NET. Описания пространств имен по аналогии описаниями типов данных размещаются в файлах. Перечислим основные свойства, которыми характеризуются пространства имен в среде Microsoft .NET: 1) пространства имен могут объединять различные сборки; 2) пространства имен могут быть вложенными друг в друга; 3) между пространствами имен и файлами не существует однозначного соответствия (т.е. отображения, переводящего название пространства имен в имя файла); 4) полное имя типа должно содержать все необходимые пространства имен.
Современные языки программирования и .NET: II семестр Лекция 6: Теория типов и типизация в .NET
Пространства имен в .NET (2) Пример описания пространств имен (в комментариях приведены полные имена): namespace N1 { class C1 { class C2 { } } namespace N2 { class C2 { } } }
// N1 // N1.C1 // N1.C1.C2 // N1.N2 // N1.N2.C2
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Для иллюстрации применения механизма пространств имен в среде программирования Microsoft .NET приведем развернутый пример описания пространств имен на языке программирования C#: namespace N1 { class C1 { class C2 { } } namespace N2 { class C2 { } } }
// N1 // N1.C1 // N1.C1.C2 // N1.N2 // N1.N2.C2
Рассмотренный пример содержит описания пространств двух имен: пространства N1 с описанием классов C1 и C2 и пространства N2 с описанием класса C2. Заметим, что в комментариях к каждой строке программы на языке C# приведены полные наименования пространств имен. Так, для обращения к классу C2, описанному в пространстве имен N1, нужно использовать полное имя N1.C1.C2, а для обращения к классу C2, описанному в пространстве имен N2 – полное имя N1.N2.C2. Таким образом, при адекватном употреблении полных квалификационных наименований пространств имен удается избежать коллизии обозначений типов.
Современные языки программирования и .NET: II семестр Лекция 6: Теория типов и типизация в .NET
Пространства имен в .NET (3) • • • •
Оператор using: позволяет использовать типы без указания полного имени; может использоваться с полным именем; также используется для указания альтернативных имен (alias).
using N1; C1 a; N1.C1 b; C2 c; N1.N2.C2 d; C1.C2 e;
// // // // //
Имя N1. является неявным Полное имя Ошибка: имя C2 не определено Один из (под)классов C2 Еще один из (под)классов C2
using C1 = N1.N2.C1; using N2 = N1.N2; C1 a; // Соответствует имени N1.N2.C1 N2.C1 b; // Соответствует имени N1.N2.C1
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Очевидно, что при проектировании и реализации масштабных программных комплексов используется весьма значительное количество идентификаторов и риск коллизии обозначений при использовании полных квалификационных имен многократно возрастает. Оказывается, что непременное использование полных имен типов программирования Microsoft .NET является избыточным требованием.
в
среде
Для экономии трудозатрат и во избежание коллизий обозначений при разработке крупных программных систем в языке программирования C# предусмотрен оператор using, к рассмотрению которого и переходим. Для иллюстрации применения механизма ликвидации коллизии обозначений типов в пространствах имен среды программирования Microsoft .NET посредством оператора using приведем развернутый пример на языке программирования C#: using N1; C1 a; // N1.C1 b; // C2 c; // N1.N2.C2 d; // C1.C2 e; // using C1 = N1.N2.C1; using N2 = N1.N2; C1 a; // N2.C1 b; //
Имя N1. является неявным Полное имя Ошибка: имя C2 не определено Один из (под)классов C2 Еще один из (под)классов C2 Соответствует имени N1.N2.C1 Соответствует имени N1.N2.C1
Заметим, что оператор using позволяет использовать типы как с без указанием полного имени, так и без него, а также для указания альтернативных имен (alias).
Современные языки программирования и .NET: II семестр Лекция 6: Теория типов и типизация в .NET
Пространства имен и ссылки • В Visual Studio для проекта могут быть указаны ссылки • Каждая ссылка идентифицирует уникальную сборку • Передается C# компилятору по ссылке (/r или /reference)
csc HelloWorld.cs /reference:System.WinForms.dll
• Пространства имен дают возможность сокращенного именования на уровне языка программирования – (устраняют необходимость многократного повторения полного имени) • Ссылки указывают на сборку для использования в проекте © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Еще одним аспектом проектирования и реализации крупных программных комплексов под управлением среды Microsoft .NET является потенциальная коллизия имен типов в рамках масштабных проектов. Для решения этой проблемы в среде разработки программного обеспечения Microsoft Visual Studio для каждого из проектов проекта могут быть указаны так называемые ссылки, каждая из которых идентифицирует уникальную сборку – самодостаточную единицу для компиляции и выполнения в рамках программного проекта. Ссылки передаются компилятору в ходе трансляции программы на том или ином языке программирования под управлением среды Microsoft .NET по ссылке (при этом используется опция /r или /reference). Скажем, команда на компиляцию файла HelloWorld с исходным текстом программы на языке C# со ссылкой на пространство имен System.WinForms.dll будет иметь вид: csc HelloWorld.cs /reference:System.WinForms.dll
Как видно из приведенного примера, механизм ссылок реализует идентификацию сборки для использования в программном проекте. Подводя итоги обсуждения механизмов управления пространствами имен среды проектирования и реализации программного обеспечения Microsoft .NET, отметим, что пространства имен предоставляют возможность сокращенного именования типов объектов на уровне языка программирования. Таким образом, устраняется необходимость многократного повторения полного имени объекта и существенно уменьшается риск коллизии обозначений, что значительно экономит трудозатраты при проектировании и реализации сложных программных систем и комплексов.
Современные языки программирования и .NET: II семестр Лекция 6: Теория типов и типизация в .NET
Преимущества типизации на платформе .NET 1. 2.
3.
4.
Использование централизованной, унифицированной системы типизации Common Type System (CTS) Строгое соответствие между примитивными типами языков программирования и базовыми классами .NET; встроенная поддержка примитивных типов большинством компиляторов для .NET Явное разделение на ссылочные типы (используются через указатель; централизованно хранятся и освобождаются) и типы-значения (не участвуют в наследовании; при присваивании значения копируются) Гибкий и надежный механизм преобразования типовзначений в ссылочные (boxing) и обратно (unboxing) © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Подводя итоги рассмотрения основных аспектов теории типов и типизации в языках программирования, можно сделать следующие выводы. Во-первых, теории с типами и языки программирования с типизацией имеют значительно более высокую вычислительную мощность, а, следовательно, более высокую теоретическую и прикладную значимость. Во-вторых, технологическая платформа .NET обеспечивает ряд несомненных дополнительных преимуществ перед другими известными платформами в отношении системы типов. В частности, технология .NET использует централизованную, унифицированную, интегрированную систему типизации Common Type System (CTS), общую для всех языков программирования, реализуемых на данной платформе. Кроме того, в рамках технологической платформы .NET обеспечивается строгое, однозначное соответствие между примитивными типами языков программирования и базовыми классами .NET. Большинством компиляторов для языков программирования, которые реализованы для платформы .NET, имеют встроенную поддержку примитивных типов. Целям безопасности типизации также служит явное разделение на ссылочные типы и типы-значения, а также гибкий и надежный механизм преобразования типов-значений в ссылочные (известный также под названием boxing) и обратно (известный также под названием unboxing).
Современные языки программирования и .NET: II семестр Лекция 6: Теория типов и типизация в .NET
Библиография 1. 2.
3.
4.
Curry H.B., Feys R. Combinatory logic, vol.I, North Holland, Amsterdam, 1958 Hindley J.R., Seldin J.P. Introduction to combinators and λcalculus. London Mathematical Society Student Texts, 1, Cambridge University Press, 1986 Milner R. A theory of type polymorphism in programming languages. Journal of Computer and System Science, 17(3):348-375, 1978 Hindley J.R. The principal type-scheme of an object in combinatory logic. Trans. Amer. Math. Soc., 146:29-60, 1969 © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду К сожалению, в рамках времени, отведенных на одну лекцию, можно лишь в общих чертах охарактеризовать такую многоаспектную и гибкую теорию, как теория типов. Мы ограничились рассмотрением лишь наиболее существенных аспектов формализации типизации в языках программирования, включая краткое знакомство с приписыванием типа, выводимостью типов и системой типизации, реализованной в .NET. Для более детального ознакомления с особенностями, достижениями и проблемами в области теории типов и типизации в языках программирования рекомендуется следующий список литературы: 1. Curry H.B., Feys R. Combinatory logic, vol.I, North Holland, Amsterdam, 1958 2. Hindley J.R., Seldin J.P. Introduction to combinators and λ-calculus. London Mathematical Society Student Texts, 1, Cambridge University Press, 1986 3. Milner R. A theory of type polymorphism in programming languages. Journal of Computer and System Science, 17(3):348-375, 1978 4. Hindley J.R. The principal type-scheme of an object in combinatory logic. Trans. Amer. Math. Soc., 146:29-60, 1969 Кратко остановимся на источниках. Работа [1] является энциклопедией формальной системы комбинаторной логики, которая формализует типизацию в языках программирования. Работа [2] связывает ламбда-исчисление и комбинаторную логику. Работа [3] описывает систему полиморфной типизации для языков программирования. Работа [4] посвящена вопросам моделирования типизации объектов языков программирования в терминах комбинаторной логики.
Концепция наследования и ее реализация в языке C#
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В данной лекции будут рассмотрены вопросы, относящиеся к истории развития, идеологии, математическому основанию и обзору возможностей наследования – одной из фундаментальных концепций, на которых зиждется объектно-ориентированное программирование.
Современные языки программирования и .NET: II семестр Лекция 7: Концепция наследования и ее реализация в языке C#
Содержание лекции 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.
Средства моделирования наследования в computer science Наследование в ООП Отношение частичного порядка Диаграммы Х.Хассе Фреймовая нотация Базовые и производные классы в C# Множественное наследование и интерфейсы Иерархия классов в .NET Отображение классов .NET в типы языков SML и C# Библиография © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Коротко о содержании лекции. В ходе лекции будут рассмотрены важнейшие научные исследования, относящиеся к эволюции подходов к математическому моделированию одной из важнейших для объектно-ориентированного подхода к программированию концепций, а именно, наследования. Прежде всего, будет сформулировано определение наследования. Затем будет представлен сравнительный анализ путей реализации концепции наследования в языках объектно-ориентированного программирования и в computer science. При этом будут подробно исследованы особенности формализации концепции наследования посредством диаграмм Х.Хассе и фреймов Н.Руссопулоса. Особое внимание будет уделено реализации механизмов наследования для объектов языка программирования C#, включая иерархическую организацию классов, а также множественное наследование. Отображение классов Microsoft .NET в классы языков программирования SML и C# проиллюстрирует практику применения концепции наследования. Лекция завершится обзором литературы для более глубокого исследования материала.
Современные языки программирования и .NET: II семестр Лекция 7: Концепция наследования и ее реализация в языке C#
Основные результаты исследований в области наследования 1950-е – Х.Хассе (Helmut Hasse, 1898-1979) предложил диаграммы (позже названные в его честь) для графической иллюстрации отношения частичного порядка 1976 – Н.Руссопулос (N.D.Roussopulos) изобрел фреймы для моделирования предметных областей и ввел ISA-отношение частичного порядка 1979 – Д.Скотт (Dana S. Scott) сформулировал теорию полных и непрерывных решеток, которая используется в диаграммах потоков данных 1988-90 – Л.Карделли, У.Кук и др. (Luca Cardelli, William R. Cook et al.) исследовали (денотационную) семантику (множественного) наследования © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Напомним ход эволюции теорий, лежащих в основе современного подхода к наследованию. Еще в 50-х г.г. прошлого столетия Хельмут Хассе (Helmut Hasse, 1898-1979) предложил использовать диаграммы особого рода для графической интерпретации отношения частичного порядка. Заметим, что позднее диаграммы, открытые ученым, получили название в его автора и стали называться диаграммами Хассе. И по сей день диаграммы Хассе являются наиболее широко распространенной графической формализацией механизма наследования. Затем, в 1976 году Н.Руссопулос (N.D.Roussopulos) впервые применил фреймовую нотацию для моделирования отношений между объектами тех или иных предметных областей. Ученым было также введено так называемое ISA-отношение частичного порядка, которое адекватно моделирует понятие наследования. Заметим, что обозначение ISA возникло от английских слов “… is a …”?, означающих «… является одним из … » и хорошо иллюстрирует суть понятия наследования на естественном языке. Позднее, в 1979 году, Д.Скотт (Dana S. Scott) сформулировал теорию полных и непрерывных решеток, которая используется в диаграммах потоков данных. Решетка Д.Скотта представляет собой модель частично упорядоченного множества, или, иначе, модель иерархии классов. Затем, в 1988-90 г.г. учеными Л.Карделли (Luca Cardelli), У.Куком (William R. Cook) и др. была исследована семантика наследования. При этом был построен вариант денотационной семантики, который, как оказалось, адекватно формализовал не только единичное, но и множественное наследование.
Современные языки программирования и .NET: II семестр Лекция 7: Концепция наследования и ее реализация в языке C#
Наследование и методы его моделирования Вообще говоря, под наследованием понимается свойство производного объекта сохранять поведение (атрибуты и операции) родительского. Для языка программирования наследование означает, что (некоторые) свойства и методы базового класса равно применимы к его производным объектам (и их конкретизациям). Наследование моделируется посредством отношения (иерархии) частичного порядка и адекватно отображается графически посредством: 1. Фреймовой нотации Н.Руссопулоса (N.D. Roussopulos); 2. Диаграм Хассе (H.Hasse) © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Кратко обсудив историю развития концепции наследования и ее формализаций, перейдем к понятийному аппарату. Под наследованием в дальнейшем будем понимать свойство производного объекта сохранять поведение родительского объекта. Под поведением будем иметь в виду для математического объекта его атрибуты и операции над ним, а для языкового объекта ООП – поля и методы. Таким образом, применительно к языку программирования концепция наследования означает, что свойства и методы базового класса равно применимы к его производным объектам. Заметим, что дочерний объект не обязательно наследует все без исключения атрибуты и операции родительского, а лишь некоторые из них. Такой подход характерен к как для классов объектов в целом, так и для отдельных их конкретизаций, или, иначе, экземпляров. Как уже упоминалось в ходе лекции, теоретическая концепция наследования удовлетворительно моделируется посредством отношения (или, точнее, иерархии) частичного порядка. Существует целый ряд формализаций наследования, но наиболее адекватными и концептуально ясными являются графические модели. Среди них следует выделить уже упомянутые ранее подходы: фреймовую нотацию Н.Руссопулоса и диаграмы Хассе.
Современные языки программирования и .NET: II семестр Лекция 7: Концепция наследования и ее реализация в языке C#
Свойства отношения частичного порядка 1. Рефлексивность: ∀ a: a ISA a 2. Транзитивность: ∀ a,b,c: a ISA b, b ISA c ⇒ a ISA c 3. Антисимметричность: ∀ a,b : a ISA b ⇒ NOT (b ISA a) © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Отношение частичного порядка обладает следующими теоретически интересными и практически полезными свойствами. Во-первых, оно является рефлексивным, т.е. любой объект языка программирования или формальной модели предметной области находится отношении частичного порядка с самим собой. Формальная запись свойства рефлексивности для отношения частичного порядка выглядит следующим образом: ∀ a: a ISA a.
Другой важной особенностью отношения частичного порядка является транзитивность. Суть транзитивности состоит в том, что если существует цепочка из (трех) объектов, связанных отношением частичного порядка, то первый и последний элементы этой цепочки можно связать тем же отношением. Это свойство гарантирует построение на множестве графа отношения частичного порядка в форме «решетки». Формальная запись свойства транзитивности для отношения частичного порядка выглядит следующим образом: ∀ a,b,c: a ISA b, b ISA c ⇒ a ISA c.
Наконец, еще одним фундаментальным свойством отношения частичного порядка как модели наследования является антисимметричность. Это свойство разрешает наследование только в одном направлении (и запрещает его в противоположном). Формальная запись свойства антисимметричности для отношения частичного порядка выглядит следующим образом: ∀ a,b : a ISA b ⇒ NOT (b ISA a).
Современные языки программирования и .NET: II семестр Лекция 7: Концепция наследования и ее реализация в языке C#
Фрейм как пример моделирования наследования THING ISA
ISA
LEGAL.PERSON
PHYSICAL.OBJECT ISA
ISA ANIMATE.OBJECT
INSTITUTION ISA EMPLOYER
ISA
ISA
RECRUITER
PERSON ISA
MALE.PERSON
ISA FEMALE.PERSON
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду По завершении исследования свойств отношения частичного порядка, перейдем к рассмотрению формализаций, моделирующих наследование. Проиллюстрируем графическую интерпретацию отношения частичного порядка на примере фреймовой нотации Н. Руссопулоса. Рассмотрим следующий фрейм, который связывает отношением частичного порядка понятия «сущность» (THING), «юридическое лицо» (LEGAL.PERSON), «учреждение» (INSTITUTION), «работодатель» (EMPLOYER), «кадровое агентство» (RECRUITER), «физический объект» (PHYSICAL.OBJECT), «одушевленный объект» (ANIMATE.OBJECT), «человек» (PERSON), «мужчина» (MALE.PERSON) и «женщина» (FEMALE.PERSON).
Как видно из структуры фрейма, понятия (или, точнее, концепты) изображены в овалах. Направленные ISA-дуги соединяют понятия, образуя иерархию с направлением в сторону увеличения уровня общности (абстракции), например, от понятия «мужчина» к понятию «сущность». Рефлексивные и транзитивные дуги опущены для удобства восприятия; их без труда можно восстановить. Ориентированность дуг характеризует антисимметричность отношения частичного порядка: любая из дуг может иметь только одну стрелку со стороны увеличения уровня абстракции.
Современные языки программирования и .NET: II семестр Лекция 7: Концепция наследования и ее реализация в языке C#
Использование диаграммы Хассе для моделирования частичного порядка Данный пример иллюстрирует отношение IS IN между множествами {}, {1}, {2}, {3}, {1,2}, {1,3}, {2,3}, и {1,2,3}. Диаграмма Хассе состоит из точек, представляющих элементы множества, а также из соединяющих их линий, которые представляют собой отношения между элементами. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Другой продуктивной формализацией, моделирующей, в частности, наследование, является диаграмма Хассе. Проиллюстрируем использование диаграмм Хассе для графической интерпретации отношения между элементами класса или домена. Диаграмма Хассе состоит из точек, которые представляют элементы множества (точнее, домена или класса), а также из соединяющих их линий, которые представляют собой отношения между элементами класса или домена (в данном случае интерпретируется отношение частичного порядка).
Данный пример иллюстрирует отношение IS IN («является подмножеством») между множествами {}, {1}, {2}, {3}, {1,2}, {1,3}, {2,3} и {1,2,3}. Заметим, что в случае графической интерпретации отношения частичного порядка с помощью диаграммы Хассе свойство антисимметричности рассматриваемого отношения было бы отображено в явном виде.
Современные языки программирования и .NET: II семестр Лекция 7: Концепция наследования и ее реализация в языке C#
Пример единичного наследования на C# (1) class A { // базовый класс int a; public A() {...} public void F() {...} } class B : A { // подкласс (наследует свойства класса A, расширяет класс A) int b; public B() {...} public void G() {...} } © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Исследовав основные свойства отношения наследования и способы его наглядной формализации, рассмотрим, каким образом эта теоретическая концепция реализуется в языках объектно-ориентированного программирования, и, в частности, в языке C#. В простейшем случае язык программирования C# поддерживает единичное наследование. Проиллюстрируем реализацию механизма единичного наследования фрагментом программы на языке C#. class A { // базовый класс int a; public A() {...} public void F() {...} } class B : A { // подкласс (наследует свойства класса A, расширяет класс A) int b; public B() {...} public void G() {...} }
Применительно к языку программирования C# наследование есть отношение между классами. Данный пример содержит описание более общего (находящегося выше по ISAиерархии) класса A и его подкласса – класса B. Заметим, что находящийся выше по ISAиерархии класс принято называть базовым, а находящийся ниже – производным (или подклассом). Подкласс B наследует свойства класса A, и, кроме того, возможно, расширяет его новыми (по сравнению с классом A) свойствами.
Современные языки программирования и .NET: II семестр Лекция 7: Концепция наследования и ее реализация в языке C#
Пример единичного наследования на C# (2)
B наследует свойство a и метод F(), добавляя b и G(): - конструкторы не наследуются; - наследуемые методы могут игнорироваться (см. далее) Единичное наследование: подкласс может наследовать свойства единственного базового класса, однако может при этом реализовывать множественные интерфейсы. Класс может наследовать свойства класса, но не структуры. Структура не может наследовать свойства другого типа данных, однако может при этом реализовывать множественные интерфейсы. Подкласс с неявным базовым классом наследует свойства класса объект (object). © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Приведенный фрагмент программы на языке C# иллюстрирует простейший случай наследования, а именно, единичное наследование. Рассмотрим подробнее, как именно производится реализация механизма наследования. Производный класс B наследует свойство a и метод F() базового класса A. Кроме того, к свойствам производного класса B добавляется новое по сравнению с базовым классом A свойство b, а к методам – новый по сравнению с базовым классом A метод G(). Заметим, что операторы конкретизации элементов базовых классов (которые в языке C# называют конструкторами) не наследуются производными классами. Заметим также, что некоторые из наследуемых методов могут игнорироваться. В ходе единичного наследования производный подкласс может наследовать свойства единственного базового класса. Множественное наследование, демонстрирующее гибкость механизмов наследования в языке C#, реализуется на основе интерфейсов. Хотя производный класс в языке программирования C# может наследовать свойства базового класса, он не может наследовать свойств структуры. Реализация механизма наследования (в том числе множественного) для структур в языке программирования C# осуществляется (как и в случае с классами) посредством интерфейсов. Вопросы множественного наследования посредством механизма интерфейсов будут более подробно обсуждены далее в ходе курса. В случае неявного задания базового класса, производный класс наследует свойства наиболее общего класса Microsoft .NET, известного как объект (object) и аналогичного концепту THING («сущность») в рассмотренном ранее примере фреймовой нотации.
Современные языки программирования и .NET: II семестр Лекция 7: Концепция наследования и ее реализация в языке C#
Множественное наследование в C#: интерфейсы (1) public interface IList : ICollection, IEnumerable { int Add (object value); // методы bool Contains (object value); ... bool IsReadOnly { get; } // свойство ... object this [int index] { get; set; } // индексатор } © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Как уже неоднократно упоминалось в ходе изложения, в языке программирования C# допускается не только единичное, но и множественное наследование. Для реализации концепции множественного наследования в языке программирования C# предусмотрен так называемый механизм интерфейсов. Для иллюстрации приведем фрагмент программы на языке C#, содержащей описание интерфейса: public interface IList : ICollection, IEnumerable { int Add (object value); // методы bool Contains (object value); ... bool IsReadOnly { get; } // свойство ... object this [int index] { get; set; } // индексатор }
Из приведенного примера можно видеть, что фрагмент программы на языке C# представляет собой описание общедоступного интерфейса IList, наследующего в иерархии элементы интерфейсов ICollection и IEnumerable, а также содержащего методы Add и Contains, свойство IsReadOnly и объект-индексатор this.
Современные языки программирования и .NET: II семестр Лекция 7: Концепция наследования и ее реализация в языке C#
Множественное наследование в C#: интерфейсы (2)
• • • • •
Интерфейсом называется чисто абстрактный класс (с полиморфизмом), содержащий только описание без реализации. Интерфейс может содержать методы, свойства, индексаторы и события (не может содержать полей, констант, конструкторов, деструкторов, операторов и др.). Элементы interface неявно являются public abstract (virtual). Элементы interface не должны быть статическими. Классы и структуры могут реализовывать множественные интерфейсы. Интерфейс может расширять другой интерфейс. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду После визуального знакомства с кодом на языке программирования C#, описывающим интерфейс, приведем более общее словесное определение этого механизма, имеющего принципиальное значение. Интерфейсом называется чисто абстрактный класс (с поддержкой полиморфизма) содержащей только описания без реализации. Концепция множественного наследования предполагает возможность наследования одним концептом языка свойств сразу нескольких языковых концептов. При этом в языке программирования C# принципиально допустимо множественное наследование, но область действия его ограничена интерфейсами. Множественное наследование классов в языке программирования C# недопустимо, однако неявно реализуемо посредством интерфейсов. Так, классы и структуры языка программирования C# могут реализовывать множественные интерфейсы. Интерфейсы могут содержать в своем составе методы, свойства, индексаторы и события. Однако интерфейсы не могут содержать в своем составе полей, констант, конструкторов, деструкторов, операторов, а также вложенных типов. Элементы интерфейса неявно являются виртуальными (т.е. общедоступными и абстрактными) объектами и описываются в языке C# как public abstract (или virtual). Интерфейсы, будучи принципиально полиморфными (т.е. динамически означиваемыми) объектами, не могут содержать в своем составе статических элементов. Наконец, свойства одного интерфейса могут быть расширены посредством другого интерфейса.
Современные языки программирования и .NET: II семестр Лекция 7: Концепция наследования и ее реализация в языке C#
Множественное наследование в C#: интерфейсы (3) • Класс может наследовать свойства единственного базового класса, но реализовывать множественные интерфейсы. • Структура не может наследовать свойства типа, но может реализовывать множественные интерфейсы. • Любой элемент интерфейса (метод, свойство, индексатор) должен быть реализован в базовом классе или унаследован от него. • Реализованные методы интерфейса могут описываться как виртуальные (virtual) или абстрактные (abstract), т.е. интерфейс может быть реализован посредством абстрактного класса, но не как override. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Рассмотрим более подробно важнейшие свойства интерфейсов как реализации концепции множественного наследования в языке программирования C#. Как уже отмечалось, концепция множественного наследования в языке программирования C# в явной форме неприменима для классов. В случае классов существует возможность только единичного наследования, т.е. производный класс может наследовать свойства единственного базового класса. Механизм интерфейсов, таким образом, является неявной возможностью реализации концепции множественного наследования для языка программирования C#, поскольку для классов в языке допустима реализация множественных интерфейсов. В отношении наследования структур в языке программирования C# наблюдается определенное сходство с классами. В частности, несмотря на то обстоятельство, что структуры не имеют возможности наследовать свойства типов, для них, также как и для классов, допустима реализация множественных интерфейсов. При этом произвольный элемент интерфейса, будь то метод, свойство или индексатор, должен непременно быть либо реализован непосредственно в базовом классе, либо унаследован от него. Кроме того, заметим, что реализованные в языке программирования C# методы интерфейса могут быть описаны либо как виртуальные (virtual), либо как абстрактные (abstract). Таким образом, интерфейс может быть реализован посредством абстрактного класса. В то же время не допускается реализация переопределенных интерфейсов по аналогии с переопределенными в производных классах методами, которые описываются посредством ключевого слова override языка программирования C#.
Современные языки программирования и .NET: II семестр Лекция 7: Концепция наследования и ее реализация в языке C#
Иерархия классов .NET framework System.Web Services Description Discovery Protocols
UI HtmlControls
Caching Configuration
Security SessionState
System.Windows.Forms Form
Button
MessageBox
ListControl
WebControls
System.Drawing Drawing2D Imaging
System.Data OLEDB Design
SQL SQLTypes
Collections Configuration Diagnostics Globalization
IO Net Reflection Resources
Printing Text
System.Xml XSLT XPath
Serialization
System Security ServiceProcess Text Threading
Runtime InteropServices Remoting Serialization
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Концепция наследования, рассмотренная нами применительно к объектноориентированному подходу к программированию, вполне может быть распространена и на случай систем и сред, поддерживающих проектирование и реализацию программного обеспечения. В этой связи не является исключением и среда интегрированной разработки приложений Microsoft .NET, классы в которой не имеют существенных различий с классами языка программирования C#. Как видно из схемы, описывающей основные пространства имен Microsoft .NET Framework, организация их является вполне иерархической и реализует классическую схему единичного наследования. Наиболее общим концептом иерархии является пространство имен System, характеризующее конфигурацию среды Microsoft .NET Framework и содержащее, в частности, параметры среды времени выполнения приложений, удаленной обработки данных, процессов, безопасности, ввода-вывода, системной конфигурации и др. Среди подпространств пространство имен System можно выделить такие пространства имен, как System.Web, System.Windows.Forms, System.Data, System.Drawing и System.Xml, которые описывают такие характеристики среды Microsoft .NET Framework, как конфигурации веб-сервисов, формы ввода-вывода данных, форматы представления данных, графических подсистем и др.
Современные языки программирования и .NET: II семестр Лекция 7: Концепция наследования и ее реализация в языке C#
Иерархия типов языка C# (фрагмент) ТИП
ПРЕДОПРЕДЕЛЕННЫЙ
Значение
USER DEFINED
Ссылка
Перечисление (enum) Массив (int[], string[])
Встроенный
Object
Интерфейс (interface)
String
Ссылочный тип (class)
sbyte short int long byte ushort
Тип-значение (struct) Указатель на функцию (delegate)
uint ulong С плавающей точкой float double Decimal Bool Char
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Данная схема иллюстрирует перечень классов Common Type System среды проектирования и реализации программного обеспечения Microsoft .NET применительно к языку программирования C#. В частности, все многообразие типов можно разделить на предопределенные (заранее заданные системой программирования) и определенные пользователем (user defined). К последним относятся перечисления, массивы, классы, интерфейсы и делегаты (указатели на функцию). Предопределенные типы делятся на ссылочные типы (объекты и символьные строки) и типы-значения (встроенные – короткие и длинные целые со знаком и без знака, а также числа с плавающей точкой – с одинарной и двойной точностью).
Современные языки программирования и .NET: II семестр Лекция 7: Концепция наследования и ее реализация в языке C#
Элементарные типы языка С# (в сопоставлении с языком SML) C# sbyte byte short ushort long float double decimal bool char
CTS System.SByte System.Byte System.Int16 System.UInt16 System.Int64 System.Single System.Double System.Decimal System.Boolean System.Char
SML --byte int word --real ----bool char
Диапазон -128 .. 127 0 .. 255 -32768 .. 32767 0 .. 65535 -263 .. 263-1 ±1.5E-45 .. ±3.4E38 (32 Bit) ±5E-324 .. ±1.7E308 (64 Bit) ±1E-28 .. ±7.9E28 (128 Bit) true, false Символ (в коде unicode)
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Перейдем к более подробному рассмотрению основных типов, входящих в состав Common Type System (CTS) Microsoft .NET. При этом прикладное исследование языков программирования произведем в форме сопоставления отображений фрагментов систем типизации языков программирования SML и C# в систему типов CTS. Для обеспечения большей наглядности сопоставления сведем отображения в следующую таблицу: C# sbyte byte short ushort long float double decimal bool char
CTS System.SByte System.Byte System.Int16 System.UInt16 System.Int64 System.Single System.Double System.Decimal System.Boolean System.Char
SML --byte int word --real ----bool char
Диапазон -128 .. 127 0 .. 255 -32768 .. 32767 0 .. 65535 -263 .. 263-1 ±1.5E-45 .. ±3.4E38 (32 Bit) ±5E-324 .. ±1.7E308 (64 Bit) ±1E-28 .. ±7.9E28 (128 Bit) true, false Символ (в коде unicode)
Даже из предварительного анализа таблицы видно, что система типизации языка программирования С# значительно богаче по сравнению с языком программирования SML. Можно заметить, что всякому типу языка программирования SML соответствует некоторый тип языка программирования С#, и их названия зачастую совпадают или являются подобными друг другу. Наконец, отметим, что все без исключения типы обоих языков программирования однозначно отображаются в систему типизации Microsoft .NET, верхним иерархическим элементом которой является пространство имен System.
Современные языки программирования и .NET: II семестр Лекция 7: Концепция наследования и ее реализация в языке C#
Преимущества наследования 1.
Отсутствие необходимости явного указания свойств и методов для производных объектов
2.
Гибкое определение уровня абстракции предметной области
3.
Возможность моделирования сколь угодно сложной предметной области
4.
Простой и прямолинейный подход к построению (производных) классов по заданной совокупности свойств и методов © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Подводя итоги обсуждения наследования, одной из основополагающих концепций объектно-ориентированного подхода к программированию, кратко резюмируем положительные стороны явления и вытекающие из них практические возможности. Прежде всего, концепция наследования устраняет необходимость многократного явного указания свойств и методов для производных объектов. Одного взгляда на схему пространств имен Microsoft .NET Framework достаточно, чтобы понять значимость этого свойства. Заметим, что на схеме показана лишь часть верхних «этажей» многоуровневой иерархии. Кроме того, следует отметить, что наследование открывает возможности для гибкого определения уровня абстракции предметной области. Можно оперировать единственным, достаточно абстрактным, концептом System или THING, и, спускаясь по ISA-иерархии, вести рассуждения в терминах все более конкретных концептов и сущностей (или, в терминологии языка программирования C#, классов и объектов). Таким образом, концепция наследования предоставляет возможность моделирования сколь угодно сложной предметной области посредством ISA-иерархии концептов (или классов языка программирования C#), моделирующих объекты реального мира. Итак, наследование предоставляет простой и прямолинейный подход к построению классов (которые в терминологии языка программирования C# принято называть производными) по заданной совокупности свойств и методов так называемых базовых классов. Заметим, что в языке программирования C# допустимо наследование свойств и методов как от единственного класса (единичное), так и от нескольких классов (множественное). Последний вид наследования реализуется посредством механизма интерфейсов. Для моделирования наследования возможно воспользоваться фреймами Н.Руссопулоса и диаграммами Х.Хассе.
Современные языки программирования и .NET: II семестр Лекция 7: Концепция наследования и ее реализация в языке C#
Библиография (1) 1. 2. 3. 4.
Cardelli L. A semantics of multiple inheritance. In: Information and Computation, vol.76, 1988, p.p. 138-164 Cook W., Palsberg J. A denotational semantics of inheritance and its correctness. In: OOPSLA 1989 as SIGPLAN, vol.24, No.10, Oct. 1989, p.p. 433-444 Cook W., Hill W.L., Canning P.S. Inheritance is not subtyping. In: Proc. 17th ACM Symposium on Principles of Programming Langauges, Jan. 1990, p.p. 125-135 Scott D.S. The lattice of flow diagrams.- Lecture Notes in Mathematics, 188, Symposium on Mathematics of Algorithmic Languages.- Springer-Verlag, 1971, p.p. 311-372 © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду К сожалению, в рамках времени, отведенных на одну лекцию, можно лишь в общих чертах охарактеризовать специфику такой фундаментальной концепции для каждого языка объектно-ориентированного программирования и для подхода в целом, как наследование. Для более детального ознакомления с особенностями, достижениями и проблемами в теории моделирования этой концепции и практики реализации связанных с ней механизмов рекомендуется следующий список литературы: 1.Cardelli L. A semantics of multiple inheritance. In: Information and Computation, vol.76, 1988, p.p. 138-164 2.Cook W., Palsberg J. A denotational semantics of inheritance and its correctness. In: OOPSLA 1989 as SIGPLAN, vol.24, No.10, Oct. 1989, p.p. 433-444 3.Cook W., Hill W.L., Canning P.S. Inheritance is not subtyping. In: Proc. 17th ACM Symposium on Principles of Programming Langauges, Jan. 1990, p.p. 125-135 4.Scott D.S. The lattice of flow diagrams.- Lecture Notes in Mathematics, 188, Symposium on Mathematics of Algorithmic Languages.- Springer-Verlag, 1971, p.p. 311-372 Кратко остановимся на источниках. В работе [1] исследуется семантика множественного наследования. В работе [2] обсуждается применимость денотационной семантики для моделирования наследования, в частности, с целью обеспечения корректности. Работа [3] устанавливает связь между наследованием и приписыванием подтипов. В работе [4] представлено исчерпывающее описание теории решеток – продуктивной формализации для моделирования наследования.
Современные языки программирования и .NET: II семестр Лекция 7: Концепция наследования и ее реализация в языке C#
Библиография (2) 5.
Scott D.S. Identity and existence in intuitionistic logic.- In: Application of Sheaves.- Berlin: Springer, 1979, p.p. 600-696
6.
Roussopulos N.D. A semantic network model of data bases, Toronto Univ., 1976
7.
Frei G. Helmut Hasse (1898-1979), Expositiones Mathematicae 3 (1) (1985), 55-69 © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Продолжим обсуждение работ, посвященных исследованию концепции наследования в объектно-ориентированном подходе к программированию. 5.Scott D.S. Identity and existence in intuitionistic logic.- In: Application of Sheaves.- Berlin: Springer, 1979, p.p. 600-696 6.Roussopulos N.D. A semantic network model of data bases, Toronto Univ., 1976 7.Frei G. Helmut Hasse (1898-1979), Expositiones Mathematicae 3 (1) (1985), 55-69 Работа [5] представляет собой систематизацию важнейших понятий – тождества и существования – в логиках высших порядков и затрагивает вопросы принципиальной формализуемости реального мира. В работе [6] обсуждаются способы построения математически и логически корректных взаимоотношений понятий предметной области, т.е. строится своего рода объектная модель наследования, графически интерпретируемая фреймами Н.Руссопулоса. В работе [7] систематизируются научные взгляды Х.Хассе, создателя диаграмм Хассе – графической формализации, моделирующей наследование.
Концепция инкапсуляции и ее реализация в языке C#
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В данной лекции будут рассмотрены вопросы, относящиеся к истории развития, идеологии, математическому основанию и обзору возможностей инкапсуляции – одной из фундаментальных концепций, на которых базируется объектно-ориентированное программирование.
Современные языки программирования и .NET: II семестр Лекция 8: Концепция инкапсуляции и ее реализация в языке C#
Содержание лекции 1.
Понятие инкапсуляции в computer science
2.
Инкапсуляция в ООП
3.
Примеры инкапсуляции в языке C# (описание и пременение)
4.
Виды областей видимости объектов
5.
Рекомендации по разграничению областей видимости
6.
Преимущества инкапсуляции
7.
Библиография © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Коротко о содержании лекции. В ходе лекции будут рассмотрены важнейшие научные исследования, относящиеся к эволюции подходов к математическому моделированию одной из важнейших для объектно-ориентированного подхода к программированию концепций, а именно, инкапсуляции. Прежде всего, будет сформулировано определение понятия инкапсуляции. Затем будет представлен сравнительный анализ путей реализации концепции инкапсуляции в языках объектно-ориентированного программирования и в computer science. Особое внимание будет уделено реализации механизмов инкапсуляции для объектов языка программирования C#, включая классификацию областей видимости объектов, а также особенности их применения. Рекомендации по использованию областей видимости с примерами программ на языке C# проиллюстрируют практику применения концепции инкапсуляции. Лекция завершится обзором литературы для более глубокого исследования материала.
Современные языки программирования и .NET: II семестр Лекция 8: Концепция инкапсуляции и ее реализация в языке C#
Концепция инкапсуляции в программировании Вообще говоря, под инкапсуляцией понимается доступность объекта исключительно посредством его свойств и методов. Таким образом, свойствами объекта (явно описанными или производными) возможно оперировать исключительно посредством его методов. Свойства инкапсуляции: • совместное хранение данных и функций; • сокрытие внутренней информации от пользователя; • изоляция пользователя от особенностей реализации. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Прежде всего, попытаемся формализовать понятие инкапсуляции в рамках объектноориентированного подхода к программированию. В неформальной постановке вопроса будем понимать под инкапсуляцией доступность объекта исключительно посредством его свойств и методов. Другими словами, концепция инкапсуляции призвана обеспечивать безопасность проектирования и реализации программного обеспечения на основе локализации манипулирования объектом в областях его полей и методов. Иначе говоря, свойствами объекта возможно оперировать исключительно посредством его методов. Это замечание касается как свойств, явно определенных в описании объекта, так и свойств, унаследованных данным объектом от другого (других). Практическая важность концепции инкапсуляции для современных языков объектноориентированного программирования (в том числе и для языка C#) определяется следующими фундаментальными свойствами. Прежде всего, реализация концепции инкапсуляции обеспечивает совместное хранение данных (или, иначе, полей) и функций (или, иначе, методов) внутри объекта. Как следствие, механизм инкапсуляции приводит к сокрытию информации о внутреннем «устройстве» объекта данных (или, в терминах языков ООП, свойств и методов объекта) от пользователя того или иного объектно-ориентированного приложения. Таким образом, пользователь, получающий программное обеспечение как сервис, оказывается изолированным от особенностей среды реализации.
Современные языки программирования и .NET: II семестр Лекция 8: Концепция инкапсуляции и ее реализация в языке C#
Понятие инкапсуляции в computer science Формальные модели инкапсуляции: 1. Ламбда-исчисление: • ламбда-термы выполняют роль объектов; • связанные переменные выполняют роль свойств; • свободные переменные выполняют роль методов; 2. Комбинаторная логика: • комбинаторы выполняют роль объектов; • переменные выполняют роль свойств; • комбинаторы выполняют роль методов. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Обсудив определение понятия инкапсуляции (пока на интуитивном уровне), перейдем к рассмотрению формализаций этой фундаментальной для объектно-ориентированного программирования концепции на основе уже известных нам формальных теорий computer science. Как оказывается, понятие инкапсуляции вполне адекватно формализуется посредством таких теоретических формальных систем, как ламбда-исчисление А.Черча и комбинаторная логика Х.Карри. При этом, при интерпретации концепции инкапсуляции в терминах формальной системы ламбда-исчисления, в роли объектов выступают ламбда-термы, в роли свойств – связанные переменные, а в роли методов – свободные переменные. В случае же интерпретации концепции инкапсуляции в терминах формальной системы комбинаторной логики, в роли объектов выступают комбинаторы, в роли свойств – переменные, а в роли методов – комбинаторы.
Современные языки программирования и .NET: II семестр Лекция 8: Концепция инкапсуляции и ее реализация в языке C#
Объект традиционного языка (сокрытие информации) ОБЪЕКТ
ДАННЫЕ
В традиционных языках программирования объявления данных и процедуры обработки этих данных отделены друг от друга. Доступ к данным может быть получен «со стороны», вообще говоря, посредством произвольной процедуры, что является непоследовательным и небезопасным. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Поясним в более детальной форме реализацию механизма сокрытия информации посредством концепции инкапсуляции. Рассмотрим в достаточно обобщенном виде схему взаимодействия объекта и данных. Вначале представим схему такого рода для традиционного императивного языка программирования (каковыми являются, например, языки C и Pascal). При этом в нашем рассуждении под термином «объект» будем понимать произвольный объект языка программирования, безотносительно к концепции объектно-ориентированного программирования. В этом случае, объявления данных и процедуры обработки данных отделены друг от друга. Зачастую в ранних языках программирования описания языковых объектов и процедуры манипулирования ими выделены в обособленные разделы. В этой связи, принципиальным недостатком ранних императивных языков программирования является то обстоятельство, что доступ к данным может быть получен методами, которые изначально не предназначались разработчиками приложений для манипулирования этими данными. Вообще говоря, управление объектом может осуществляться посредством произвольной процедуры или функции, и у среды проектирования и реализации программного обеспечения нет возможности централизованного управления этим процессом. Такой подход к программированию, безусловно, является довольно непоследовательным и весьма небезопасным.
Современные языки программирования и .NET: II семестр Лекция 8: Концепция инкапсуляции и ее реализация в языке C#
Схема инкапсуляции объекта языка ООП
ОБЪЕКТ ДАННЫЕ В ООП определение и методы обработки свойств объекта хранятся совместно; доступ к объекту, минуя его методы, не представляется возможным. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В отличие от предыдущей схемы, при объектно-ориентированном подходе к проектированию и реализации прикладного программного обеспечения взаимодействие объектов языка программирования и конкретизирующих его данных реализуется принципиально иным образом. По существу, объект и данные составляют единое и неделимое целое. Прежде всего, определение (или описание свойств классов) и процедуры манипулирования этими свойствами (или методы) для каждого объекта языка программирования при объектно-ориентированном подходе хранятся совместно. Кроме того, среда проектирования и реализации программного обеспечения (например, Microsoft Visual Studio .NET) не предоставляет иных возможностей доступа к объекту, как посредством методов, изначально предназначенных для манипулирования данным объектом. Таким образом, концепция инкапсуляции в языках объектно-ориентированного программирования служит целям обеспечения единообразия определения, хранения и манипулирования информацией о языковых объектах.
Современные языки программирования и .NET: II семестр Лекция 8: Концепция инкапсуляции и ее реализация в языке C#
Основные виды областей видимости в языке C# Степень инкапсуляции объекта зависит от вида области видимости: 1. public (доступность из любого места, для которого известно пространство имен с описанием объекта): - элементы интерфейсов и перечислений являются public по умолчанию; - типы в пространствах имен (классы, структуры, интерфейсы, перечисления, делегаты) по умолчанию являются доступными как internal (видимы из сборки с описанием объекта); 2. private (доступность из описания класса или структуры): - элементы классов и структур (поля, методы, свойства, вложенные типы и т.д.) являются private по умолчанию. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Заметим, что инкапсуляция является безусловно необходимым требованием для каждого объекта. В то же время, в практике программирования, степень инкапсуляции объекта (в широком значении этого слова) определяется его описанием, а также описанием порождающих его объектов (в действительности это, как правило, описания базовых и производных классов). В этой связи в языках объектно-ориентированного программирования вводится понятие области видимости как степени доступности произвольного языкового объекта. Применительно к языку программирования подразделяются на следующие виды.
C#
области
видимости
объектов
Общедоступные объекты описываются с помощью зарезервированного слова public и характеризуются доступностью из произвольного места программы, для которого определено пространство имен с описанием рассматриваемого объекта. При этом элементы интерфейсов и перечислений являются общедоступными (public) объектами по умолчанию. С другой стороны, типы, описанные в составе пространств имен в форме классов, структур, интерфейсов, перечислений или делегатов являются по умолчанию видимыми из сборки с описанием объекта и описываются с помощью зарезервированного слова internal. Наконец, элементы классов и структур, в частности, поля, методы, свойства и вложенные типы являются по умолчанию доступными из описаний соответствующих классов или структур и описываются с помощью зарезервированного слова private.
Современные языки программирования и .NET: II семестр Лекция 8: Концепция инкапсуляции и ее реализация в языке C#
Пример использования областей видимости в C# public class Stack { private int[] val; // private используется и по умолчанию private int top; // private используется и по умолчанию public Stack() {...} public void Push(int x) {...} public int Pop() {...} } © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Проиллюстрируем обсуждение использования модификаторов областей видимости объектов (public и private) следующим содержательным примером фрагмента программы на языке C#: public class Stack { private int[] val; // private используется и по умолчанию private int top; // private используется и по умолчанию public Stack() {...} public void Push(int x) {...} public int Pop() {...} }
Как видно из приведенного примера, фрагмент программы на языке C# содержит описание класса стека Stack, реализованного на основе массива целочисленных элементов (поле val). Голова стека представляет собой целочисленное значение (поле top). Над стеком определены операции инициализации (метод Stack), а также вставки (метод Push) и удаления (метод Pop) элемента. Как явствует из примера, класс Stack и все манипулирующие его объектами методы (Stack, Push и Pop) являются общедоступными (public), тогда как поля являются доступными локально (private), т.е. только из описания данного класса.
Современные языки программирования и .NET: II семестр Лекция 8: Концепция инкапсуляции и ее реализация в языке C#
Расширенные возможности использования областей видимости в языке C# Виды дополнительных областей видимости объектов в языке C#: 1) protected: доступность из класса с описанием объекта и его подклассов; 2) internal: доступность из сборки с описанием объекта; 3) protected internal: доступность из класса с описанием объекта, его подклассов, а также из сборки с описанием объекта © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Заметим, что в приведенном выше примере фрагмента программы с описанием областей видимости использовались только базовые возможности модификаторов видимости языка программирования C#. Оказывается, что язык программирования C# располагает механизмами реализации дополнительных (или расширенных) по сравнению с базовыми областей видимости объектов. Рассмотрим более подробно особенности основных типов расширенных областей видимости объектов в языке программирования C#. К числу расширенных областей видимости следует отнести доступность языковых объектов как непосредственно из класса с описанием объекта, так и из его производных классов. В данном случае для описания языкового объекта используется зарезервированное слово protected. Кроме того, для описания доступности языкового объекта лишь из сборки с его описанием используется зарезервированное слово internal. Наконец, для описания доступности языкового объекта непосредственно из класса с описанием данного объекта, его производных классов, а также из сборки с описанием данного объекта используется зарезервированное слово protected internal.
Современные языки программирования и .NET: II семестр Лекция 8: Концепция инкапсуляции и ее реализация в языке C#
Пример использования расширенных областей видимости в языке C# class Stack { protected int[] values = new int[32]; protected int top = -1; public void Push(int x) {...} public int Pop() {...} } class BetterStack : Stack { public bool Contains(int x) { foreach (int y in values) if(x==y) return true; return false; } } class Client { Stack s = new Stack(); ... s.values[0] ... // ошибка при компиляции! } © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Проиллюстрируем обсуждение использования модификаторов расширенных областей видимости объектов (protected и internal) следующим содержательным примером фрагмента программы на языке C#: class Stack { protected int[] values = new int[32]; protected int top = -1; public void Push(int x) {...} public int Pop() {...} } class BetterStack : Stack { public bool Contains(int x) { foreach (int y in values) if(x==y) return true; return false; } } class Client { Stack s = new Stack(); ... s.values[0] ... // ошибка при компиляции! }
Как видно из приведенного примера, фрагмент программы на языке C# содержит описание класса стека Stack (для хранения 32 целочисленных элементов и значением –1 в вершине), а также реализованного на его основе усовершенствованного класса стека BetterStack, дополнительно реализующего повторяющиеся элементы стека. В отличие от предыдущего примера, все поля класса стека Stack доступны как из данного класса, так и из классов, производных от него, поскольку описаны посредством ключевого слова protected. Особенности реализации оператора foreach будут рассмотрены далее в ходе курса.
Современные языки программирования и .NET: II семестр Лекция 8: Концепция инкапсуляции и ее реализация в языке C#
Инкапсуляция полей и констант в языке C# (1) Поле: - инициализация факультативна, однако запрещен доступ к полям и методам того же типа; - поля структуры не подлежат инициализации Пример поля: class C { int value = 0;
Константа: - Значение должно быть вычислимо в процессе компиляции Пример константы: const long size = ((long)int.MaxValue + 1) / 4; © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду После обсуждения использования (степеней) инкапсуляции применительно к классам в целом, рассмотрим особенности приложения данной концепции к таким фундаментальным объектам языка программирования C# как поля и константы. Инициализация не является безусловно необходимой для полей в языке программирования C#. Тем не менее, доступ к полям и методам изначально запрещен (что соответствует использованию по умолчанию модификатора доступа private). В случае структуры поля инициализации не подлежат. Простейшей иллюстрацией описания поля в языке программирования C# является следующий пример, содержащий определение класса C с целочисленным полем value: class C { int value = 0; }
В случае константы инициализация также не является необходимым требованием. Тем не менее, значение константы должно быть вычислимо в процессе компиляции. Простейшей иллюстрацией описания константы в языке программирования C# является следующий пример, содержащий определение константы size , представляющей собой целочисленное значение двойной длины (long): const long size = ((long)int.MaxValue + 1) / 4;
Заметим, что фрагмент …(long) … в правой части присваивания представляет собой явное преобразование типов языковых объектов.
Современные языки программирования и .NET: II семестр Лекция 8: Концепция инкапсуляции и ее реализация в языке C#
Инкапсуляция полей и констант в языке C# (2) Поле только для чтения (readonly): - необходимо инициализировать в описании или конструкторе; - значение не обязательно должно быть вычислимым в ходе компиляции; - занимает область памяти (аналогично полю). Пример поля только для чтения: readonly DateTime date; Доступ изнутри класса: ... value ... size ... date ... Доступ из других классов: c = new C(); ... c.value ... c.size ... c.date ... © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Особым случаем реализации концепции инкапсуляции в языке объектноориентированного программирования C# является механизм полей, предназначенных только для чтения. Для описания такого рода полей в языке C# используется зарезервированное слово readonly. Основные свойства полей, предназначенных только для чтения, сводятся к следующему. Прежде всего, такие поля необходимо инициализировать непосредственно при описании или в конструкторе класса. Кроме того, значение поля, предназначенного только для чтения, не обязательно должно быть вычислимым в ходе компиляции, а может быть вычислено во время выполнения программы. Наконец, поля, предназначенные только для чтения, занимают предназначенные для них области памяти (что до определенной степени аналогично статическим объектам). Проиллюстрируем основные свойства полей, предназначенных только для чтения, следующими примерами фрагментов программ на языке C#. Описание поля выглядит следующим образом: readonly DateTime date;
Доступ к полю изнутри класса организуется по краткому имени объекта: ... value ... size ... date ...
Доступ к полю из других классов (на примере объекта c как конкретизации класса C) реализуется с указанием полного имени объекта: c = new C(); ... c.value ... c.size ... c.date ...
Современные языки программирования и .NET: II семестр Лекция 8: Концепция инкапсуляции и ее реализация в языке C#
Доступ к статическим полям и константам Статические поля и константы принадлежат классу, а не объекту: class Rectangle { static Color defaultColor;//однократно для класса static readonly int scale; //однократно для класса // статические константы недопустимо использовать int x, y, width,height; //однократно для объекта ... }
Доступ изнутри класса: ... defaultColor ... scale ...
Доступ из других классов: ... Rectangle.defaultColor ... Rectangle.scale ... © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Рассмотрим подробнее особенности реализации механизмов доступа к статическим полям и константам в языке программирования C#. Прежде всего, необходимо отметить следующее фундаментальное положение, характеризующее статические поля и константы. Поскольку изменения свойств объектов, динамических по своей природе и порожденных динамическими классами, не затрагивают статических полей и констант, последние принадлежат классам, а не объектам. Проиллюстрируем это высказывание следующим примером фрагмента программы на языке C#: class Rectangle { static Color defaultColor; //однократно для класса static readonly int scale; //однократно для класса // статические константы недопустимо использовать int x, y, width,height; //однократно для объекта ... }
Как видно из приведенного примера, при описании класса Rectangle со статическими полями Color и scale и динамическими полями x, y, width и height, статическими являются поля, инвариантные по отношению к классу, а динамическими – представляющие собой «неподвижную точку» относительно объекта. Доступ к статическим полям изнутри класса по краткому имени и из других классов по полному имени соответственно реализуется по аналогии с полями только для чтения: ... defaultColor ... scale ... ... Rectangle.defaultColor ... Rectangle.scale ...
Современные языки программирования и .NET: II семестр Лекция 8: Концепция инкапсуляции и ее реализация в языке C#
Доступ к методам в языке C# (1) class C { int sum = 0, n = 0; public void Add (int x) { // процедура sum = sum + x; n++; } public float Mean() { // функция (возвращает значение) return (float)sum / n; } }
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Продолжим иллюстрацию механизмов реализации концепции инкапсуляции в языке программирования C# следующим примером фрагмента программы: class C { int sum = 0, n = 0; public void Add (int x){ // процедура sum = sum + x; n++; } public float Mean() { // функция (возвращает значение) return (float)sum / n; } }
Приведенный пример представляет собой описание класса C, содержащего целочисленные поля sum и n, а также методы Add и Mean для суммирования и вычисления среднего значения, реализованные в форме процедуры и функции соответственно. Заметим, что методы Add и Mean класса C описаны как общедоступные и, следовательно, могут быть доступны из любого места программного проекта при указании полного имени, тогда как поля sum и n, в силу умолчаний, принятых в языке программирования C#, являются доступными локально (private). Заметим попутно, что функция (в терминологии языка C#) отличается от процедуры тем, что обязательно возвращает значение. Для определения процедуры, не возвращающей значения, в C# используется зарезервированное слово void.
Современные языки программирования и .NET: II семестр Лекция 8: Концепция инкапсуляции и ее реализация в языке C#
Доступ к методам в языке C# (2) Доступ изнутри класса: this.Add(3); float x = Mean(); Доступ из других классов: C c = new C(); c.Add(3); float x = c.Mean(); © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Проиллюстрируем сказанное об областях видимости объектов языка программирования C# примерами фрагментов программ. Предположим, что в предыдущем примере, описывающем общедоступный класс C, содержащего целочисленные поля sum и n, а также методы Add и Mean, необходимо организовать доступ к элементам класса изнутри, а также из других классов. Очевидно, что в силу общедоступности принципиально осуществимо.
реализации
класса
C
такое
задание
При реализации доступа к элементам класса C изнутри данного класса достаточно указать краткие имена объектов: this.Add(3); float x = Mean();
В то же время, при реализации механизма доступа к элементам класса C из других классов (внешних по отношению к данному) необходимо указывать полные имена объектов: C c = new C(); c.Add(3); float x = c.Mean();
Современные языки программирования и .NET: II семестр Лекция 8: Концепция инкапсуляции и ее реализация в языке C#
Доступ к статическим методам в языке C# Операции над данными классов (статическими полями): class Rectangle { static Color defaultColor; public static void ResetColor() { defaultColor = Color.white; } }
Доступ изнутри класса: ResetColor();
Доступ из других классов: Rectangle.ResetColor(); © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Манипулирование статическими полями и методами в языке программирования C# осуществляется вполне аналогично рассмотренным выше случаям статических полей и констант. Например, в случае, если класс, содержащий статические элементы данных, определяется посредством следующего описания: class Rectangle { static Color defaultColor; public static void ResetColor() { defaultColor = Color.white; } },
доступ к элементам данных изнутри класса осуществляется посредством указания краткого имени объекта класса, например: ResetColor();
а доступ к элементам данных из других классов – посредством указания полного имени объекта класса, например: Rectangle.ResetColor();
Современные языки программирования и .NET: II семестр Лекция 8: Концепция инкапсуляции и ее реализация в языке C#
Преимущества использования инкапсуляции: 1.
Унификация моделирования предметной области
2.
Прямолинейный подход к моделированию предметной области
3.
Гибкое управление уровнем абстракции данных (и метаданных)
4.
Безопасность и независимость от пользователя результирующего кода
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду По результатам исследования концепции инкапсуляции и ее применения в языках объектно-ориентированного программирования можно сделать следующие выводы о принципиальных преимуществах рассмотренной концепции. Прежде всего, реализация концепции инкапсуляции приводит к унификации представления, а, следовательно, и моделирования сколь угодно сложных предметных областей. Кроме того, механизм инкапсуляции обеспечивает четкий, недвусмысленный, прямолинейный подход к моделированию предметной области за счет объединения объектов с данными. .
Именно в силу последнего обстоятельства становится принципиально возможной реализация гибкого управления уровнем абстракции как для данных, так и для метаданных. Наконец, концепция инкапсуляции гарантирует более высокую степень безопасности результирующего кода и его защищенности от несанкционированных или нецеленаправленных действий пользователя.
Современные языки программирования и .NET: II семестр Лекция 8: Концепция инкапсуляции и ее реализация в языке C#
Библиография 1. 2. 3. 4. 5.
Pratt T.W., Zelkovitz M.V. Programming languages, design and implementation (4th ed.).- Prentice Hall, 2000 Appleby D., VandeKopple J.J. Programming languages, paradigm and practice (2nd ed.).- McGraw-Hill, 1997 Date C.J. Encapsulation is a Red Herring. DataBase Programming and Design On-LineFrei, Sept. 1998. (www.dbpd.com/9809date.htm ) Troelsen A. C# and the .NET platform (2nd ed.).- APress, 2003, 1200 p.p. Liberty J. Programming C# (2nd ed.).- O’Reilly, 2002, 656 p.p. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду К сожалению, в рамках времени, отведенных на одну лекцию, можно лишь в общих чертах охарактеризовать специфику такой фундаментальной концепции для каждого языка объектно-ориентированного программирования и для подхода в целом, как инкапсуляция. Для более детального ознакомления с особенностями, достижениями и проблемами в теории моделирования этой концепции и практики реализации связанных с ней механизмов рекомендуется следующий список литературы: 1.Pratt T.W., Zelkovitz M.V. Programming languages, design and implementation (4th ed.).Prentice Hall, 2000 2.Appleby D., VandeKopple J.J. Programming languages, paradigm and practice (2nd ed.).McGraw-Hill, 1997 3.Date C.J. Encapsulation is a Red Herring. DataBase Programming and Design On-LineFrei, Sept. 1998. (www.dbpd.com/9809date.htm ) 4.Troelsen A. C# and the .NET platform (2nd ed.).- APress, 2003, 1200 p.p. 5.Liberty J. Programming C# (2nd ed.).- O’Reilly, 2002, 656 p.p. Кратко остановимся на источниках. Кратко остановимся на источниках. В работе [1] приведен наиболее полный анализ истории развития и особенностей языков программирования с классификацией по областям применения. В работах [2,4,5] рассмотрены теоретические проблемы и практические аспекты реализации конструкций в языках программирования, прежде всего, в языке C#.NET, изучение которого составляет основу курса. Работа [3] представляет собой исследование концепции инкапсуляции в современном программировании.
Концепция полиморфизма и ее реализация в языке C#
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В данной лекции будут рассмотрены вопросы, относящиеся к истории развития, идеологии, математическому основанию и обзору возможностей полиморфизма – одной из фундаментальных концепций, на которых основано объектно-ориентированное программирование.
Современные языки программирования и .NET: II семестр Лекция 9: Концепция полиморфизма и ее реализация в языке C#
Содержание лекции 1.
Полиморфизм в computer science (механизм соотнесений)
2.
Полиморфизм в функциональном программировании и ООП
3.
Примеры полиморфизма в языках SML и C#
4.
Виды полиморфизма
5.
Абстрактные типы данных
6.
Методы вызова процедур
7.
Преимущества программирования с полиморфизмом
8.
Библиография © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Коротко о содержании лекции. В ходе лекции будут рассмотрены важнейшие научные исследования, относящиеся к эволюции подходов к математическому моделированию одной из важнейших для объектно-ориентированного подхода к программированию концепций аспекта, а именно, полиморфизма. Прежде всего, будет сформулировано определение понятия полиморфизма. Затем будет представлен сравнительный анализ путей реализации концепции языках функционального и объектно-ориентированного полиморфизма в программирования и в computer science. При этом будут подробно исследованы особенности различных видов полиморфизма. Особое внимание будет уделено реализации механизмов реализации абстрактных типов данных и вызова процедур в языке программирования C#, включая вызов по имени, по ссылке, а также «ленивое» означивание при вызове по необходимости. Фрагменты программ на языках SML и C# проиллюстрируют практику применения концепции полиморфизма и дадут возможность сопоставления особенностей ее реализации в зависимости от подхода. Лекция завершится обзором литературы для более глубокого исследования материала.
Современные языки программирования и .NET: II семестр Лекция 9: Концепция полиморфизма и ее реализация в языке C#
Основные результаты исследований полиморфизма 1934 – А. Черч (Alonso Church) изобрел ламбда-исчисление и исследовал порядок вычислений в ламбда-термах 1936 – Г. Плоткин (G.D. Plotkin) исследовал стратегии вызова по имени и по значению на основе ламбда-исчисления 1960’s – П.Лендин (Peter J. Landin) создал SECD-машину, математический формализм, моделирующий вызов по имени 1969 – Р.Хиндли (Roger Hindley) исследовал полиморфные системы с типами 1978 –Р.Милнер (Robin Milner) предложил расширенную систему полиморфной типизации для языка программирования ML 1989-90 – У.Кук, П.Кэннинг, У.Хилл и др. (William R. Cook, Peter S. Canning, Walter L. Hill et al.) исследовали полиморфизм в ООП и его связь с ламбда-исчислением © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Кратко остановимся на наиболее значительных (с точки зрения данного курса) этапах эволюции теории и практики реализации полиморфизма в формальных теориях и языках программирования. В 30-х г.г. А. Черч (Alonso Church) предложил исчисление ламбда-конверсий или ламбдаисчисление и применил его для исследования теории множеств. Вклад ученого был настолько фундаментальным, что теория (до сих пор называемая ламбда-исчислением и часто именуемая в литературе ламбда-исчислением Черча) является основополагающей и для рассматриваемых нами вопросов. Исследования различных стратегий передачи параметров при обращении к (полиморфным) функциям языков программирования (в частности, вызова функций по имени и по значению) на основе ламбда-исчисления были проведены Г. Плоткиным (G.D. Plotkin). Заметим, что полученные результаты значительно позднее (уже в 70-х г.г.) были использованы для моделирования вычислений в ранних версиях языка функционального программирования ML. В 60-х г.г., уже в эпоху высокоуровневых языков программирования, П. Лендином (Peter J. Landin) была разработана так называемая SECD-машина, а именно, математическая формализация для реализации вычислений в терминах ламбда-выражений. Кроме того, тем же автором был создан формальный язык ISWIM (If you See What I Mean), представляющий собой вариант расширенного ламбда-исчисления и ставший впоследствии прообразом языка программирования ML. В конце 60-х г.г. Р. Хиндли (Roger Hindley) исследовал полиморфные системы типов, т.е. такие системы типов, в которых возможны параметризованные функции или функции, имеющие переменный тип. При этом основной проблемой, стоящей перед исследователем, было моделирование языков программирования со строгой типизацией.
Затем, в 70-х г.г. Р. Милнер (Robin Milner) предложил практическую реализацию расширенной системы полиморфной типизации для языков функционального программирования. Наконец, на рубеже 80-х и 90-х г.г., рядом исследователей – У.Куком (William R. Cook), П.Кэннингом (Peter S. Canning), У.Хиллом (Walter L. Hill) и другими – была изучена концепция полиморфизма в приложении к объектно-ориентированному программированию (в частности, к языку C++) и выявлена возможность моделирования полиморфизма в ООП на основе ламбда-исчисления.
Современные языки программирования и .NET: II семестр Лекция 9: Концепция полиморфизма и ее реализация в языке C#
Понятие полиморфизма в программировании Вообще говоря, под полиморфизмом понимается возможность оперировать объектами, не обладая точным знанием их типов. В функциональном программировании и ООП понятие полиморфизма связано с: • • •
наследованием; интерфейсами; отложенным связыванием (“ленивыми” или “замороженными” вычислениями)
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду По рассмотрении теоретических оснований такой важнейшей концепции объектноориентированного программирования как полиморфизм, предпримем попытку формализовать это понятие. Под полиморфизмом будем иметь в виду возможность оперирования объектами без однозначной идентификации их типов. Напомним, что понятие полиморфизма уже исследовалось в части курса, посвященной функциональному подходу к программированию. Наметим концепции, объединяющие функциональный и объектно-ориентированный подходы к программированию с точки зрения полиморфизма. Как было отмечено в ходе исследования функционального подхода к программированию, концепция полиморфизма предполагает в части реализации отложенное связывание переменных со значениями. При этом во время выполнения программы происходят так называемые “ленивые” или, иначе, “замороженные” вычисления. Таким образом, означивание языковых идентификаторов выполняется по мере необходимости. В случае объектно-ориентированного подхода к программированию теоретический и практический интерес при исследовании концепции полиморфизма представляет отношение наследования, прежде всего, в том смысле, что это отношение порождает семейства полиморфных языковых объектов. С точки зрения практической реализации концепции полиморфизма в языке программирования C# в форме полиморфных функций особую значимость для исследования представляет механизм интерфейсов.
Современные языки программирования и .NET: II семестр Лекция 9: Концепция полиморфизма и ее реализация в языке C#
Полиморфизм типов в языке SML Встроенная функция hd для списка произвольного типа: hd [1, 2, 3]; val it = 1: int (тип функции: (int list) → int) hd [true, false, true, false]; val it = true: bool (тип: (bool list) → bool) hd [(1,2)(3,4),(5,6)]; val it = (1,2) : int*int ((int*int)list→(int*int)) Функция hd имеет тип (type list) →type, где type – произвольный тип © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Напомним, что реализация полиморфизма при функциональном подходе программированию основана на оперировании функциями переменного типа.
к
Для иллюстрации исследуем поведение встроенной функции hd, (от слова «head» – голова), которая выделяет «голову» (первый элемент) списка, вне зависимости от типа его элементов. Применим функцию к списку из целочисленных элементов: hd [1, 2, 3]; val it = 1: int Получим, что функция имеет тип функции из списка целочисленных величин в целое число (int list → int). В случае списка из значений истинности та же самая функция hd [true, false, true, false]; val it = true: bool возвращает значение истинности, т.е. имеет следующий тип: bool list → bool. Наконец, для случая списка кортежей из пар целых чисел hd [(1,2)(3,4),(5,6)]; val it = (1,2) : int*int
получим тип ((int*int)list→ (int*int)). В итоге можно сделать вывод о том, что функция hd имеет тип (type list) → type, где type – произвольный тип, т.е. полиморфна.
Современные языки программирования и .NET: II семестр Лекция 9: Концепция полиморфизма и ее реализация в языке C#
Полиморфизм типов в языке C# Рассмотрим пример полиморфной функции: void Poly(object o) { Console.WriteLine(o.ToString()); } а также примеры ее применения: Poly(25); Poly(“John Smith”); Poly(3.141592536m); Poly(new Point(12,45)); © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Проиллюстрируем сходные черты и особенности реализации концепции полиморфизма при функциональном и объектно-ориентированном подходе к программированию следующим примером фрагмента программы на языке C#: void Poly(object o) { Console.WriteLine(o.ToString()); } Как видно, приведенный пример представляет собой описание полиморфной функции Poly, которая выводит на устройство вывода (например, на экран) произвольный объект o, преобразованный к строковому формату (o.ToString()). Рассмотрим ряд примеров применения функции Poly: Poly(25); Poly(“John Smith”); Poly(3.141592536m); Poly(new Point(12,45)); Заметим, что независимо от типа аргумента (в первом случае это целое число 25, во втором – символьная строка “John Smith”, в третьем – вещественное число π=3.141592536, в четвертом – объект типа Point, т.е. точка на плоскости с
координатами (12,45)), обработка происходит единообразно и, как и в случае с языком функционального программирования SML, функция генерирует корректный результат.
Современные языки программирования и .NET: II семестр Лекция 9: Концепция полиморфизма и ее реализация в языке C#
Понятия, связанные с полиморфизмом в C# 1. Интерфейсы (функции с множеством элементов; четко определенные соглашения) 2. Типы (определяют на интерфейсы объектов и их реализацию; переменные также могут быть типизированными) 3. Наследование (классы и типы объединяются в иерархии базовых (или надклассов) и производных (или подклассов). Существуют определенные различия между наследованием интерфейсов и реализаций 4. Отложенное связывание или ленивые вычисления (значения присваиваются (связываются) объектам по мере того, как они требуются во время выполнения программы) © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Как видно из приведенных выше примеров, концепция полиморфизма одинаково применима как к функциональному, так и к объектно-ориентированному подходу к программированию. При этом целью полиморфизма является унификация обработки разнородных языковых объектов, которые в случае функционального подхода являются функциями, а в случае объектно-ориентированного – объектами переменного типа. Отметим, что для реализации полиморфизма в языке объектно-ориентированного программирования C# требуется четкое представление о ряде понятий и механизмов. Естественно, что говорить о полиморфизме можно только с учетом понятия типа. Типы определяют интерфейсы объектов и их реализацию. Переменные, функции и объекты в рассматриваемых в данном курсе языках программирования также рассматриваются как типизированные элементы. Необходимо также напомнить, что важное практическое значение при реализации полиморфизма в языке C# имеет механизм интерфейсов (под которыми понимаются чисто абстрактные классы с поддержкой полиморфизма, содержащие только описания без реализации). Для реализации концепции множественного наследования необходимо принять ряд дополнительных соглашений об интерфейсах. Сложно говорить о полиморфизме и в отрыве от концепции наследования, при принятии которой классы и типы объединяются в иерархические отношения частичного порядка из базовых классов (или, иначе, надклассов) и производных классов (или, иначе, подклассов). При этом существуют определенные различия между наследованием интерфейсов как частей, отвечающих за описания классов и частей, описывающих правила реализации. Еще одним значимым механизмом, сопряженным с полиморфизмом, является так называемое отложенное связывание (или, иначе, ленивые вычисления), в ходе которых
значения присваиваются объектам (т.е. связываются с ними) по мере того как, эти значения требуются во время выполнения программы.
Современные языки программирования и .NET: II семестр Лекция 9: Концепция полиморфизма и ее реализация в языке C#
Методы вызова процедур 1. Вызов по значению – call-by-value (в числе первых моделей computer science – абстрактная SECD-машина П.Лендина (Peter J.Lendin)) 2. Вызов по имени – call-by-name (или вызов по ссылке – call-by-reference) 3. Вызов по необходимости – call-by-need («ленивые» – “lazy”, «замороженные» –“frozen” или отложенные вычисления) © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Напомним классификацию стратегий вычислений, построенную в части курса, посвященной исследованию функционального подхода к программированию. При вычислении с вызовом по значению (call-by-value) все выражения должны быть означены до вычисления операции аппликации. Заметим, что формализация стратегии вычислений с вызовом по значению возникла в числе первых моделей computer science в виде абстрактной SECD-машины П.Лендина (Peter J.Lendin). При вычислении с вызовом по имени (call-by-name) до вычисления операции аппликации необходима подстановка термов вместо всех вхождений формальных параметров до означивания. Стратегию вычислений с вызовом по значению иначе принято называть вызовом по ссылке (call-by-reference). Наконец, при вычислении с вызовом по необходимости (call-by-need) ранее вычисленные значения аргументов сохраняются в памяти компьютера только в том случае, если необходимо их повторное использование. Именно эта стратегия лежит в основе «ленивых» (lazy), «отложенных» (delayed) или «замороженных» (frozen) вычислений, которые принципиально необходимы для обработки потенциально бесконечных структур данных.
Современные языки программирования и .NET: II семестр Лекция 9: Концепция полиморфизма и ее реализация в языке C#
Вызов по значению В случае вызова по значению (call-by-value, CBV): 1) формальный параметр является копией фактического параметра; 2) фактический параметр является выражением Пример использования (ввод значений) void Inc(int x) {x = x + 1;} void f() { int val = 3; Inc(val); // val == 3 © Учебный Центр безопасности информационных технологий Microsoft } Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Рассмотрим более подробно особенности стратегии вычислений с вызовом по значению (call-by-value, CBV). Прежде всего, в случае вызова по значению формальный параметр является копией фактического параметра и занимает выделенную область в памяти компьютера. Кроме того, фактический параметр в случае вызова по значению является выражением. Проиллюстрируем особенности использования следующим фрагментом программы на языке C#:
стратегии
вызова
по
значению
void Inc(int x) {x = x + 1;} void f() { int val = 3; Inc(val); // val == 3 } Как видно из приведенного примера, фрагмент программы на языке C# реализует ввод значений val посредством функции f. Функция Inc является функцией следования. Отметим, что несмотря на применение функции Inc к аргументу val, значение переменной val, как явствует из комментария // val == 3, остается неизменным. Это обусловлено тем обстоятельством, что при реализации стратегии вызова по значению формальный параметр является копией фактического.
Современные языки программирования и .NET: II семестр Лекция 9: Концепция полиморфизма и ее реализация в языке C#
Вызов по имени (ссылке) В случае вызова по имени (иначе по ссылке, или call-by-reference, CBR): 1) формальный параметр является подстановкой (alias) фактического параметра (передается адрес фактического параметра); 2) фактический параметр должен быть переменной, формальный параметр является копией фактического параметра Пример (преобразование значений): void Inc(ref int x) { x = x + 1; } void f() { int val = 3; Inc(ref val); // val == 4 } © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Рассмотрим более подробно особенности стратегии вычислений с вызовом по имени, или, иначе, по ссылке (call-by-reference, CBR). Прежде всего, в случае вызова по имени формальный параметр является подстановкой (alias) фактического параметра и не занимает отдельной области в памяти компьютера. При реализации данной стратегии вычислений вызывающей функции передается адрес фактического параметра. Кроме того, фактический параметр в случае вызова по имени должен быть не выражением, а переменной. При этом формальный параметр является копией фактического параметра. Проиллюстрируем особенности использования стратегии вызова по имени следующим фрагментом программы на языке C#: void Inc(ref int x) { x = x + 1; } void f() { int val = 3; Inc(ref val); // val == 4 } Как видно из приведенного примера, фрагмент программы на языке C# реализует преобразование значений val посредством функции f. Функция Inc является функцией следования. Отметим, что вследствие применения функции Inc к аргументу val, значение переменной val, как явствует из комментария // val == 4, изменяется. Это обусловлено тем обстоятельством, что при реализации стратегии вызова по имени формальный параметр является подстановкой фактического.
Современные языки программирования и .NET: II семестр Лекция 9: Концепция полиморфизма и ее реализация в языке C#
Вызов по необходимости В случае вызова по необходимости (call-by-need, CBN): 1) ситуация с параметром аналогична CBR, однако значение не передается вызывающей функции; 2) не следует использовать в методах до того, как значение будет получено Пример (ввод значений): void Read (out int first, out int next) { first = Console.Read(); next = Console.Read(); } void f() { int first, next; Read(out first, out next); } © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Рассмотрим более подробно особенности стратегии вычислений с вызовом по необходимости (call-by-need, CBN). В целом, данная стратегия вычислений сходна вызовом по имени (или ссылке, call-byreference, CBR), однако имеет ее реализация имеет две характерные особенности. Во-первых, в случае вызова по необходимости значение фактического параметра не передается вызывающей функции, т.е. не происходит связывания переменной со значением. Во-вторых, данная стратегия вычислений неприменима до того, как означивание может быть произведено, т.е. значение фактического параметра может быть получено. Проиллюстрируем особенности использования стратегии вызова по необходимости следующим фрагментом программы на языке C#: void Read (out int first, out int next) { first = Console.Read(); next = Console.Read(); } void f() { int first, next; Read(out first, out next); } Как видно из приведенного примера, фрагмент программы на языке C# реализует ввод значений first и next посредством функции Read со стандартного устройства ввода. Функция f может быть означена по необходимости, по мере поступления аргументов.
Современные языки программирования и .NET: II семестр Лекция 9: Концепция полиморфизма и ее реализация в языке C#
Абстрактные классы и методы в языке C# 1.Средство реализации концепции полиморфизма. 2.Абстрактные методы не имеют части реализации (implementation). 3. Абстрактные методы неявно являются виртуальными (virtual). 4. В случае, если класс имеет абстрактные методы, его необходимо описывать как абстрактный. 5. Запрещено создавать объекты абстрактных классов. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Исследовав особенности реализации различных стратегий вычислений в языке программирования C#, рассмотрим концепцию полиморфизма в соотнесении с механизмом так называемых абстрактных классов. Абстрактные классы при объектно-ориентированном подходе (в частности, в языке программирования C#) являются аналогами полиморфных функций в языках функционального программирования (в частности, в языке SML) и используются для реализации концепции полиморфизма. Методы, которые реализуют абстрактные классы, также называются абстрактными и являются полиморфными. Перечислим основные особенности, которыми обладают абстрактные классы и методы в рамках объектно-ориентированного подхода к программированию. Прежде всего, отметим то обстоятельство, что абстрактные методы не имеют части реализации (implementation). Кроме того, абстрактные методы неявно являются виртуальными (т.е. как бы оснащенными описателем virtual). В том случае, если внутри класса имеются определения абстрактных методов, данный класс необходимо описывать как абстрактный. Ограничений на количество методов внутри абстрактного класса в языке программирования C# не существует. Наконец, в языке программирования C# запрещено создание объектов абстрактных классов (как конкретизаций или экземпляров).
Современные языки программирования и .NET: II семестр Лекция 9: Концепция полиморфизма и ее реализация в языке C#
Абстрактные классы в языке C#: пример применения abstract class Stream { public abstract void Write(char ch); public void WriteString(string s) { foreach (char ch in s) Write(s); } } class File : Stream { public override void Write(char ch) { ... write ch to disk ... } } © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Проиллюстрируем особенности использования фрагментом программы на языке C#:
абстрактных
классов
следующим
abstract class Stream { public abstract void Write(char ch); public void WriteString(string s) { foreach (char ch in s) Write(s); } } class File : Stream { public override void Write(char ch) { ... write ch to disk ... } } Как видно из приведенного примера, фрагмент программы на языке C# представляет собой описание абстрактных классов Stream и File, реализующих потоковую запись (метод Write) данных в форме символьных строк ch. Заметим, что описание абстрактного класса Stream реализовано явно посредством зарезервированного слова abstract. Оператор foreach … in реализует последовательную обработку элементов и будет рассмотрен более подробно в продолжение курса. Необходимо обратить внимание на то обстоятельство, что поскольку в производных классах необходимо замещение методов, метод Write класса File оснащен описателем override.
Современные языки программирования и .NET: II семестр Лекция 9: Концепция полиморфизма и ее реализация в языке C#
Преимущества концепции полиморфизма 1.
Унификация обработки объектов различной природы
2.
Снижение стоимости программного обеспечения
3.
Повторное использование кода
4.
Интуитивная прозрачность исходного текста
4.
Строгое математическое основание (ламбда-исчисление)
5.
Концепция является универсальной и в равной степени применима в функциональном и объектноориентированном программировании © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Подводя итоги рассмотрения основных аспектов концепции полиморфизма в объектноориентированном подходе к программированию и особенностей реализации этой концепции применительно к языку программирования C#, кратко отметим достоинства полиморфизма. Прежде всего, к преимуществам концепции полиморфизма следует отнести унификацию обработки объектов различной природы. В самом деле, абстрактные классы и методы позволяют единообразно оперировать гетерогенными данными, причем для адаптации к новым классам и типам данных не требуется реализации дополнительного программного кода. Кроме того, важным практическим следствием реализации концепции полиморфизма для экономики программирования является снижение стоимости проектирования и реализации программного обеспечения. Еще одним существенным достоинством полиморфизма является возможность усовершенствования стратегии повторного использования кода. Код с более высоким уровнем абстракции не требует существенной модификации при адаптации к изменившимся условиям задачи или новым типам данных. Важно также отметить, что идеология полиморфизма основана на строгом математическом фундаменте (в частности, в виде формальной системы ламбдаисчисления), что обеспечивает интуитивную прозрачность исходного текста для математически мыслящего программиста, а также верифицируемость программного кода. Наконец, концепция полиморфизма является достаточно универсальной и в равной степени применима для различных подходов к программированию, включая функциональный и объектно-ориентированный.
Современные языки программирования и .NET: II семестр Лекция 9: Концепция полиморфизма и ее реализация в языке C#
Библиография (1) 1. 2. 3. 4.
Pratt T.W., Zelkovitz M.V. Programming languages, design and implementation (4th ed.).- Prentice Hall, 2000 Appleby D., VandeKopple J.J. Programming languages, paradigm and practice (2nd ed.).- McGraw-Hill, 1997 Milner R. A theory of type polymorphism in programming languages. Journal of Computer and System Science, 17(3):348-375, 1978 Canning P.S., Cook W.R., Hill W.L., Olthoff W., Mitchell J.C. F-bounded polymorphism for object-oriented programming.Conference on Functional Programming and Computer Architecture, 1989, p.p. 273-280 © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду К сожалению, в рамках времени, отведенных на одну лекцию, можно лишь в общих чертах охарактеризовать специфику такой фундаментальной концепции объектноориентированных языков, ООП, а также для целого ряда других подходов к программированию как полиморфизм. Рассмотрение более глубоких аспектов полиморфизма планируется в продолжение курса. Для более детального ознакомления с особенностями, достижениями и проблемами в теории моделирования этой концепции и практики реализации связанных с ней механизмов рекомендуется следующий список литературы: 1. Pratt T.W., Zelkovitz M.V. Programming languages, design and implementation (4th ed.).Prentice Hall, 2000 2. Appleby D., VandeKopple J.J. Programming languages, paradigm and practice (2nd ed.).McGraw-Hill, 1997 3. Milner R. A theory of type polymorphism in programming languages. Journal of Computer and System Science, 17(3):348-375, 1978 4. Canning P.S., Cook W.R., Hill W.L., Olthoff W., Mitchell J.C. F-bounded polymorphism for object-oriented programming. Conference on Functional Programming and Computer Architecture, 1989, p.p. 273-280 Кратко остановимся на источниках. В работе [1] приведен наиболее полный анализ истории развития и особенностей языков программирования с классификацией по областям применения. В работе [2] рассмотрены вопросы проектирования и реализации современных языков программирования. Работа [3] представляет собой исследование концепции полиморфизма в условиях функционального подхода к программированию.
Работа [4] посвящена исследованию применимости полиморфизма в функциональном программировании к ООП.
Современные языки программирования и .NET: II семестр Лекция 9: Концепция полиморфизма и ее реализация в языке C#
Библиография (2) 5.
6. 7. 8. 9.
Thorup L., Tofte M. Object-oriented programming and Standard ML. Proc. ACM SIGPLAN 1994 Workshop on ML and its applications, Orlando, FL, June 1994, Tech. Report 2265 INRIA, p.p. 41-49. Troelsen A. C# and the .NET platform (2nd ed.).- APress, 2003, 1200 p.p. Liberty J. Programming C# (2nd ed.).- O’Reilly, 2002, 656 p.p. Plotkin G.D. Call-by-name, call-by-value and the λ-calculus. Theoretical computer science, 1, pp. 125-159, 1936 Turner D.A. A new implementation technique for applicative languages. Software – Practice and Experience, 9:21-49, 1979 © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Продолжим обсуждение работ, посвященных исследованию теоретических основ и практической реализации концепции полиморфизма. 5. Thorup L., Tofte M. Object-oriented programming and Standard ML. Proc. ACM SIGPLAN 1994 Workshop on ML and its applications, Orlando, FL, June 1994, Tech. Report 2265 INRIA, p.p. 41-49 6. Troelsen A. C# and the .NET platform (2nd ed.).- APress, 2003, 1200 p.p. 7. Liberty J. Programming C# (2nd ed.).- O’Reilly, 2002, 656 p.p. 8. Plotkin G.D. Call-by-name, call-by-value and the λ-calculus. Theoretical computer science, 1, pp. 125-159, 1936 9. Turner D.A. A new implementation technique for applicative languages. Software – Practice and Experience, 9:21-49, 1979 Продолжим обсуждение библиографии. Работа [5] анализирует взаимосвязи полиморфизма в рамках объектно-ориентированного и функционального подхода к программированию и иллюстрирует их примерами программ на языках SML и C++. В работе [6] рассмотрены теоретические проблемы и практические аспекты реализации инновационных конструкций в языках программирования, прежде всего, в языке C#.NET, изучение которого составляет основу курса. В работе [7] рассматриваются вопросы, связанные с разработкой программ на языке C#. Работа [8] представляет собой сравнительное исследование стратегий вычислений в современном программировании. Работа [9] посвящена формализации полиморфизма средствами теоретического computer science.
Расширенные возможности полиморфизма в языке C#
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В данной лекции будут рассмотрены вопросы, относящиеся к истории развития, идеологии, математическому основанию и обзору расширенных возможностей полиморфизма – одной из фундаментальных концепций, на которых основано объектноориентированное программирование.
Современные языки программирования и .NET: II семестр Лекция 10: Расширенные возможности полиморфизма в языке C#
Содержание лекции 1. 2. 3. 4. 5. 6. 7. 8.
Абстрактные структуры данных в языках SML и C# Абстрактные методы, свойства и индексаторы в языке C# «Запечатанные» (sealed) классы в языке C# Динамическое и статическое связывание в языке C# Виртуальные классы и методы в языке C# Интерфейсы в языке C# и их связь с абстрактными классами Реализация интерфейсов на основе классов и структур Библиография © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Коротко о содержании лекции. В ходе лекции будут рассмотрены важнейшие научные исследования, относящиеся к эволюции подходов к математическому моделированию расширенных возможностей одного из важнейших для объектно-ориентированного подхода к программированию концепций аспекта, а именно, полиморфизма. Прежде всего, будет представлен сравнительный анализ путей реализации абстрактных структуры данных в языках SML и C#. Затем будут рассмотрены так называемые виртуальные классы и методы, а также способы представления абстрактных методов, свойств и индексаторов в языке программирования C#. При этом будут подробно исследованы особенности реализации так называемых «запечатанных» (sealed) классов. Кроме того, будет произведено сопоставление вариантов связывания объектов языка программирования C# с их значениями для динамического и статического случаев. Особое внимание будет уделено реализации механизмов абстрактных классов в языке программирования C# на основе использования механизма интерфейсов, причем будет рассмотрено применение интерфейсов на основе классов и структур. Фрагменты программ на языках программирования SML и C# проиллюстрируют практику использования концепции полиморфизма и дадут возможность сопоставления особенностей ее реализации в зависимости от подхода. Лекция завершится обзором литературы для более глубокого исследования материала.
Современные языки программирования и .NET: II семестр Лекция 10: Расширенные возможности полиморфизма в языке C#
Основные результаты исследований полиморфизма 1934 – А. Черч (Alonso Church) изобрел ламбда-исчисление и исследовал порядок вычислений в ламбда-термах 1936 – Г. Плоткин (G.D. Plotkin) исследовал стратегии вызова по имени и по значению на основе ламбда-исчисления 1960’s – П.Лендин (Peter J. Landin) создал SECD-машину, математический формализм, моделирующий вызов по имени 1969 – Р.Хиндли (Roger Hindley) исследовал полиморфные системы с типами 1978 –Р.Милнер (Robin Milner) предложил расширенную систему полиморфной типизации для языка программирования ML 1989-90 – У.Кук, П.Кэннинг, У.Хилл и др. (William R. Cook, Peter S. Canning, Walter L. Hill et al.) исследовали полиморфизм в ООП и его связь с ламбда-исчислением © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Кратко остановимся на наиболее значительных (с точки зрения данного курса) этапах эволюции теории и практики реализации полиморфизма в формальных теориях и языках программирования. Заметим, что рассматриваемая проблематика не раз затрагивалась нами в ходе изложения курса благодаря тому обстоятельству, что она является основополагающей для современного computer science. В 30-х г.г. А. Черч (Alonso Church) предложил исчисление ламбда-конверсий или ламбдаисчисление и применил его для исследования теории множеств. Вклад ученого был настолько фундаментальным, что теория (до сих пор называемая ламбда-исчислением и часто именуемая в литературе ламбда-исчислением Черча) является основополагающей и для рассматриваемых нами вопросов. Исследования различных стратегий передачи параметров при обращении к (полиморфным) функциям языков программирования (в частности, вызова функций по имени и по значению) на основе ламбда-исчисления были проведены Г. Плоткиным (G.D. Plotkin). Заметим, что полученные результаты значительно позднее (уже в 70-х г.г.) были использованы для моделирования вычислений в языках программирования. В 60-х г.г., уже в эпоху высокоуровневых языков программирования, П. Лендином (Peter J. Landin) была разработана так называемая SECD-машина, а именно, математическая формализация для реализации вычислений в терминах ламбда-выражений. Кроме того, тем же автором был создан формальный язык, представляющий собой вариант расширенного ламбда-исчисления и ставший впоследствии прообразом ряда языков программирования. В конце 60-х г.г. Р. Хиндли (Roger Hindley) исследовал полиморфные системы типов, т.е. такие системы типов, в которых возможны параметризованные функции или функции, имеющие переменный тип. При этом основной проблемой, стоящей перед исследователем, было моделирование языков программирования со строгой типизацией.
Затем, в 70-х г.г. Р. Милнер (Robin Milner) предложил практическую реализацию расширенной системы полиморфной типизации для языков программирования. Наконец, на рубеже 80-х и 90-х г.г., рядом исследователей – У.Куком (William R. Cook), П.Кэннингом (Peter S. Canning), У.Хиллом (Walter L. Hill) и другими – была изучена концепция полиморфизма в приложении к объектно-ориентированному программированию (в частности, к языку C++) и выявлена возможность моделирования полиморфизма в ООП на основе ламбда-исчисления.
Современные языки программирования и .NET: II семестр Лекция 10: Расширенные возможности полиморфизма в языке C#
Понятие полиморфизма в программировании Вообще говоря, под полиморфизмом понимается возможность оперировать объектами, не обладая точным знанием их типов. В функциональном программировании и ООП понятие полиморфизма связано с: • • •
наследованием; интерфейсами; отложенным связыванием (“ленивыми” или “замороженными” вычислениями)
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду По рассмотрении теоретических оснований такой важнейшей концепции объектноориентированного программирования как полиморфизм, предпримем попытку формализовать это понятие. Под полиморфизмом будем иметь в виду возможность оперирования объектами без однозначной идентификации их типов. Напомним, что понятие полиморфизма уже исследовалось в части курса, посвященной функциональному подходу к программированию. Наметим концепции, объединяющие функциональный и объектно-ориентированный подходы к программированию с точки зрения полиморфизма. Как было отмечено в ходе исследования функционального подхода к программированию, концепция полиморфизма предполагает в части реализации отложенное связывание переменных со значениями. При этом во время выполнения программы происходят так называемые “ленивые” или, иначе, “замороженные” вычисления. Таким образом, означивание языковых идентификаторов выполняется по мере необходимости. В случае объектно-ориентированного подхода к программированию теоретический и практический интерес при исследовании концепции полиморфизма представляет отношение наследования, прежде всего, в том отношении, что это отношение порождает семейства полиморфных языковых объектов. С точки зрения практической реализации концепции полиморфизма в языке программирования C# в форме полиморфных функций особую значимость для исследования представляет механизм интерфейсов.
Современные языки программирования и .NET: II семестр Лекция 10: Расширенные возможности полиморфизма в языке C#
Полиморфизм типов в языке SML Встроенная функция hd для списка произвольного типа: hd [1, 2, 3]; val it = 1: int (тип функции: (int list) → int) hd [true, false, true, false]; val it = true: bool (тип: (bool list) → bool) hd [(1,2)(3,4),(5,6)]; val it = (1,2) : int*int ((int*int)list→(int*int)) Функция hd имеет тип (type list) →type, где type – произвольный тип © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Напомним, что реализация полиморфизма при функциональном подходе программированию основана на оперировании функциями переменного типа.
к
Для иллюстрации исследуем поведение встроенной функции hd, (от слова «head» – голова), которая выделяет «голову» (первый элемент) списка, вне зависимости от типа его элементов. Применим функцию к списку из целочисленных элементов: hd [1, 2, 3]; val it = 1: int Получим, что функция имеет тип функции из списка целочисленных величин в целое число (int list → int). В случае списка из значений истинности та же самая функция hd [true, false, true, false]; val it = true: bool возвращает значение истинности, т.е. имеет следующий тип: bool list → bool. Наконец, для случая списка кортежей из пар целых чисел hd [(1,2)(3,4),(5,6)]; val it = (1,2) : int*int получим тип ((int*int)list→ (int*int)). В итоге можно сделать вывод о том, что функция hd имеет тип (type list) → type, где type – произвольный тип, т.е. полиморфна.
Современные языки программирования и .NET: II семестр Лекция 10: Расширенные возможности полиморфизма в языке C#
Полиморфизм типов в языке C# Рассмотрим пример полиморфной функции: void Poly(object o) { Console.WriteLine(o.ToString()); } а также примеры ее применения: Poly(25); Poly(“John Smith”); Poly(3.141592536m); Poly(new Point(12,45)); © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Проиллюстрируем сходные черты и особенности реализации концепции полиморфизма при функциональном и объектно-ориентированном подходе к программированию следующим примером фрагмента программы на языке C#: void Poly(object o) { Console.WriteLine(o.ToString()); } Как видно, приведенный пример представляет собой описание полиморфной функции Poly, которая выводит на устройство вывода (например, на экран) произвольный объект o, преобразованный к строковому формату (o.ToString()). Рассмотрим ряд примеров применения функции Poly: Poly(25); Poly(“John Smith”); Poly(3.141592536m); Poly(new Point(12,45)); Заметим, что независимо от типа аргумента (в первом случае это целое число 25, во втором – символьная строка “John Smith”, в третьем – вещественное число π=3.141592536, в четвертом – объект типа Point, т.е. точка на плоскости с координатами (12,45)), обработка происходит единообразно и, как и в случае с языком функционального программирования SML, функция генерирует корректный результат.
Современные языки программирования и .NET: II семестр Лекция 10: Расширенные возможности полиморфизма в языке C#
Абстрактные классы в языке C# 1.Средство реализации концепции полиморфизма. 2.Абстрактные методы не имеют части реализации (implementation). 3. Абстрактные методы неявно являются виртуальными (virtual). 4. В случае, если класс имеет абстрактные методы, его необходимо описывать как абстрактный. 5. Запрещено создавать объекты абстрактных классов. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Исследовав особенности реализации различных стратегий вычислений в языке программирования C#, рассмотрим концепцию полиморфизма в соотнесении с механизмом так называемых абстрактных классов. Абстрактные классы при объектно-ориентированном подходе (в частности, в языке программирования C#) являются аналогами полиморфных функций в языках функционального программирования (в частности, в языке SML) и используются для реализации концепции полиморфизма. Методы, которые реализуют абстрактные классы, также называются абстрактными и являются полиморфными. Перечислим основные особенности, которыми обладают абстрактные классы и методы в рамках объектно-ориентированного подхода к программированию. Прежде всего, отметим то обстоятельство, что абстрактные методы не имеют части реализации (implementation). Кроме того, абстрактные методы неявно являются виртуальными (т.е. как бы оснащенными описателем virtual). В том случае, если внутри класса имеются определения абстрактных методов, данный класс необходимо описывать как абстрактный. Ограничений на количество методов внутри абстрактного класса в языке программирования C# не существует. Наконец, в языке программирования C# запрещено создание объектов абстрактных классов (как конкретизаций или экземпляров).
Современные языки программирования и .NET: II семестр Лекция 10: Расширенные возможности полиморфизма в языке C#
Абстрактные классы в языке C#: пример применения abstract class Stream { public abstract void Write(char ch); public void WriteString(string s) { foreach (char ch in s) Write(s); } } class File : Stream { public override void Write(char ch) { ... write ch to disk ... } } © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Проиллюстрируем особенности использования фрагментом программы на языке C#:
абстрактных
классов
следующим
abstract class Stream { public abstract void Write(char ch); public void WriteString(string s) { foreach (char ch in s) Write(s); } } class File : Stream { public override void Write(char ch) { ... write ch to disk ... } } Как видно из приведенного примера, фрагмент программы на языке C# представляет собой описание абстрактных классов Stream и File, реализующих потоковую запись (метод Write) данных в форме символьных строк ch. Заметим, что описание абстрактного класса Stream реализовано явно посредством зарезервированного слова abstract. Оператор foreach … in реализует последовательную обработку элементов. Необходимо обратить внимание на то обстоятельство, что поскольку в производных классах необходимо замещение методов, метод Write класса File оснащен описателем override.
Современные языки программирования и .NET: II семестр Лекция 10: Расширенные возможности полиморфизма в языке C#
Абстрактные свойства и методы в языке С# (пример) abstract class Sequence { public abstract void Add(object x); // метод public abstract string Name { get; } // свойство public abstract object this [int i] {get;set;} // индексатор } class List : public public public {...} } }
Sequence override override override
{ void Add(object x) {...} string Name { get {...} } object this [int i] { get {...} set
© Microsoft Information Security and Technology Training Center Moscow Engineering Physics Institute (State University), 2003
Комментарий к слайду Проиллюстрируем особенности использования следующим фрагментом программы на языке C#:
абстрактных
свойств
и
методов
abstract class Sequence { public abstract void Add(object x); // метод public abstract string Name { get; } // свойство public abstract object this [int i] {get;set;} // индексатор } class List : Sequence { public override void Add(object x) {...} public override string Name { get {...} } public override object this [int i] { get {...} set {...} } } Как видно из приведенного примера, фрагмент программы на языке C# представляет собой описание абстрактного класса Sequence и List, реализующих потоковое чтение и запись данных (get и set). Заметим, что описание абстрактного класса Sequence реализовано явно посредством зарезервированного слова abstract. Необходимо обратить внимание на то обстоятельство, что поскольку в производных классах необходимо замещение методов, методы Add и Name класса List оснащены описателем override.
Современные языки программирования и .NET: II семестр Лекция 10: Расширенные возможности полиморфизма в языке C#
«Запечатанные» классы в языке C#
1) 2)
«Запечатанными» (sealed) называют нерасширяемые классы, которые могут наследовать свойства других классов. Замещенные (override) методы могут описываться как sealed в индивидуальном порядке. Такого рода решения возможны по следующим соображениям: безопасность (предотвращается изменение семантики класса); эффективность (методы могут вызываться путем статического связывания) sealed class Account : Asset { long val; public void Deposit (long x) { ... } public void Withdraw (long x) { ... } ... © Учебный Центр безопасности информационных технологий Microsoft }
Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Еще одним средством реализации расширенного полиморфизма в языке программирования C# является механизм, известный под названием «запечатанных» (sealed) классов. Под «запечатанными» классами будем понимать нерасширяемые классы, которые могут наследовать свойства других классов. Решение об использовании механизма «запечатывания» при описании приоритетных или, иначе, замещенных (override) методов принимается в индивидуальном порядке. Рассмотрим соображения, обосновывающие использование механизма «запечатанных» классов в языке программирования C#. Прежде всего, благодаря реализации данного механизма предотвращается изменение семантики класса. Таким образом существенно повышается безопасность разрабатываемого программного обеспечения. Кроме того, за счет того, что вызов «запечатанных» методов предполагает использование статического связывания, значительно возрастает эффективность реализуемых приложений. Проиллюстрируем особенности использования механизма «запечатанных» классов следующим фрагментом программы на языке C#: sealed class Account : Asset { long val; public void Deposit (long x) { ... } public void Withdraw (long x) { ... } ... } Как видно из приведенного примера, фрагмент программы на языке C# представляет собой описание «запечатанного» класса Account, реализующего абстрактные методы Deposit и Withdraw для занесения средств на счет и их снятия со счета.
Современные языки программирования и .NET: II семестр Лекция 10: Расширенные возможности полиморфизма в языке C#
Основы динамического связывания в языке C# (1) class A { public virtual void WhoAreYou() { Console.WriteLine("I am an A"); } } class B : A { public override void WhoAreYou() { Console.WriteLine("I am a B"); } }
Сообщение запускает метод, который динамически определяет принадлежность к классу A a = new B(); a.WhoAreYou();
// "I am a B"
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В ходе курса уже обсуждалась стратегия динамического связывания переменных со значениями при функциональном и объектно-ориентированном подходах. Проиллюстрируем особенности реализации динамического программирования C# следующим фрагментом программы: class A {
связывания
в
языке
public virtual void WhoAreYou() { Console.WriteLine("I am an A"); }
} class B : A { public override void WhoAreYou() { Console.WriteLine("I am a B"); } }
Как видно из приведенного примера, данный фрагмент программы содержит описания класса A с виртуальным методом WhoAreYou, который выводит на стандартное устройство вывода сообщение о принадлежности к классу A, а также замещенного класса B с виртуальным методом WhoAreYou, который выводит на стандартное устройство вывода сообщение о принадлежности к классу B. При таком подходе сообщение запускает метод, который динамически определяет принадлежность к классу (в приведенном ниже примере создается и идентифицируется объект класса B): A a = new B(); a.WhoAreYou();
// "I am a B"
Современные языки программирования и .NET: II семестр Лекция 10: Расширенные возможности полиморфизма в языке C#
Основы динамического связывания в языке C# (2) Каждый из методов, который способен обрабатывать объект класса A, способен также обрабатывать объект класса B (см. следующий пример): void Use (A x) { x.WhoAreYou(); } Use(new A()); // " I am an A" Use(new B()); // " I am a B" © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Заметим, что существенной особенностью рассматриваемого примера является то обстоятельство, что B – это замещенный метод. В этой связи, каждый из методов, который способен обрабатывать A, способен также обрабатывать B. Проиллюстрируем этот факт следующим фрагментом программы на языке C#: void Use (A x) { x.WhoAreYou(); } Use(new A()); // " I am an A" Use(new B()); // " I am a B" Как видно из приведенного фрагмента программы, применение метода Use, реализующего идентификацию объекта класса A, приводит к результату для объекта " I am an A" класса A и к результату " I am a B" для объекта класса B. Корректность получаемого результата для класса B (несмотря на детерминированное описание класса A как параметра метода Use) объясняется тем обстоятельством, что класс B является замещенным.
Современные языки программирования и .NET: II семестр Лекция 10: Расширенные возможности полиморфизма в языке C#
Преимущества концепции полиморфизма 1.
Унификация обработки объектов различной природы
2.
Снижение стоимости программного обеспечения
3.
Повторное использование кода
4.
Интуитивная прозрачность исходного текста
5.
Строгое математическое основание (ламбда-исчисление)
6.
Концепция является универсальной и в равной степени применима в функциональном и объектноориентированном программировании © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Подводя промежуточные итоги рассмотрения основных аспектов расширенных возможностей концепции полиморфизма в объектно-ориентированном подходе к программированию и особенностей реализации этой концепции применительно к языку программирования C#, кратко отметим достоинства полиморфизма. Прежде всего, к преимуществам концепции полиморфизма следует отнести унификацию обработки объектов различной природы. В самом деле, абстрактные классы и методы позволяют единообразно оперировать гетерогенными данными, причем для адаптации к новым классам и типам данных не требуется реализации дополнительного программного кода. Кроме того, важным практическим следствием реализации концепции полиморфизма для экономики программирования является снижение стоимости проектирования и реализации программного обеспечения. Еще одним существенным достоинством полиморфизма является возможность усовершенствования стратегии повторного использования кода. Код с более высоким уровнем абстракции не требует существенной модификации при адаптации к изменившимся условиям задачи или новым типам данных. Важно также отметить, что идеология полиморфизма основана на строгом математическом фундаменте (в частности, в виде формальной системы ламбдаисчисления), что обеспечивает интуитивную прозрачность исходного текста для математически мыслящего программиста, а также верифицируемость программного кода. Наконец, концепция полиморфизма является достаточно универсальной и в равной степени применима для различных подходов к программированию, включая функциональный и объектно-ориентированный.
Современные языки программирования и .NET: II семестр Лекция 10: Расширенные возможности полиморфизма в языке C#
Сокрытие в языке C# Экземпляры могут быть описаны как new в подклассе. Они скрывают одноименные наследуемые экземпляры. class A { public int x; public void F() {...} public virtual void G() {...} } class B : A { public new int x; public new void F() {...} public new void G() {...} } B b = new B(); b.x = ...; b.F(); ... b.G(); ((A)b).x = ...; ((A)b).F(); ... ((A)b).G();
// // // //
имеет доступ вызывает B.F имеет доступ вызывает A.F
к и к и
B.x B.G A.x A.G
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Рассмотрим особенности реализации сокрытия данных в языке программирования C#. Заметим, что в языке C# существует возможность описания объектов как экземпляров в составе подкласса с использованием зарезервированного слова new. При этом происходит сокрытие одноименных наследуемых экземпляров в подклассах. Проиллюстрируем особенности использования механизма сокрытия данных в языке программирования C# следующим фрагментом программы: class A {
public int x; public void F() {...} public virtual void G() {...}
} class B : A { public new int x; public new void F() public new void G() } B b = new B(); b.x = ...; b.F(); ... b.G(); ((A)b).x = ...; ((A)b).F(); ... ((A)b).G();
{...} {...} // имеет доступ к B.x // вызывает B.F и B.G // имеет доступ к A.x // вызывает A.F и A.G
Как видно из приведенного фрагмента программы, базовый класс A и производный класс B характеризуются общедоступными полем x и методами F и G. Особенности доступа к элементам классов приведены в комментариях. Заметим, что при описании элементов производного класса используется зарезервированное слово new.
Современные языки программирования и .NET: II семестр Лекция 10: Расширенные возможности полиморфизма в языке C#
Сложное (с сокрытием) динамическое связывание в языке C# (1) class A { public virtual void WhoAreYou(){ Console.WriteLine("I am an A"); } } class B : A { public override void WhoAreYou(){ Console.WriteLine("I am a B"); } } class C : B { public new virtual void WhoAreYou() { Console.WriteLine("I am a C"); } © Учебный Центр безопасности информационных технологий Microsoft } Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Рассмотрим особенности реализации сложного динамического связывания в языке программирования C#. Под сложным связыванием будем понимать связывание с сокрытием (hiding) данных. Для детальной иллюстрации особенностей использования механизма сокрытия данных воспользуемся следующим фрагментом программы в качестве развернутого примера на языке C#. Приведем начало примера: class A { public virtual void WhoAreYou(){ Console.WriteLine("I am an A"); } } class B : A { public override void WhoAreYou(){ Console.WriteLine("I am a B"); } } class C : B { public new virtual void WhoAreYou() { Console.WriteLine("I am a C"); } } Как видно из первой части примера, фрагмент программы содержит описания общедоступных классов: базового класса A и производных классов B и C с иерархией C ISA B ISA A. Каждый из классов характеризуется единственным общедоступным методом WhoAreYou для вывода в стандартный поток диагностического сообщения о принадлежности к данному классу. Заметим, что методы WhoAreYou для классов A и C описаны как виртуальные, причем в последнем описании используется зарезервированное слово new. Метод WhoAreYou для класса B описан как замещенный.
Современные языки программирования и .NET: II семестр Лекция 10: Расширенные возможности полиморфизма в языке C#
Сложное (с сокрытием) динамическое связывание в языке C# (2) class D : C { public override void WhoAreYou(){ Console.WriteLine("I am a D"); } } C c = new D(); c.WhoAreYou();
// "I am a D"
A a = new D(); a.WhoAreYou();
// "I am a B"
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Продолжим изложение развернутого примера, демонстрирующего сложное динамическое связывание в языке программирования C#. Приведем окончание примера на языке C#: class D : C { public override void WhoAreYou(){ Console.WriteLine("I am a D"); } } C c = new D(); c.WhoAreYou(); // "I am a D" A a = new D(); a.WhoAreYou(); // "I am a B" Как видно из заключительной части примера, фрагмент программы содержит описание общедоступного класса D как производного от C. Таким образом, иерархия классов принимает вид: D ISA C ISA B ISA A. Класс D характеризуется аналогичным предыдущим классам общедоступным методом WhoAreYou для вывода в стандартный поток диагностического сообщения о принадлежности к данному классу. Заметим, что метод WhoAreYou для класса D является замещенным (но не виртуальным), и в его описании не используется зарезервированное слово new. При инициализации объектов c и a как экземпляров класса D, применение «отладочных» методов дает результат "I am a D" для объекта c и результат "I am a B" для объекта a. Полученный результат объясняется расположением описателей методов override в иерархии классов (более верхний описатель имеет более высокий приоритет).
Современные языки программирования и .NET: II семестр Лекция 10: Расширенные возможности полиморфизма в языке C#
Требования к методам с приоритетами: • • •
1. Идентичность описаний: одинаковые количество и типы параметров (включая типы функций); одинаковые области видимости (public, protected, ...). 2. Свойства и индексаторы также могут иметь приоритет (virtual, override). 3. Статические методы не могут иметь приоритета. 4. Только методы, описанные как виртуальные, могут иметь приоритет в производных классах. 5. Методы с приоритетами необходимо описывать как override © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Дальнейшим развитием динамического связывания в языке программирования C# является реализация механизма вызова методов с приоритетами. При реализации рассматриваемого механизма на взаимосвязанные семейства методов накладывается ряд дополнительных ограничений. Прежде всего, требуется обеспечить идентичность описаний методов в группе с приоритетами. При этом для каждого из методов должны выполняться следующие условия. Во-первых, у всех методов семейства для вызова с приоритетами должны быть одинаковыми как количество параметров, так и типы этих параметров. Типы функций не должны составлять исключение из этого правила. Во-вторых, все методы семейства для вызова с приоритетами должны иметь одинаковые области видимости (например, каждый из методов семейства должен иметь описатель public или, скажем, protected; однако, наличие в семействе методов с разными описателями области видимости не допускается). Кроме того, необходимо отметить, что свойства и индексаторы для семейства методов с приоритетами также могут иметь приоритет (с использованием описателя override). Поскольку метод с приоритетами является принципиально динамическим объектом языка программирования, статические методы не могут описываться как методы с приоритетами. Заметим, что только методы, описанные как виртуальные (virtual), могут иметь приоритет в производных классах. Наконец, при задании методов с приоритетами необходимо использовать описатель override.
Современные языки программирования и .NET: II семестр Лекция 10: Расширенные возможности полиморфизма в языке C#
Пример применения методов с приоритетами class A { public void F() {...} // может иметь приоритет public virtual void G() {...} // может иметь приоритет в подклассе } class B : A { public void F() {...} // предупреждение: скрывается производный метод F() -> необходимо использовать оператор new public void G() {...} // предупреждение: скрывается производный метод G() -> необходимо использовать оператор new public override void G() { // ok: перекрывает приоритетом производный G ... base.G(); // вызов производного G() } © Учебный Центр безопасности информационных технологий Microsoft } Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Проиллюстрируем особенности использования механизма методов с приоритетами в языке программирования C# следующим фрагментом программы: class A { public void F() {...} // может иметь приоритет public virtual void G() {...} // может иметь приоритет в подклассе } class B : A { public void F() {...} // предупреждение: скрывается производный метод F() -> необходимо использовать оператор new public void G() {...} // предупреждение: скрывается производный метод G() -> необходимо использовать оператор new public override void G() { // ok: перекрывает приоритетом производный G ... base.G(); // вызов производного G() } } Как видно из приведенного примера, фрагмент программы содержит описания базового класса A и производного класса B, каждый из которых содержит общедоступные методы F и G. При этом метод G класса использует описатель virtual. Как следует из комментариев, при задании методов F и G в производном классе B без использования описателя override происходит сокрытие производных методов F и G. Таким образом, для корректной работы F и G в классе необходимо использовать оператор new. В случае использования описателя override при задании метода G в классе B, происходит замещение приоритетным методом G и, таким образом, оператор new не требуется.
Современные языки программирования и .NET: II семестр Лекция 10: Расширенные возможности полиморфизма в языке C#
Понятие интерфейса в языке C# Под интерфейсом понимается чисто абстрактный класс, содержащий только описания без реализации. Свойства интерфейсов: 1) могут содержать методы, свойства, индексаторы и события (но не поля, константы, конструкторы, деструкторы, операторы и вложенные типы); 2) все элементы являются общедоступными и абстрактными (виртуальными); 3) ни один из элементов не может быть статическим; 4) множественные наследования могут реализовываться классами и структурами; 5) интерфейсы могут расширяться другими интерфейсами. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В ходе изложения курса неоднократно упоминалось понятие интерфейса. На данном этапе исследований становится возможным произвести детальное рассмотрение данного механизма и рассмотреть особенности его реализации применительно к языку программирования C#. Под интерфейсом будем понимать чисто абстрактный класс, который содержит только описания языковых объектов и не содержит части, отвечающей за реализацию (implementation). При реализации рассматриваемого механизма необходимо обеспечить выполнение следующих условий. Прежде всего, требуется, чтобы в состав интерфейсов входили только такие объекты языка как методы, свойства, индексаторы и события. Интерфейсы не могут содержать полей, констант, конструкторов, деструкторов, операторов и вложенных типов. Кроме того, все элементы интерфейсов должны быть описаны как общедоступные (public) и абстрактные виртуальные (virtual). В состав интерфейсов не могут входить статические элементы. Механизм множественного наследования, рассмотренный ранее в ходе курса, может быть реализован посредством классов и структур (далее будет рассмотрен еще один пример подобного рода наследования). Заметим также, что произвольный интерфейс может быть расширен посредством одного или нескольких интерфейсов.
Современные языки программирования и .NET: II семестр Лекция 10: Расширенные возможности полиморфизма в языке C#
Пример интерфейса Рассмотрим следующий пример интерфейса: public interface IList : ICollection, IEnumerable { int Add (object value); // методы bool Contains (object value); ... bool IsReadOnly { get; } // свойство ... object this [int index] { get; set; } // индексатор } © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Проиллюстрируем особенности использования механизма методов с приоритетами в языке программирования C# следующим фрагментом программы: public interface IList : ICollection, IEnumerable { int Add (object value); // методы bool Contains (object value); ... bool IsReadOnly { get; } // свойство ... object this [int index] { get; set; } // индексатор } Как видно из приведенного примера, фрагмент программы на языке C# содержит описание общедоступного интерфейса IList на основе стандартных классов ICollection и IEnumerable. Интерфейс моделирует списковую структуру данных и оснащен методами Add для добавления объекта в список, Contains для установления принадлежности объекта списку и IsReadOnly для определения возможности записи в список (а, возможно, и рядом других методов), тем или иным набором свойств, а также индексатором.
Современные языки программирования и .NET: II семестр Лекция 10: Расширенные возможности полиморфизма в языке C#
Реализация интерфейса на основе классов и структур Сформулируем требования к реализации интерфейсов: 1. Класс может наследовать свойства единственного базового класса и при этом реализовывать множественные интерфейсы. 2. Структура может наследовать свойства любого типа и при этом реализовывать множественные интерфейсы. 3. Каждый элемент интерфейса (метод, свойство, индексатор) может реализовать или наследовать свойства класса. 4. Реализованные методы интерфейса нельзя описывать как override. 5. Реализованные методы интерфейса можно описывать как virtual или abstract (т.е. интерфейс может быть реализован посредством абстрактного класса). © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Рассмотрим более подробно особенности реализации множественного наследования в языке программирования C#. Для достижения этой цели потребуется применить механизм интерфейсов для классов и структур. Сформулируем требования, необходимые для реализации данного варианта механизма интерфейсов. Прежде всего, следует потребовать, чтобы класс имел возможность наследования свойств лишь единственного базового класса. Однако, при этом класс должен иметь возможность реализации множественных интерфейсов. Кроме того, необходимо выдвинуть условия для структур, которые сводятся к следующему. Структура может наследовать свойства любого типа данных и при этом имеет возможность реализации множественных интерфейсов. Подчеркнем, что важным свойством элементов, входящих в состав интерфейса (в частности, методов, свойств и индексаторов) является возможность реализации или наследования свойств порождающего их класса. Заметим далее, что реализованные методы интерфейса не могут быть замещенными, т.е. задаваться с помощью описателя override. Наконец, методы, которые реализуются посредством интерфейса, могут снабжаться одним из описателей virtual либо abstract. Таким образом, осуществляется возможность реализации механизма интерфейсов на основе абстрактного класса.
Современные языки программирования и .NET: II семестр Лекция 10: Расширенные возможности полиморфизма в языке C#
Пример реализации интерфейса на основе классов и структур Рассмотрим следующий пример реализации интерфейса на основе классов и структур: class MyClass : MyBaseClass, IList, ISerializable { public int Add (object value) {...} public bool Contains (object value) {...} ... public bool IsReadOnly { get {...} } ... public object this [int index] { get {...} set {...} } } © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Проиллюстрируем особенности использования механизма методов с приоритетами в языке программирования C# следующим фрагментом программы: class MyClass : MyBaseClass, IList, ISerializable { public int Add (object value) {...} public bool Contains (object value) {...} ... public bool IsReadOnly { get {...} } ... public object this [int index] { get {...} set {...} } } Как видно из приведенного примера, фрагмент программы на языке C# содержит описание общедоступного интерфейса IList на основе стандартных классов ICollection и IEnumerable. Данный пример во многом схож фундаментальное отличие от него.
с
предыдущим,
однако
имеет
следующее
Отличие заключается в том, что интерфейс IList в данном примере реализуется на основе некоторого базового класса MyBaseClass, определенного пользователем. При этом интерфейс IList в данном примере фактически получает возможность множественного наследования. Заметим, что ни один из методов интерфейса Ilist не является замещенным.
Современные языки программирования и .NET: II семестр Лекция 10: Расширенные возможности полиморфизма в языке C#
Библиография (1) 1. 2. 3. 4.
Pratt T.W., Zelkovitz M.V. Programming languages, design and implementation (4th ed.).- Prentice Hall, 2000 Appleby D., VandeKopple J.J. Programming languages, paradigm and practice (2nd ed.).- McGraw-Hill, 1997 Milner R. A theory of type polymorphism in programming languages. Journal of Computer and System Science, 17(3):348-375, 1978 Canning P.S., Cook W.R., Hill W.L., Olthoff W., Mitchell J.C. F-bounded polymorphism for object-oriented programming.Conference on Functional Programming and Computer Architecture, 1989, p.p. 273-280 © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду К сожалению, в рамках времени, отведенных на одну лекцию, можно лишь в общих чертах охарактеризовать специфику такой фундаментальной концепции объектноориентированных языков, ООП, а также для целого ряда других подходов к программированию как полиморфизм. Для более детального ознакомления с особенностями, достижениями и проблемами в теории моделирования этой концепции и практики реализации связанных с ней механизмов рекомендуется следующий список литературы: 1. Pratt T.W., Zelkovitz M.V. Programming languages, design and implementation (4th ed.).Prentice Hall, 2000 2. Appleby D., VandeKopple J.J. Programming languages, paradigm and practice (2nd ed.).McGraw-Hill, 1997 3. Milner R. A theory of type polymorphism in programming languages. Journal of Computer and System Science, 17(3):348-375, 1978 4. Canning P.S., Cook W.R., Hill W.L., Olthoff W., Mitchell J.C. F-bounded polymorphism for object-oriented programming. Conference on Functional Programming and Computer Architecture, 1989, p.p. 273-280 Кратко остановимся на источниках. В работе [1] приведен наиболее полный анализ истории развития и особенностей языков программирования с классификацией по областям применения. В работе [2] рассмотрены вопросы проектирования и реализации современных языков программирования. Работа [3] представляет собой исследование концепции полиморфизма в условиях функционального подхода к программированию. Работа [4] посвящена исследованию применимости полиморфизма в функциональном программировании к ООП.
Современные языки программирования и .NET: II семестр Лекция 10: Расширенные возможности полиморфизма в языке C#
Библиография (2) 5.
6. 7. 8. 9.
Thorup L., Tofte M. Object-oriented programming and Standard ML. Proc. ACM SIGPLAN 1994 Workshop on ML and its applications, Orlando, FL, June 1994, Tech. Report 2265 INRIA, p.p. 41-49 Troelsen A. C# and the .NET platform (2nd ed.).- APress, 2003, 1200 p.p. Liberty J. Programming C# (2nd ed.).- O’Reilly, 2002, 656 p.p. Plotkin G.D. Call-by-name, call-by-value and the λ-calculus. Theoretical computer science, 1, pp. 125-159, 1936 Turner D.A. A new implementation technique for applicative languages. Software – Practice and Experience, 9:21-49, 1979 © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Продолжим обсуждение работ, посвященных исследованию теоретических основ и практической реализации концепции полиморфизма. 5. Thorup L., Tofte M. Object-oriented programming and Standard ML. Proc. ACM SIGPLAN 1994 Workshop on ML and its applications, Orlando, FL, June 1994, Tech. Report 2265 INRIA, p.p. 41-49 6. Troelsen A. C# and the .NET platform (2nd ed.).- APress, 2003, 1200 p.p. 7. Liberty J. Programming C# (2nd ed.).- O’Reilly, 2002, 656 p.p. 8. Plotkin G.D. Call-by-name, call-by-value and the λ-calculus. Theoretical computer science, 1, pp. 125-159, 1936 9. Turner D.A. A new implementation technique for applicative languages. Software – Practice and Experience, 9:21-49, 1979 Работа [5] анализирует взаимосвязи полиморфизма в рамках объектно-ориентированного и функционального подходов к программированию и иллюстрирует их примерами программ на языках SML и C++. В работе [6] рассмотрены теоретические проблемы и практические аспекты реализации инновационных конструкций в языках программирования, прежде всего, в языке C#.NET, изучение которого составляет основу курса. В работе [7] рассматриваются вопросы, связанные с разработкой программ на языке C#. Работа [8] представляет собой сравнительное исследование стратегий вычислений в современном программировании. Работа [9] посвящена формализации полиморфизма средствами теоретического computer science.
Событийно управляемое программирование в .NET
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В данной лекции будут рассмотрены вопросы, относящиеся к истории развития, идеологии, математическому основанию и обзору возможностей событийно управляемого проектирования и реализации программных систем – одного из важнейших аспектов современного объектно-ориентированного программирования.
Современные языки программирования и .NET: II семестр Лекция 11: Событийно управляемое программирование в .NET
Содержание лекции 1. 2. 3. 4. 5. 6. 7. 8. 9.
Понятие события в математике и программировании Методы моделирования событий Фреймы и функции как модели событий Делегаты в языке C# Конструкторы для делегатов в языке C# Делегаты с множественным вызовом в языке C# События как особый вид делегатов Исключения и их обработка в языке C# Библиография © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Коротко о содержании лекции. В ходе лекции будут рассмотрены важнейшие научные исследования, относящиеся к эволюции подходов к математическому моделированию такого важнейшего для объектноориентированного подхода к программированию аспекта как управление событиями. Прежде всего, будет представлено сопоставление понятий о событии в математической теории и практике программирования. Затем будут рассмотрены наиболее продуктивные (с точки зрения целей данного курса) методы моделирования событий. При этом будут подробно исследованы особенности формализации событий посредством функций и фреймов. Существенное внимание будет уделено реализации так называемого механизма делегатов в языке программирования C# (который практически применяется для поддержки событий), причем будут рассмотрены примеры использования делегатов как особого вида событий. Фрагменты программ на языке C# проиллюстрируют практику обработки событий. При этом особая роль будет отведена исследованию механизмов обработки исключительных ситуаций, возникающих в ходе анализа параметров событий. Лекция завершится обзором литературы для более глубокого исследования материала.
Современные языки программирования и .NET: II семестр Лекция 11: Событийно управляемое программирование в .NET
Основные работы в области моделирования событий 1924 – М.Шейнфинкель (Moses Shönfinkel) разработал простую теорию функций 1934 – А.Черч (Alonso Church) создал ламбда-исчисление и применил его в исследованиях теории множеств 1971 – Д.Скотт (Dana S. Scott) предложил использовать полные и непрерывные решетки для моделирования семантики ламбда-исчисления 80-е г.г.– Д.Скотт (Dana S. Scott) и М.Фурман (Michael P. Fourman) исследовали механизм определенных дескрипций для формализации определений 90-е г.г.– В.Э.Вольфенгаген предложил схему двухуровневой концептуализации для моделирования событий © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Кратко остановимся на наиболее значительных (с точки зрения данного курса) этапах эволюции теории и практики реализации механизмов управления событиями в формальных теориях и языках программирования. Еще в 1924 году М. Шейнфинкель (Moses Shönfinkel) разработал простую (simple) теорию функций, которая фактически являлась исчислением объектов-функций и предвосхитила появление ламбда-исчисления и других теорий, моделирующих поведение объектов и события. В 1934 г. А. Черч (Alonso Church) предложил исчисление ламбда-конверсий или ламбдаисчисление и применил его для исследования теории множеств. Вклад ученого был настолько фундаментальным, что теория (до сих пор называемая ламбда-исчислением и часто именуемая в литературе ламбда-исчислением Черча) является основополагающей и для рассматриваемых нами вопросов. В начале 70-х г.г. Д. Скоттом (Dana S. Scott) было предложено использовать для формализации семантики математических теорий (в частности, ламбда-исчисления) так называемые решетки, которые обладают свойствами полноты и непрерывности. На этой основе Д. Скоттом был предложен денотационный подход к семантике. Такой подход предполагает анализ синтаксически корректных конструкций языка (в том числе объектов или событий) с точки зрения возможности вычисления их значений посредством специализированных функций. Позднее, в 80-х г.г. , тем же Д.Скоттом (Dana S. Scott), а также М.Фурманом (Michael P. Fourman) был исследован механизм определенных дескрипций для формализации определений. В ходе изложения мы будем неоднократно использовать эту лаконичную и интуитивно прозрачную нотацию. Наконец, в 90-х г.г. В.Э.Вольфенгагеном была предложена так называемая схема двухуровневой концептуализации для моделирования поведения объектов и событий.
Современные языки программирования и .NET: II семестр Лекция 11: Событийно управляемое программирование в .NET
Понятие события в математике Вообще говоря, под событием понимается соотнесение над объектом предметной области (или, иначе, индивидом). Произвольное семейство (действительных) объектов может быть параметризовано (или, иначе, концептуализировано) не только типами, но и событиями.
Оценивающее отображение ||•|| переводит индивид языка (программирования) в h. Возможный индивид h∈H переводится событием i ∈ Asg в действительный индивид h(i) ∈ Ui. Следующий шаг, управляемый событием j ∈ Asg, переводит h(i) в состояние h(i)(j). © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Завершив краткий обзор теоретических концепций моделирования событий, рассмотрим подробнее формализацию понятия события с точки зрения последнего из предложенных подходов. Под событием в математическом смысле далее будем иметь в виду соотнесение над объектом предметной области, который в рамках терминологии курса будем называть индивидом. Неформально говоря, под индивидом понимается такой объект предметной области (или языка программирования), который возможно выделить в этой области (или языке) посредством указания так называемой индивидуализирующей функции. Построение такой функции будем считать зависимым от эксперта в предметной области. Обычно такая функция имеет в качестве области своих значения истинности (а именно, «истина» и «ложь») и является истинной при аппликации к данному объекту и ложной в противном случае. Ранее нами было рассмотрено понятие типа как совокупности объектов. Заметим, что произвольное семейство (действительных в нашем частном случае) объектов может быть параметризовано (или, иначе, концептуализировано) не только типами, но и событиями.
В соответствии со схемой двухуровневой концептуализации, оценивающее отображение ||·|| переводит индивид языка (в частности, языка программирования) в h. Затем возможный (потенциальный) индивид h из семейства возможных индивидов H переводится событием i из семейства соотнесений Asg в действительный индивид h(i) из семейства действительных индивидов Ui. Аналогично, следующий шаг преобразований, управляемый событием j из семейства Asg, переводит h(i) в состояние h(i)(j).
Современные языки программирования и .NET: II семестр Лекция 11: Событийно управляемое программирование в .NET
Понятие события в программировании Под событием понимается способ внедрения фрагмента в код с целью изменения поведения программы. Как только происходит нечто, что интересует программиста или пользователя, активизируется событие и выполняется соответствующий фрагмент кода. В целом, обработка события подобна вызову процедуры. Любой интерфейс пользователя построен на основе обработки событий (onClick,onMouseMove,onMouseOver и т.д.). События, взаимодействующие с сетью, операционной системой, сторонними приложениями и т.д. могут также активизироваться по времени. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду На первый взгляд, определение понятия события в программировании существенно отличается от одноименной математической концепции. Под событием в языке программирования обычно понимается способ внедрения того или фрагмента в программный код с целью изменения поведения программы. Как только происходит изменение среды вычислений из числа представляющих интерес для разработчика или пользователя программного обеспечения, активизируется событие и выполняется соответствующий фрагмент кода. В целом, с точки зрения практического программирования, обработка события подобна вызову процедуры, причем в качестве параметров выступают те или иные характеристики среды вычислений. Любой интерфейс пользователя (или, в математической терминологии, среда вычислений) построен на основе обработки событий (onClick,onMouseMove,onMouseOver и т.д.). События, которые осуществляют взаимодействие с каналами локальных сетей, операционной системой, сторонними приложениями и т.д. могут также активизироваться по времени. В соответствии со схемой двухуровневой концептуализации, первый уровень может означать, например, инициацию пользователем события «щелчок левой кнопкой мыши», а второй – изменение состояния объекта меню при выборе соответствующего пункта. Как видим, сначала возможный индивид становится действительным (т.е. происходит активация события), а затем осуществляется означивание объекта программы (изменяется текущая позиция меню). Фрагментом кода программы в таком случае является метод, изменяющий текущую позицию меню, который активируется, исходя из значения первого соотнесения (т.е. конкретизации события). Таким образом, на основе механизма событий осуществляется управление программой.
Современные языки программирования и .NET: II семестр Лекция 11: Событийно управляемое программирование в .NET
Использование делегатов для обработки событий в языке C# (1) Под делегатом понимается метод-тип. Описание типа-делегата delegate void Notifier (string sender); // обычное описание метода // с ключевым словом delegate
Описание переменной-делегата Notifier greetings;
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду После изложения понятийного аппарата концепции событийно-управляемого программирования перейдем к вопросу реализации данного механизма применительно к языку объектно-ориентированного программирования C#. В целях реализации механизма событий в языке программирования C# предусмотрен так называемый механизм делегатов. Заметим, что механизм делегатов в языке C# является существенным усовершенствованием ранних подходов сходной функциональности в языках программирования C и C++, известных под названием функции обратного вызова (callback function), основанных на использовании малоинформативных и потенциально небезопасных указателей в оперативной памяти. Преимущество делегатов языка C# состоит в большей управляемости и безопасности кода (в частности, в C# существует возможность контроля соответствия типов параметров делегатов и логики вызова). В качестве интуитивного определения понятия делегата отметим, что под делегатом понимается метод, который ведет себя как тип. В качестве иллюстрации приведем описание типа- и переменной-делегатов на языке С#: delegate void Notifier (string sender); // обычное описание метода с ключевым словом delegate Notifier greetings;
// описание переменной-делегата
Современные языки программирования и .NET: II семестр Лекция 11: Событийно управляемое программирование в .NET
Использование делегатов для обработки событий в языке C# (2) Присваивание метода переменной-делегату: void SayHello(string sender) { Console.WriteLine("Hello from " + sender); } greetings = new Notifier(SayHello);
Вызов переменной-делегата: greetings("John"); "Hello from John"
// активирует SayHello("John") =>
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Как видно из приведенного фрагмента программы, формальное описание типов- и переменных-делегатов не отличается от традиционного описания методов и переменных. Фундаментальное отличие переменной-делегата от ранее рассмотренных объектов языка C# состоит в том, что в качестве значения переменной-делегату можно присвоить метод. Проиллюстрируем это утверждение следующим фрагментом программы на языке C#: void SayHello(string sender) { Console.WriteLine("Hello from " + sender); } greetings = new Notifier(SayHello);
Как видно из приведенного примера, на основе ранее описанного типа-делегата Notifier в соотнесении с вновь описанным методом SayHello осуществляется присваивание значения переменной greetings. Фактически данный пример изображает первый шаг концептуализации. Проиллюстрируем далее порядок вызова переменной-делегата следующим фрагментом программы на языке C#: greetings("John"); // активирует SayHello("John") => "Hello from John"
Как видно из приведенного примера, означивание переменной-делегата greetings активирует соотнесенный с ней на предыдущем шаге метод SayHello в соотнесении
"John" с генерацией состояния "Hello from John". Фактически данный пример изображает второй шаг концептуализации. Современные языки программирования и .NET: II семестр Лекция 11: Событийно управляемое программирование в .NET
Управление событиями с помощью переменных-делегатов языка C# (1) Переменной-делегату может быть присвоен любой из назначенных методов : void SayGoodBye(string sender) { Console.WriteLine("Good bye from " + sender); } greetings = new Notifier(SayGoodBye); greetings("John"); "Good bye from John"
//SayGoodBye("John") =>
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Отметим далее, что в предыдущих фрагментах программ рассматривался лишь один вариант соотнесения, характеризующего второй шаг концептуализации. Для более наглядной иллюстрации работы механизма делегатов в языке программирования C#, приведем пример фрагмента программы, характеризующего еще одно из соотнесений семейства для второго шага концептуализации: void SayGoodBye(string sender) { Console.WriteLine("Good bye from " + sender); } greetings = new Notifier(SayGoodBye); greetings("John"); //SayGoodBye("John") =>
"Good bye from John"
Как видно из приведенного примера, переменная-делегат greetings типа Notifier может принимать в качестве значения любой из методов SayHello и SayGoodBye. В данном случае, в отличие от предыдущего примера, значением, вычисляемым в ходе выполнения метода SayGoodBye, соотнесенного с переменной-делегатом greetings, является конкретизация "Good bye from John", полученная на основе означивания SayGoodBye("John"). Таким образом, становится ясным, каким образом посредством активизации (в зависимости от значения переменной-делегата) того или иного метода, становится
возможным управлять поведением программы в зависимости от событий, происходящих в среде вычислений.
Современные языки программирования и .NET: II семестр Лекция 11: Событийно управляемое программирование в .NET
Управление событиями с помощью переменных-делегатов языка C# (2) Перечислим следующие особенности переменных-делегатов: 1. Переменная-делегат может иметь пустое значение null (метод не назначен). 2. Пустая переменная-делегат не может быть вызвана (возникает исключительная ситуация). 3. Переменные-делегаты являются объектами первого рода (first class object): их можно хранить в структурах данных, передавать как параметры и т.д. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Для более подробного рассмотрения механизмов расширенного управления программой на языке C# посредством событий на основе делегатов, необходимо предварительно исследовать основные особенности переменных данного типа. Прежде всего, необходимо отметить то обстоятельство, что переменные-делегаты могут иметь пустое значение null, что соответствует отсутствию назначенного им метода. Здесь проявляется аналогия с теорией вычислений Д.Скотта в том отношении, что любой домен непременно имеет неопределенное значение. Эта параллель наводит на предположение, что теория вычислений Д.Скотта способна адекватно формализовать событийно управляемое программирование. Оказывается, что это предположение весьма важно, а его исследование – весьма продуктивно. Кроме того, пустые переменные-делегаты в языке C# не подлежат вызову. При попытке осуществить обращение к такой переменной в среде программирования возникает исключительная ситуация. И снова здесь прослеживается аналогия с теорией вычислений Д.Скотта. Еще одной особенностью переменных-делегатов является их принадлежность к классу объектов первого рода (first class object). Согласно правилам языка программирования C#, делегаты возможно хранить в структурах данных, передавать как параметры и т.д. Таким образом, делегаты как модели событий во многом сходны с функциями в математическом понимании этого слова. Следовательно, для формализации механизмов, основанных на событиях, вполне пригодны уже хорошо знакомые нам формальные системы ламбдаисчисления и комбинаторной логики.
Современные языки программирования и .NET: II семестр Лекция 11: Событийно управляемое программирование в .NET
Делегаты как объекты языка C# (1) Проиллюстрируем использование переменных-делегатов на следующих примерах. Создадим переменную-делегат: new DelegateType (obj.Method); Переменная-делегат хранит как сам метод, так и его приемник (receiver), при этом сама не имеет параметров: new Notifier(myObj.SayHello); Объект obj cможет быть описан как this, а также опущен: new Notifier(SayHello);
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Обсудив основные возможности использования описания и использования механизма делегатов в языке программирования C#, рассмотрим свойства делегатов как объектов языка более подробно. При этом будем приводить необходимые примеры в виде кода на языке программирования C#. Прежде всего, рассмотрим порядок описания языкового объекта-делегата. Проиллюстрируем обобщение создания переменной-делегата в виде формы Бэкуса-Наура (БНФ): ::= new (.);
При этом переменная-делегат в ходе соотнесения инициализируется конкретным методом явно указанного объекта в соответствии с типом делегата. Необходимо также отметить, что в структуре переменной-делегата хранится не только сам метод, но и его выход или приемник (receiver). Тем не менее, переменная-делегат не имеет собственных параметров: new Notifier(myObj.SayHello);
В данном фрагменте программного кода на языке C# приведен конкретный пример описания переменной-делегата как конкретизации типа-делегата Notifier в соотнесении с уже известным нам методом SayHello определенного пользователем объекта myObj. Заметим, что присутствующий в описании объект obj cможет быть определен явно посредством описателя this, а может быть и опущен, как, например, в следующем фрагменте программы на языке C#: new Notifier(SayHello);
Современные языки программирования и .NET: II семестр Лекция 11: Событийно управляемое программирование в .NET
Делегаты как объекты языка C# (2) В случае статического метода вместо объекта указывается имя класса: new Notifier(MyClass.StaticSayHello); Метод не описывается как абстрактный, но может быть описан посредством virtual, override или new.
• • •
Описание метода должно соответствовать описанию типа делегата в следующих отношениях: одинаковое количество параметров; одинаковые типы параметров (включая тип возвращаемого значения); одинаковые виды параметров (ref, out, value). © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Обсудив основные возможности описания и использования механизма делегатов с динамическими методами, рассмотрим особенности статического случая. При этом обобщенный формат описания переменной-делегата программирования C# в виде формы Бэкуса-Наура (БНФ) примет вид:
для
языка
::= new (.)
Таким образом, описание переменной-делегата со статическим методом в форме кода на языке программирования C# может иметь, например, следующий вид: new Notifier(MyClass.StaticSayHello);
Существует еще ряд особенностей, характеризующих статический случай использования переменных-делегатов в языке программирования C#. Перечислим наиболее существенные из них. Прежде всего, следует отметить, что метод в составе делегата не может быть описан как абстрактный (abstract), но может быть определен c использованием описателей как виртуальный (virtual), замещенный (override) или как экземпляр (new). Кроме того, описание метода должно соответствовать описанию типа делегата, т.е. оба описания должны иметь одинаковое количество параметров и типы параметров (включая тип возвращаемого значения), причем виды параметров (в частности, с передачей по ссылке (ref), по значению (value), а также возвращаемых (out)) должны совпадать.
Современные языки программирования и .NET: II семестр Лекция 11: Событийно управляемое программирование в .NET
Использование делегатов множественного вызова для управлениями событиями в языке C# Переменная-делегат может содержать множественные значения в одно и то же время: Notifier greetings; greetings = new Notifier(SayHello); greetings += new Notifier(SayGoodbye); greetings("John"); // "Hello from John" // "Good bye from John" greetings -= new Notifier(SayHello); greetings("John");
// "Good bye from John"
Заметим, что если множественный делегат является функцией, то возвращаются как значение, так и параметр последнего вызова.© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Еще одним важным свойством переменных-делегатов является их динамическая природа. Теоретически это означает, что в зависимости от (временного) соотнесения переменнаяделегат пробегает по домену значений конкретизаций связанного с ней метода. Практика программирования на языке C# показывает, что переменная-делегат может содержать множественные значения в одно и то же время. Проиллюстрируем это утверждение следующим фрагментом программы на языке C#: Notifier greetings; greetings = new Notifier(SayHello); greetings += new Notifier(SayGoodbye); greetings("John"); // "Hello from John" // "Good bye from John" greetings -= new Notifier(SayHello); greetings("John"); // "Good bye from John"
Как видно из приведенного примера, фрагмент программы на языке C# содержит описание уже известной нам переменной-делегата greetings типа-делегата Notifier. Переменной-делегату greetings в качестве значения последовательно инкрементно присваиваются конкретизации-методы SayHello и SayGoodbye. При этом отладочный вывод значения переменной greetings с конкретизацией "John" демонстрирует семейство значений "Hello from John" и "Good bye from John". По декрементном присваивании переменной-делегату greetings конкретизации-метода SayHello, отладочный вывод значения переменной демонстрирует значение "Good bye from John". Заметим, что если множественный делегат является функцией, то возвращаются как значение, так и параметр последнего вызова.
Современные языки программирования и .NET: II семестр Лекция 11: Событийно управляемое программирование в .NET
События как особый вид переменных-делегатов (1) Проиллюстрируем управление событиями следующим расширенным примером использования делегатов: class Model { public event Notifier notifyViews; public void Change() { ... notifyViews("Model"); } } class View1 { public View1(Model m) { m.notifyViews += new Notifier(this.Update1); } void Update1(string sender) { Console.WriteLine(sender + " was changed"); } } © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Обсудив наиболее существенные для данного курса аспекты типов- и переменныхделегатов, перейдем к рассмотрению порядка использования механизма делегатов для создания событийно управляемых программ. Проиллюстрируем подход к управлению событиями посредством механизма делегатов следующим фрагментом программного кода на языке программирования C# (приводим начало фрагмента): class Model { public event Notifier notifyViews; public void Change() { ... notifyViews("Model"); } } class View1 { public View1(Model m) { m.notifyViews += new Notifier(this.Update1); } void Update1(string sender){ Console.WriteLine(sender + "was changed"); } }
Как видно из приведенного примера, фрагмент программы на языке C# содержит описание класса Model с полем-событием notifyViews (описатель event) и методом Change, оповещающем через делегат о смене соотнесения. Кроме того, в данном фрагменте содержатся описания класса View1 с одноименными методом для просмотра
состояния делегата посредством метода Update1, содержащего вывод на стандартное устройство отладочной информации о смене приложения-«отправителя» сообщения.
Современные языки программирования и .NET: II семестр Лекция 11: Событийно управляемое программирование в .NET
События как особый вид переменных-делегатов (2) class View2 { public View2(Model m) { m.notifyViews += new Notifier(this.Update2); } void Update2(string sender) { Console.WriteLine(sender + " was changed"); } }
class Test { static void Main() { Model m = new Model(); new View1(m); new View2(m); m.Change(); } } Заметим, что события используются вместо обычных переменныхделегатов для улучшения абстракции, поскольку событие может активировать только тот класс, в котором оно описано.
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Завершим иллюстрацию программирования :
использования
делегатов
для
событийно
управляемого
class View2 { public View2(Model m){ m.notifyViews += new Notifier(this.Update2); } void Update2(string sender){ Console.WriteLine(sender + " was changed"); } } class Test { static void Main() { Model m = new Model(); new View1(m); new View2(m); m.Change(); } }
Как видно из приведенного фрагмента программы, пример завершается описанием класса View2, аналогичного классу View1, а также класса Test, который инициализирует классы View1 и View2 и запускает метод Change, инициирующий смену соотнесений (и состояний) переменных-делегатов.
Заметим, что события используются вместо обычных переменных-делегатов для увеличения уровня абстракции программной компоненты, поскольку событие может активировать только тот класс, в котором оно описано.
Современные языки программирования и .NET: II семестр Лекция 11: Событийно управляемое программирование в .NET
Обработка исключений в языке C#: оператор try (1) FileStream s = null; try { s = new FileStream(curName, FileMode.Open); ... } catch (FileNotFoundException e) { Console.WriteLine("file {0} not found", e.FileName); } catch (IOException) { Console.WriteLine("some IO exception occurred"); } catch { Console.WriteLine("some unknown error occurred"); } finally { if (s != null) s.Close(); } © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Процесс обработки событий, как и процесс проектирования и реализации программного обеспечения в целом, не может быть свободным от ошибок. Ранее в ходе изложения уже упоминалось о таком важном свойстве доменов как наличие неопределенного элемента. Кроме того, при обсуждении семантики рассматривалась модель генерации ошибочной ситуации при невозможности связывания переменной со значением. Подобные ситуации часто возникают и при обработке событий. Рассмотрим особенности реализации оператора try языка C# для обнаружения и обработки ошибок на следующем примере: FileStream s = null; try {s = new FileStream(curName, FileMode.Open); ... } catch (FileNotFoundException e){ Console.WriteLine("file {0} not found", e.FileName); } catch (IOException){ Console.WriteLine("some IO exception occurred"); } catch { Console.WriteLine("some unknown error occurred"); } finally {if (s != null) s.Close(); }
Как видно из примера, оператор try анализирует выход функции чтения из потокового файла. Для обработки вариантов при разборе возможных ошибочных ситуаций
используется оператор catch , в данном примере генерирующий диагностические сообщения. В случае ложности всех catch-альтернатив выполняется блок операторов, следующий за словом finally (происходит штатное закрытие файла).
Современные языки программирования и .NET: II семестр Лекция 11: Событийно управляемое программирование в .NET
Обработка исключений в языке C#: оператор try (2) Перечислим основные свойства оператора try: 1) условия обнаружения (catch) проверяются последовательно; 2) в итоге, одно из условий всегда удовлетворяется (если список условий не пуст); 3) имя параметра exception в условии обнаружения можно опустить; 4) тип exception должен быть выводим из System.Exception; 5) в случае отсутствия параметра exception , подразумевается System.Exception © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду По результатам анализа приведенного фрагмента программы на языке C# рассмотрим основные характеристики обработки исключительных ситуаций с учетом особенностей среды вычислений Microsoft .NET. Прежде всего, необходимо отметить то обстоятельство, что условия обнаружения catch в составе оператора try проверяются последовательно сверху вниз. Таким образом, при полном разборе случаев разработчиком программного обеспечения, одно из условий обнаружения catch всегда удовлетворяется (естественно, в том случае, если список условий не пуст). Кроме того, синтаксис языка программирования C# разрешает опустить имя параметра exception в условии обнаружения catch. Далее, заметим, что тип конкретизации исключительной ситуации exception должен быть выводим из базового класса системы типизации Microsoft .NET под названием System.Exception. Наконец, важным свойством оператора является тот факт, что при отсутствии явного указания параметра exception подразумевается обработка событий в соответствии с умолчаниями, принятыми для полей и методов базового класса System.Exception системы типизации Microsoft .NET.
Современные языки программирования и .NET: II семестр Лекция 11: Событийно управляемое программирование в .NET
Описание класса System.Exception Свойства:
сообщение об ошибке в виде строки; установка нового Exception(msg); e.StackTrace просмотр стека вызова методов как строки; e.Source приложение или объект, которые вызвали исключительную ситуацию; e.TargetSite метод объекта, который вызвал исключительную ситуацию; e.Message
...
Методы: e.ToString()
возвращает имя исключительной ситуации;
...
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Для иллюстрации особенностей механизма обработки исключительных ситуаций в среде вычислений Microsoft .NET приведем фрагмент содержательного описания системного базового класса System.Exception системы типизации .NET, оформив его для наглядности в форме следующей таблицы:
Таблица . Некоторые свойства и методы класса System.Exception. Имя свойства или метода
Функции свойства или метода
Свойства: e.Message e.StackTrace e.Source e.TargetSite
сообщение об ошибке в виде строки; установка нового сообщение об ошибке Exception(msg); просмотр стека вызова методов как строки; приложение или объект, которые вызвали исключительную ситуацию; метод объекта, который вызвал исключительную ситуацию;
...
Методы: e.ToString() ...
возвращает имя исключительной ситуации;
Как видно из приведенной таблицы, класс System.Exception представляет собой описание многочисленных объектов и методов, которые контролируют стандартный ход обработки исключительных ситуаций, возникающих в программных реализациях (в том числе и разработанных на языке C#). При этом каждая исключительная ситуация характеризуется уникальным диагностическим сообщением. Современные языки программирования и .NET: II семестр Лекция 11: Событийно управляемое программирование в .NET
Активация исключительной ситуации в языке C# 1. Посредством недопустимой операции (неявно): 1) деление на нуль; 2) выход за границы массива; 3) обращение к пустому (null) указателю; ...
2. Посредством оператора throw (явно): throw new FunnyException(10); class FunnyException : ApplicationException { public int errorCode; public FunnyException(int x) { errorCode = x; } } © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду При исследовании механизмов обработки исключительных ситуаций в той или иной системе, среде или языке программирования, неизбежно возникает вопрос об источниках таких ситуаций. Исходя из вида изученного оператора try языка программирования C#, а также из стандартных свойств и методов обработки исключений класса System.Exception среды вычислений .NET, можно сделать предположение о том, что существуют явные и неявные источники возникновения исключительных ситуаций. К неявным источникам исключений будем относить недопустимые операции, возникающие во время выполнения программы (будем считать, что компилятор работает корректно). В частности, недопустимыми операциями будем считать хорошо знакомые нам ситуации деления на нуль, выхода за границы массива, обращения к пустому (null) указателю и т.д. Однако, для реализации событийно управляемых программ в языке программирования C# существует механизм явной генерации исключений, который реализуется посредством оператора throw (приводим соответствующий фрагмент программы): throw new FunnyException(10); class FunnyException : ApplicationException{ public int errorCode; public FunnyException(int x){ errorCode = x; }
} Как видно из приведенного фрагмента программы, оператор throw реализует
явный вызов экземпляра класса FunnyException с генерацией кода ошибки.
Современные языки программирования и .NET: II семестр Лекция 11: Событийно управляемое программирование в .NET
Фрагмент иерархии исключений языка С# (1) Exception SystemException ArithmeticException DivideByZeroException OverflowException ... NullReferenceException IndexOutOfRangeException InvalidCastException ... © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Заметим, что в силу высокой сложности и гетерогенной природы среды вычислений Microsoft .NET, семейство исключительных ситуаций весьма многообразно. Для удобства систематизации, хранения, поиска и анализа исключений, а также в силу особенностей строения системы типизации Microsoft .NET, классификация исключительных ситуаций в ней организована по иерархическому принципу. Приведем для сведения небольшой фрагмент сложной структуры иерархии стандартных исключительных ситуаций среды вычислений Microsoft .NET: Exception SystemException ArithmeticException DivideByZeroException OverflowException ... NullReferenceException IndexOutOfRangeException InvalidCastException ...
Заметим, что существует еще более общий уровень иерархии исключений, чем SystemException, а именно, уровень Exception. В данной иерархии исключительных ситуаций перечислены наиболее типичные неявные исключения: деление на нуль и переполнение как варианты арифметического исключения. Другим подклассом исключений являются обращение к пустой ссылке, выход за границы массива, а также неверный вызов.
Современные языки программирования и .NET: II семестр Лекция 11: Событийно управляемое программирование в .NET
Фрагмент иерархии исключений языка С# (2) ApplicationException ... //специализированные исключения ... IOException FileNotFoundException DirectoryNotFoundException ... WebException ... © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Продолжим анализ иерархии исключительных ситуаций среды вычислений .NET. ApplicationException ... //специализированные исключения ... IOException FileNotFoundException DirectoryNotFoundException ... WebException ...
Отдельный подкласс приложениях.
исключений
составляют
исключения,
встречающиеся
в
Еще одним важным подклассом исключительных ситуаций являются ошибки вводавывода, связанные, в частности, с невозможностью найти файл или каталог. Наконец, еще одним подклассом исключительных ситуаций, существенным для среды вычислений Microsoft .NET, ориентированной на распределенные сетевые вычисления и веб-сервисы, является подкласс веб-исключений.
Современные языки программирования и .NET: II семестр Лекция 11: Событийно управляемое программирование в .NET
Алгоритм поиска условия обнаружения:
Цепочка вызовов просматривается в обратном направлении до тех пор, пока не находится метод с соответствующим условием обнаружения. Если таковой не найден, программа аварийно завершается с дампом стека. Исключительные ситуации не должны с обязательностью обнаруживаться в языке C#. Не существует различия между: 1) помеченными исключениями, которые необходимо обнаружить, и 2) непомеченными исключениями, которые нет необходимости обнаружить. Замечание. Хотя такой подход представляется удобным, он приводит к созданию менее устойчивых приложений. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Рассмотрим особенности реализации механизма реакции на исключительные ситуации в языке программирования C# и среде Microsoft .NET. Поиск условия обнаружения исключительной ситуации в языке программирования C# реализован на основе следующего обобщенного алгоритма. Осуществляется просмотр цепочки вызовов методов в обратном направлении до тех пор, пока не найден метод с соответствующим условием обнаружения catch. В случае, если такой метод не удается обнаружить, программа завершается аварийно и выдается дамп стека (оперативной памяти). Подчеркнем, что алгоритм поиска исключительных ситуаций не обязательно должен результативно завершиться даже для такого современного и позволяющего создавать относительно безопасный код языка программирования как C#. Заметим, что в языке C# не существует различия между помеченными исключениями, которые необходимо обнаружить, и непомеченными исключениями, в обнаружении которых нет необходимости. Несмотря на то, что такой подход в первом приближении представляется удобным, он заведомо приводит к созданию менее устойчивого и безопасного прикладного (и тем более системного) программного кода.
Современные языки программирования и .NET: II семестр Лекция 11: Событийно управляемое программирование в .NET
Преимущества событийноориентированного программирования 1. 2. 3. 4. 5. 6.
Возможность моделирования произвольных реальных объектов Потенциальная легкость настройки интерфейса Программирование, основанное на сценариях (скрипты изменяют состояние программы) Высокий процент повторного использования программного кода Гибкость реинжиниринга программного обеспечения Строгое математическое основание (концептуализация) © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Подводя итоги рассмотрения основных аспектов теории и практики событийно управляемого программирования на языке C#, можно сделать следующие выводы. Во-первых, как и в объектно-ориентированном программировании, управление событиями (а, другими словами, поведением объектов программ) открывает возможность моделирования реальных объектов сколь угодно сложной структуры и природы. Во-вторых, событийно ориентированное программирование обеспечивает потенциальную легкость настройки интерфейса пользователя (и даже его адаптации в процессе работы программы в соответствии с требованиями пользователя). Кроме того, процедуры обработки событий представляют собой методы в терминологии ООП. Таким образом, основным предметом программирования являются сценарии, причем методы делегатов, реализованные в форме скриптов, изменяют состояние программы. Затем, важным преимуществом программирования, ориентированного на события или скрипты, является высокий процент повторного использования программного кода. Заметим, что значительное количество событий уже реализовано в среде вычислений .NET, и нами был рассмотрен фрагмент их иерархии. Далее, необходимо отметить такой позитивный аспект событийного программирования как гибкость реинжиниринга (т.е. разработки в обратном направлении) программного обеспечения. По сути речь идет о концептуализации, которая является теоретической основой наших рассуждений. Именно концептуализация является тем строгим математическим основанием, которое позволяет не только моделировать управление событиями, но и обеспечить верифицируемость создаваемого программного обеспечения.
Современные языки программирования и .NET: II семестр Лекция 11: Событийно управляемое программирование в .NET
Библиография (1) 1.
2. 3. 4.
Schönfinkel M. ‘Über die Bausteine der matematischen Logik, Math. Annalen 92, pp. 305-316, 1924. Translation printed as ‘On the building blocks of mathematical logic’, in van Heijenoort, J. (ed.), From Frege to Gödel, Harvard University Press, 1967 Church A. The calculi of lambda-conversion.- Princeton, 1941, ed. 2, 1951 Barendregt H.P. The lambda calculus (revised edition), Studies in Logic, 103, North Holland, Amsterdam, 1984 Scott D.S. The lattice of flow diagrams.- Lecture Notes in Mathematics, 188, Symposium on Mathematics of Algorithmic Languages.- Springer-Verlag, 1971, p.p. 311-372 © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду К сожалению, в рамках времени, отведенных на одну лекцию, можно лишь в общих чертах охарактеризовать специфику такого многоаспектного явления, как событийноуправляемый подход к проектированию и реализации программного обеспечения. Для более детального ознакомления с особенностями, достижениями и проблемами в теории моделирования данного подхода и практики реализации связанных с ним механизмов рекомендуется следующий список литературы: 1.Schönfinkel M. ‘Über die Bausteine der matematischen Logik, Math. Annalen 92, pp. 305-316, 1924. Translation printed as ‘On the building blocks of mathematical logic’, in van Heijenoort, J. (ed.), From Frege to Gödel, Harvard University Press, 1967 2.Church A. The calculi of lambda-conversion.- Princeton, 1941, ed. 2, 1951 3.Barendregt H.P. The lambda calculus (revised edition), Studies in Logic, 103, North Holland, Amsterdam, 1984 4.Scott D.S. The lattice of flow diagrams.- Lecture Notes in Mathematics, 188, Symposium on Mathematics of Algorithmic Languages.- Springer-Verlag, 1971, p.p. 311-372 Кратко остановимся на источниках. Работы [1-3] являются исчерпывающим описанием синтаксиса и семантики ламбда-исчисления, основной формализации языков программирования, в том числе языков ООП. В работе [4] представлен вариант подхода к семантике динамики и статики объектов в форме теории решеток, по которым «протекает» информация.
Современные языки программирования и .NET: II семестр Лекция 11: Событийно управляемое программирование в .NET
Библиография (2) 5. 6. 7. 8. 9.
Scott D.S. Identity and existence in intuitionistic logic.- In: Application of Sheaves.- Berlin: Springer, 1979, p.p. 600-696 Fourman M. The logic of topoi. In: Handbook of Mathematical Logic, J.Barwise et al., eds. North-Holland, 1977 Wolfengagen V.E. Event-driven objects. In: Proc. CSIT’1999, Moscow, Russia, 1999, Vol.1, p.p. 88-96 Wolfengagen V.E. Fuctional notation for indexed concepts. In: Proc. WFLP’2000, Benicassim, Spain, Sept. 2000. http://www.dsic.upv.es/~wflp2000/ Scott D.S. Domains for denotational semantics. ICALP 1982, 577-613 © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Продолжим обсуждение работ, посвященных исследованию основных элементов событийно управляемого программирования. 5.Scott D.S. Identity and existence in intuitionistic logic.- In: Application of Sheaves.- Berlin: Springer, 1979, p.p. 600-696 6.Fourman M. The logic of topoi. In: Handbook of Mathematical Logic, J.Barwise et al., eds. North-Holland, 1977 7.Wolfengagen V.E. Event-driven objects. In: Proc. CSIT’1999, Moscow, Russia, 1999, Vol.1, p.p. 88-96 8.Wolfengagen V.E. Fuctional notation for indexed concepts. In: Proc. WFLP’2000, Benicassim, Spain, Sept. 2000. http://www.dsic.upv.es/~wflp2000/ 9.Scott D.S. Domains for denotational semantics. ICALP 1982, 577-613 Работа [5] представляет собой систематизацию важнейших понятий – тождества и существования – в логиках высших порядков и затрагивает вопросы принципиальной формализуемости реального мира. В работе [6] обсуждаются способы построения математически и логически корректных определений понятий предметной области, т.е. строится своего рода объектная модель. В работах [7,8] исследуется событийная ориентированность объектных теорий с учетом динамики и статики объектов, а также их взаимовлияния. В работе [9] рассматриваются вопросы, связанные с развитием денотационной семантики, имеющей широкое распространение в теории моделирования объектов, и, в частности, с ее представлением посредством доменов.
Компонентное программирование в .NET
© Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В данной лекции будут рассмотрены вопросы, относящиеся к истории развития, идеологии, математическому основанию и обзору возможностей компонентного проектирования и реализации программных систем – одного из важнейших и наиболее передовых подходов в современном программировании.
Современные языки программирования и .NET: II семестр Лекция 12: Компонентное программирование в .NET
Содержание лекции 1. 2. 3. 4. 5. 6. 7. 8. 9.
Современные подходы к программированию Объектно-ориентированный подход к программированию Компонентный подход к программированию как расширение ООП Обзор архитектурного решения .NET Понятия сборки и манифеста в .NET Пространства имен в .NET Гетерогенное компонентное программирование в .NET Итоги и перспективы развития курса Библиография © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Коротко о содержании лекции. В ходе лекции будут рассмотрены важнейшие научные исследования, относящиеся к эволюции подходов к математическому моделированию такого важнейшего из современных подходов к программированию как компонентно-ориентированного проектирования и реализации программных систем. Прежде всего, будет программированию.
представлен
краткий
обзор
современных
подходов
к
При этом особое внимание будет уделено обсуждению объектно-ориентированного подхода к программированию и компонентного подхода как усовершенствованного варианта ООП. Затем будут рассмотрены основные особенности архитектурного решения Microsoft .NET. При этом в фокусе нашего исследования окажутся такие концепции, как сборка, манифест и пространство имен. Наконец, предметом нашего внимания станут особенности проектирования и реализации гетерогенных программных систем согласно компонентно-ориентированному подходу. Лекция завершится обзором литературы для более глубокого исследования материала.
Современные языки программирования и .NET: II семестр Лекция 12: Компонентное программирование в .NET
Основные работы в области моделирования компонент 1924 – М.Шейнфинкель (Moses Shönfinkel) разработал простую теорию функций 1934 – А.Черч (Alonso Church) создал ламбда-исчисление и применил его в исследованиях теории множеств 1971 – Д.Скотт (Dana S. Scott) предложил использовать полные и непрерывные решетки для моделирования семантики ламбдаисчисления 80-е г.г.– Д.Скотт (Dana S. Scott) и М.Фурман (Michael P. Fourman) исследовали механизм определенных дескрипций для формализации определений 90-е г.г.– В.Э.Вольфенгаген предложил схему двухуровневой концептуализации для моделирования компонент © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Кратко остановимся на наиболее значительных с точки зрения данного курса этапах эволюции теории и практики реализации механизмов формальных теорий и языков программирования, которые адекватны для исследования компонентно-ориентированного подхода. Еще в 1924 году М. Шейнфинкель (Moses Shönfinkel) разработал простую (simple) теорию функций, которая фактически являлась исчислением объектов-функций и предвосхитила появление ламбда-исчисления и других теорий, моделирующих поведение объектов и события. В 1934 г. А. Черч (Alonso Church) предложил исчисление ламбда-конверсий или ламбдаисчисление и применил его для исследования теории множеств. Вклад ученого был настолько фундаментальным, что теория (до сих пор называемая ламбда-исчислением и часто именуемая в литературе ламбда-исчислением Черча) является основополагающей и для рассматриваемых нами вопросов. В начале 70-х г.г. Д. Скоттом (Dana S. Scott) было предложено использовать для формализации семантики математических теорий (в частности, ламбда-исчисления) так называемые решетки, которые обладают свойствами полноты и непрерывности. На этой основе Д. Скоттом был предложен так называемый денотационный подход к семантике. Такой подход предполагает анализ синтаксически корректных конструкций языка (в том числе объектов или событий) с точки зрения возможности вычисления их значений посредством специализированных функций. Позднее, в 80-х г.г. тем же Д.Скоттом (Dana S. Scott), а также М.Фурманом (Michael P. Fourman) был исследован механизм определенных дескрипций для формализации определений. Наконец, в 90-х г.г. В.Э.Вольфенгагеном была предложена так называемая схема двухуровневой концептуализации для моделирования поведения объектов и событий.
Современные языки программирования и .NET: II семестр Лекция 12: Компонентное программирование в .NET
Подходы к программированию Основные подходы к программированию: • структурный, модульный; • функциональный; • логический; • объектно-ориентированный (ООП); • смешанный (комбинированный, интегрированный); • компонентно-ориентированный (.NET); • чисто объектный © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Остановимся несколько подробнее на языках и подходах к программированию, которые наиболее существенны для формирования компонентно-ориентированного проектирования и реализации программных систем. Перечислим рассмотренные в ходе курса подходы к программированию: • ранние неструктурные подходы; • структурный или модульный подход (задача разбивается на подзадачи, затем на алгоритмы, составляются их структурные схемы и происходит реализация); • функциональный подход; • логический подход; • объектно-ориентированный подход; • смешанный подход (некоторые подходы возможно комбинировать); • компонентно-ориентированный (программный проект рассматривается как множество компонент, такой подход принят, в частности, в .NET); • чисто объектный подход (идеальный с математической точки зрения вариант, который пока не реализован практически). Заметим, что приведенную классификацию не следует считать единственно верной и абсолютной, поскольку языки программирования постоянно развиваются и совершенствуются, и недавние недостатки устраняются с появлением необходимых инструментальных средств или теоретических обоснований.
Современные языки программирования и .NET: II семестр Лекция 12: Компонентное программирование в .NET
Интуитивные определения основных понятий Объектом называется математическое представление сущности реального мира (или предметной области), которое используется для моделирования. Классом называется весьма общая сущность, которая может быть определена как совокупность элементов. Свойством (или атрибутом) называется пропозициональная функция, определенная на произвольном типе (данных). Методом (или функцией) называется операция, определенная над объектами некоторого класса. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Сформулируем определения таких основополагающих для объектно-ориентированного подхода к программированию понятий, как объект, класс, свойство и метод. Под объектом будем понимать математическое представление сущности реального мира (или предметной области), которое используется для моделирования. Классом будем называть весьма общую сущность, которая может быть определена как совокупность элементов (нужно заметить, что класс при объектно-ориентированном подходе к программированию – это, как правило, первичное, неопределяемое понятие, до некоторой степени аналогичное теоретико-математическому понятию множества, или, точнее, домена). Под свойством (или атрибутом) будем понимать пропозициональную функцию, определенную на произвольном типе (данных). Методом (или функцией) назовем операцию, которая определена над объектами того или иного класса.
Современные языки программирования и .NET: II семестр Лекция 12: Компонентное программирование в .NET
Принципы объектно-ориентированного программирования: 1. Абстракция данных 2. Наследование конкретных атрибутов объектов и функций оперирования объектами на основе иерархии 3. Инкапсуляция (свойства и методы «спрятаны» внутри объекта) 4. Полиморфизм (функции с возможностью обработки данных переменного типа) © © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Напомним, что важнейшим преимуществом объектно-ориентированного программирования является повышение производительности труда программистов при проектировании и реализации программного обеспечения. Другое преимущество ООП перед ранними подходами к программированию состоит в возрастании процента повторного использования уже разработанного программного кода. При этом, в отличие от предыдущих подходов к программированию, объектноориентированный подход требует глубокого понимания основных концепций, на которых он зиждется. К числу основополагающих понятий ООП обычно относят абстракцию данных, наследование, инкапсуляцию и полиморфизм. Преимуществом предлагаемого курса является то обстоятельство, что уже изученные в первой его части курса разделы computer science (такие как, например, ламбда-исчисление и комбинаторная логика) позволяют сформировать глубокое и точное понимание фундаментальных понятий объектно-ориентированного программирования. В частности, понятие абстракции – основной операции ламбда-исчисления – для нас является уже хорошо знакомым. Напомним качественные основы фундаментальных принципов ООП. Наследование конкретных атрибутов объектов и функций оперирования объектами основано на иерархии. Инкапсуляция означает «сокрытие» свойств и методов внутри объекта. Полиморфизм, как и в функциональном программировании, понимается как наличие функций с возможностью обработки данных переменного типа.
Современные языки программирования и .NET: II семестр Лекция 12: Компонентное программирование в .NET
Абстракция и методы ее моделирования Вообще говоря, под aбстракцией понимается выражение языка программирования, отличное от идентификатора. Значение функции или переменной может быть присвоено абстракции и является значением последней. Поведение абстракции заключается в приложении функции к аргументу. Абстракция адекватно моделируется ламбда-исчислением (а именно, посредством операции абстракции). © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду
Рассмотрим более подробно такой фундаментальный ориентированного подхода к программированию, как абстракция.
принцип
объектно-
В разделах математики, исследующих моделирование процесса создания программ, под абстракцией принято понимать произвольное выражение языка программирования, которое является отличным от идентификатора. Важнейшей операцией, которая была исследована нами в первой части курса, является операция вычисления значения выражения или команды, т.е. операция означивания (в частности, функция вычисления значения явно используется при построении семантики языка программирования). В этой связи важно установить, что является значением абстракции. Будем считать, что значение функции или переменной может быть присвоено абстракции и является значением последней. В объектно-ориентированном программировании каждый объект является принципиально динамической сущностью, т.е. изменяется в зависимости от времени (а также от воздействия внешних по отношению к нему факторов). Иначе говоря, объект обладает тем или иным образом поведения. В отношении абстракции как объекта, поведение заключается в приложении функции к аргументу. Как мы уже отмечали, концепция абстракции в объектно-ориентированном программировании адекватно моделируется посредством ламбда-исчисления. Точнее говоря, операция абстракции в полной мере является моделью одноименного понятия ООП.
Современные языки программирования и .NET: II семестр Лекция 12: Компонентное программирование в .NET
Наследование и методы его моделирования Вообще говоря, под наследованием понимается свойство производного объекта сохранять поведение (атрибуты и операции) базового (родительского). В языках программирования понятие наследование означает применимость (некоторых) свойств или методов базового класса для классов, производных от него (а также для их конкретизаций). Наследование моделируется (иерархическим) отношением частичного порядка и адекватно формализуется посредством: 1) фреймовой нотации Руссопулоса (N.D. Roussopulos); 2) диаграмм Хассе (Hasse) © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Под наследованием будем понимать свойство производного объекта сохранять поведение родительского объекта. Под поведением будем иметь в виду для математического объекта его атрибуты и операции над ним, а для языкового объекта ООП – поля и методы. Таким образом, применительно к языку программирования концепция наследования означает, что свойства и методы базового класса равно применимы к его производным объектам. Заметим, что дочерний объект не обязательно наследует все без исключения атрибуты и операции родительского, а лишь некоторые из них. Такой подход характерен как для классов объектов в целом, так и для отдельных их конкретизаций, или, иначе, экземпляров. Теоретическая концепция наследования удовлетворительно моделируется посредством отношения (или, точнее, иерархии) частичного порядка. Существует целый ряд формализаций наследования, но наиболее адекватными и концептуально ясными являются графические модели. Среди них следует выделить уже упомянутые ранее подходы: фреймовую нотацию Н.Руссопулоса и диаграммы Хассе.
Современные языки программирования и .NET: II семестр Лекция 12: Компонентное программирование в .NET
Понятие инкапсуляции в программировании Вообще говоря, под инкапсуляцией понимается доступность объекта исключительно посредством его свойств и методов. Таким образом, свойствами объекта (явно описанными или производными) возможно оперировать исключительно посредством его методов. Свойства инкапсуляции: • совместное хранение данных и функций; • сокрытие внутренней информации от пользователя; • изоляция пользователя от особенностей реализации © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В неформальной постановке вопроса будем понимать под инкапсуляцией доступность объекта исключительно посредством его свойств и методов. Другими словами, концепция инкапсуляции призвана обеспечивать безопасность проектирования и реализации программного обеспечения на основе локализации манипулирования объектом в областях его полей и методов. Иначе говоря, свойствами объекта возможно оперировать исключительно посредством его методов. Это замечание касается как свойств, явно определенных в описании объекта, так и свойств, унаследованных данным объектом от другого (других). Практическая важность концепции инкапсуляции для современных языков объектноориентированного программирования (в том числе и для языка C#) определяется следующими фундаментальными свойствами. Прежде всего, реализация концепции инкапсуляции обеспечивает совместное хранение данных (или, иначе, полей) и функций (или, иначе, методов) внутри объекта. Как следствие, механизм инкапсуляции приводит к сокрытию информации о внутреннем «устройстве» объекта данных (или, в терминах языков ООП, свойств и методов объекта) от пользователя того или иного объектно-ориентированного приложения. Таким образом, пользователь, получающий программное обеспечение как сервис, оказывается изолированным от особенностей среды реализации.
Современные языки программирования и .NET: II семестр Лекция 12: Компонентное программирование в .NET
Понятие полиморфизма в программировании Вообще говоря, под полиморфизмом понимается возможность оперировать объектами, не обладая точным знанием их типов. Рассмотрим пример полиморфной функции: void Poly(object o) { Console.WriteLine(o.ToString()); }
а также вариантов ее использования: Poly(25); Poly(“John Smith”); Poly(3.141592536m); Poly(new Point(12,45)); © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Под полиморфизмом будем иметь в виду возможность оперирования объектами без однозначной идентификации их типов. Проиллюстрируем сходные черты и особенности реализации концепции полиморфизма при функциональном и объектно-ориентированном подходе к программированию следующим примером фрагмента программы на языке C#: void Poly(object o) { Console.WriteLine(o.ToString()); }
Как видно, приведенный пример представляет собой описание полиморфной функции Poly, которая выводит на устройство вывода (например, на экран) произвольный объект o, преобразованный к строковому формату (o.ToString()). Рассмотрим ряд примеров применения функции Poly: Poly(25); Poly(“John Smith”); Poly(3.141592536m); Poly(new Point(12,45));
Заметим, что независимо от типа аргумента (в первом случае это целое число 25, во втором – символьная строка “John Smith”, в третьем – вещественное число π=3.141592536, в четвертом – объект типа Point, т.е. точка на плоскости с координатами (12,45)), обработка происходит единообразно и, как и в случае с языком функционального программирования SML, функция генерирует корректный результат.
Современные языки программирования и .NET: II семестр Лекция 12: Компонентное программирование в .NET
Компонентно-ориентированное программирование как расширение ООП Под компонентом понимается независимый модуль для повторного использования и разворачивания. Свойства компонента: 1) более крупная единица, чем объект (объект - это конструкция уровня языка программирования); 2) содержит множественные классы; 3) не зависит от языка программирования (в большинстве случаев). Вообще говоря, автор и пользователь компонента географически распределены и используют разные языки. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Обсудив концепции ООП, которые являются вполне применимыми и для компонентноориентированного программирования, рассмотрим основные особенности компонентного подхода. Во-первых, следует отметить то обстоятельство, что компонентно-ориентированный подход к проектированию и реализации программных систем и комплексов является в некотором смысле развитием объектно-ориентированного, и прежде всего практически более пригоден для разработки крупных и распределенных систем (например, корпоративных приложений). Прежде всего, сформулируем основополагающее для рассматриваемого подхода определение компонента. Под компонентом будем далее иметь в виду независимый модуль программного кода, предназначенный для повторного использования и разворачивания. Как видно из определения, применение компонентного программирования призвано обеспечить более простую, быструю и прямолинейную процедуру первоначальной инсталляции прикладного программного обеспечения, а также увеличить процент повторного использования кода, т.е. усилить основные преимущества ООП. Говоря о свойствах компонентов, следует прежде всего отметить, что это существенно более крупные единицы, чем объекты (в том смысле, что объект является конструкцией уровня языка программирования). Другими отличиями компонентов от традиционных объектов является возможность содержать множественные классы и (в большинстве случаев) независимость от языка программирования. Заметим, что, автор и пользователь компонента, вообще говоря, территориально распределены и используют разные языки. Вполне возможно, что они не только пишут программы, но и общаются на разных языках.
Современные языки программирования и .NET: II семестр Лекция 12: Компонентное программирование в .NET
Модели, поддерживающие компонентное программирование
1. Component Object Model (COM) – изначальный стандарт Microsoft для компонент. Определяет протокол для конкретизации и использования компонент внутри процесса, между процессами или между компьютерами. Основа для ActiveX, OLE и многих других технологий. Может создаваться в Visual Basic, C++, .NET, и др. 2. Java Beans – стандарт Sun Microsystems для компонентов (не является независимым от языка) 3. CORBA (громоздкий IDL-интерфейс, сложность отображения одного языка реализации в другой) © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Получив представление о компонентах и их отличиях от традиционных объектов ООП, рассмотрим существующие подходы к моделированию вариаций компонентного подхода в современной практике проектирования и реализации программных комплексов и систем. Прежде всего, поскольку основной вычислительной средой для исследования в данном курсе является Microsoft .NET, обсудим особенности модели для компонентноориентированной разработки программного обеспечения, предложенной корпорацией Microsoft. Эта модель называется компонентной объектной моделью (или Component Object Model, COM) и является изначальным стандартом, принятым для компонентной разработки приложений в корпорации Microsoft. Компонентная модель COM определяет протокол для конкретизации (т.е. создания экземпляров) и использования компонент (по аналогии с классами и объектами) как внутри одного и того же процесса, так и между различными процессами или компьютерами, предназначенными для выполнения того или иного программного проекта, основанного на компонентной технологии. Модель COM является достаточно универсальной и используется в качестве фундамента для таких технологий проектирования и реализации программного обеспечения, как ActiveX, OLE и целого ряда других технологий. Приложения для COM-модели могут создаваться средствами таких языков и сред разработки как Visual Basic, C++, .NET и др. Другим известным стандартом для компонентной модели является стандарт компании Sun Microsystems, известный как JavaBeans, который не обладает свойством независимости от языка программирования. Еще одним широко используемыми стандартом компонентного программирования является архитектура объектных запросов CORBA (несмотря на поддержку многоязычной разработки приложений, существуют сложности отображения одного языка реализации в другой, для этой цели применяется достаточно громоздкий интерфейс, основанный на специальном языке описания IDL).
Современные языки программирования и .NET: II семестр Лекция 12: Компонентное программирование в .NET
Архитектурная схема .NET Framework и Visual Studio.NET SML
C#
VB
C++
…
ASP.NET: Веб-сервисы и веб-формы
Формы Windows
ADO.NET: данные и XML Базовые классы .NET Framework
Visual Studio.NET
Common Language Specification (CLS)
Common Language Runtime (CLR) © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Кратко напомним основные аспекты архитектурного решения Microsoft .NET Framework, отметив прежде всего то обстоятельство, что важную роль играет среда разработки Microsoft Visual Studio.NET, а первостепенное значение отводится среде выполнения программ – Common Language Runtime (CLR).Среда выполнения программ CLR реализует управление памятью, типами данных, межъязыковым взаимодействием, разворачиванием (deployment) приложений. Существенным преимуществом конструктивного решения .NET является компонентноориентированный подход к проектированию и реализации программного обеспечения. Суть подхода состоит в принципиальной возможности создания независимых составляющих программного обеспечения с унифицированной интерфейсной частью для многократного повторного и распределенного использования. При этом продуктивность решения обусловлена многоязычностью интегрируемых программных проектов (концепция .NET потенциально поддерживает произвольный язык программирования, в числе наиболее известных языков – C#, Visual Basic, C++ и др.) В ходе компиляции программа на .NET-совместимом языке программирования трансформируется в соответствии с заранее заданной обобщенной спецификацией языка Common Type System (CTS). Система типов CTS полностью описывает все типы данных, поддерживаемые средой выполнения, определяет их взаимосвязи и хранит их отображения в систему типов .NET. Под Common Language Specification (или CLS) понимается набор правил, определяющих подмножество обобщенных типов данных, в отношении которых гарантируется, что они безопасны при использовании во всех языках .NET. Интерфейсы реализуются посредством форм Windows и ASP.NET для веб-приложений.
Современные языки программирования и .NET: II семестр Лекция 12: Компонентное программирование в .NET
Сборки Common Language Runtime в .NET Вообще говоря, под сборкой понимается логическая единица разворачивания приложения, содержащая манифест, метаданные, MSIL и необходимые ресурсы. Под манифестом понимается совокупность метаданных о компонентах сборки (версия, типы, зависимости и т.д.). Метаданные типов исчерпывающе описывают все типы, определенные в сборке: свойства, методы, аргументы, возвращаемые значения, атрибуты, базовые классы и т.д. Под Microsoft Intermediate Language (или MSIL, IL) понимается семейство языков, которые компилируются в IL (или управляемый код). Замечание. IL всегда компилируется в native-код до выполнения. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Обсудим средства поддержки жизненного цикла программного обеспечения в рамках компонентной идеологии подхода .NET. Для установки на компьютеры пользователей ранее созданного прикладного программного обеспечения создаются инсталляционные комплекты в форме так называемых сборок. Сборкой называется логическая единица, содержащая множество модулей, необходимых для осуществления инсталляции программного обеспечения. Сборка характеризуется уникальностью, которая обеспечивается идентификатором версии сборки и цифровой подписью автора. Сборка является самодостаточной единицей для установки программного обеспечения и не требует никаких дополнений. Возможно как индивидуальное, так и коллективное (сетевое) использование сборки на основе компонентной технологии. Сборка обеспечивает простой и удобный механизм инсталляции и экономит средства на разворачивание программного обеспечения, сводя к минимуму затраты времени и труда на установку. Описание сборки содержится в так называемом манифесте, где хранятся метаданные о компонентах сборки, идентификация автора и версии, сведения о типах и зависимостях, а также режим и политика использования. Метаданные типов манифеста исчерпывающе описывают все типы, определенные в сборке, а именно, свойства, методы, аргументы, возвращаемые значения, атрибуты, базовые классы и т.д. Семейство языков, которые компилируются в так называемый промежуточный язык (Intermediate Language или IL, т.е. в так называемый управляемый код) объединяется в Microsoft Intermediate Language или MSIL. Заметим, что промежуточный язык IL всегда компилируется в естественный (native) код до выполнения программы.
Современные языки программирования и .NET: II семестр Лекция 12: Компонентное программирование в .NET
Пространства имен в языке C# (1) Файл может содержать множество пространств имен: xxx.cs namespace A {...} namespace B {...} namespace C {...}
Samples xxx.cs
Пространства имен и классы не однозначно соответствуют каталогам и файлам: xxx.cs namespace A { class C {...} } © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Для более эффективного манипулирования системой типизации компонент создаваемого программного обеспечения в рамках модели COM, концепция .NET предусматривает механизм пространств имен (namespace). Пространством имен будем называть механизм среды Microsoft .NET, предназначенный для идентификации типов объектов языков программирования и среды реализации. Описания пространств имен по аналогии с описаниями типов данных размещаются в файлах. Перечислим основные свойства, которыми характеризуются пространства имен в среде Microsoft .NET. Прежде всего, пространства имен могут как объединять различные сборки, так и быть вложенными друг в друга. Кроме того, файлы с описаниями могут содержать множественные пространства имен. Важно отметить, что между пространствами имен и файлами не существует однозначного соответствия. Наконец, полное имя типа должно содержать все необходимые пространства имен. Приведем пример файла xxx.cs с описанием множественных пространств имен на языке C#: xxx.cs namespace A {...} namespace B {...} namespace C {...} Приведем пример файла xxx.cs с описанием пространств имен на языке C# с неоднозначным (с учетом предыдущего примера) соответствием файлов и пространств имен: xxx.cs namespace A { class C {...} }
Современные языки программирования и .NET: II семестр Лекция 12: Компонентное программирование в .NET
Пространства имен в языке C# (2) Пространства имен могут импортироваться: using System;
Одни пространства имен могут импортироваться в другие: using A; namespace B { using C; ... }
Разрешаются псевдонимы: using F = System.Windows.Forms; ... F.Button b;
для явного указания полных и сокращенных имен. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Кроме свойств, перечисленных выше, механизм пространств имен в среде вычислений .NET обладает еще целым рядом важных особенностей. Так, допускается импорт пространств имен с использованием зарезервированного слова using языка программирования C# (похожий подход реализован в модулях языка Modula-2). Проиллюстрируем эту особенность фрагментом программы на языке C#: using System;
Кроме того, существует возможность импорта одних пространств имен в другие. Проиллюстрируем это свойство фрагментом программы на языке C#: using A; namespace B { using C; ... }
Отметим также, что для явного указания полных и сокращенных имен разрешаются псевдонимы (alias). Проиллюстрируем это свойство следующим примером программы на языке C#: using F = System.Windows.Forms; ... F.Button b;
Как видно из приведенного фрагмента программы, для удобства именования стандартного пространства имен .NET под именем System.Windows.Forms применяется псевдоним F.
Современные языки программирования и .NET: II семестр Лекция 12: Компонентное программирование в .NET
Сборки в языке программирования C# (1) Под сборкой понимается самодостаточная исполняемая единица с информацией для развертывания и уникальным номером версии, содержащая типы и другие ресурсы. Сборка является атомарной единицей для развертывания. Каждый тип сборки имеет уникальный номер версии. Сборка может содержать несколько пространств имен; пространство имен может занимать несколько сборок. Сборка может состоять из нескольких файлов, объединенных в составе манифеста (аналога оглавления). © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Рассмотрим особенности использования механизма сборок, важнейшей концепции компонентного программирования, применительно к языку C#. Напомним, что под сборкой понимается самодостаточная исполняемая единица, содержащая все необходимые данные для инсталляции, развертывания и повторного использования. Сборка является минимальной единицей для развертывания приложений, представляет собой своеобразный атом компонентного программирования.
т.е.
Каждый тип сборки характеризуется уникальным идентификатором – номером версии сборки. Таким образом, каждый программный проект формируется в виде сборки, которая является самодостаточным компонентом для разворачивания, тиражирования и повторного использования. Сборка идентифицируется цифровой подписью автора и уникальным номером версии. Между сборками и пространствами имен существует следующее соотношение. Сборка может содержать несколько пространств имен. В то же время, пространство имен может занимать несколько сборок. Сборка может иметь в своем составе как один, так и из несколько файлов, которые объединяются в составе так называемого манифеста или описания сборки, который на привычном нам естественном языке аналогичен оглавлению книги. Манифест содержит метаданные о компонентах сборки, идентификацию автора и версии, сведения о типах и зависимостях, а также режим и политику использования сборки. Метаданные типов манифеста в полной мере описывают все типы, которые описаны в сборке.
Современные языки программирования и .NET: II семестр Лекция 12: Компонентное программирование в .NET
Сборки в языке программирования C# (2) Сборка в языке программирования C# является аналогом компонента в среде программирования .NET. При компиляции создается либо сборка (исполняемый EXE-файл и файл DLL-библиотеки с манифестом) либо модуль (файл .NETMODULE без манифеста). Прочие модули и ресурсы могут быть добавлены посредством компоновщика сборок. © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду В ходе обсуждения реализации механизма сборок в языке программирования C# следует отметить еще несколько важных характеристик. Прежде всего, сборка как элемент языка программирования C# является аналогом компонента в среде проектирования и реализации программного обеспечения Microsoft .NET. В результате компиляции программного кода на языке C# в среде вычислений .NET (например, в .NET Framework SDK) создается либо сборка, либо так называемый модуль. При этом сборка существует в форме исполняемого файла (с расширением EXE), а также файла динамически присоединяемой библиотеки (с расширением DLL). Естественно, в состав сборки входит манифест. Модуль представляет собой файл с расширением .NETMODULE и, в отличие от сборки, не содержит в своем составе манифеста. Заметим, что интеграция в программный проект других модулей и ресурсов (в частности, типов и метаданных) может быть осуществлена посредством системного программного обеспечения, известного под названием компоновщика сборок.
Современные языки программирования и .NET: II семестр Лекция 12: Компонентное программирование в .NET
Преимущества компонентного программирования 1.
Снижение стоимости программного обеспечения
2.
Повторное использование кода
3.
Унификация обработки объектов различной природы
4.
Менее человекозависимый процесс создания программного обеспечения
5.
Строгое математическое основание (ламбда-исчисление)
6.
Концепция универсальна и одинаково применима для функционального программирования и ООП © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Подводя итоги рассмотрения основных аспектов концепции компонентноориентированного подхода к программированию и особенностей реализации этой концепции применительно к языку программирования C#, кратко отметим достоинства подхода. Прежде всего, важным практическим следствием реализации концепции компонентного подхода для экономики программирования является снижение стоимости проектирования и реализации программного обеспечения. Еще одним существенным достоинством компонентного программирования является возможность усовершенствования стратегии повторного использования кода. Код с более высоким уровнем абстракции не требует существенной модификации при адаптации к изменившимся условиям задачи или новым типам данных. Кроме того, к преимуществам концепции компонентного программирования следует отнести унификацию обработки объектов различной природы. В самом деле, абстрактные классы и методы позволяют единообразно оперировать гетерогенными данными, причем для адаптации к новым классам и типам данных не требуется реализации дополнительного программного кода. Важно также отметить, что идеология компонентного программирования основана на строгом математическом фундаменте (в частности, в виде формальной системы ламбдаисчисления), что обеспечивает интуитивную прозрачность исходного текста для математически мыслящего программиста, а также верифицируемость программного кода. Наконец, концепция компонентного программирования является достаточно универсальной и в равной степени применима для различных подходов к программированию, включая функциональный и объектно-ориентированный.
Современные языки программирования и .NET: II семестр Лекция 12: Компонентное программирование в .NET
Вопросы, рассмотренные в рамках курса 1) объектно-ориентированный подход к программированию; 2) основные понятия ООП (объекты, классы, методы, абстракция, инкапсуляция, наследование, полиморфизм); 3) математические основы ООП (ламбда-исчисление, фреймы, решетки, коцептуализация); 4) синтаксис и семантика языков ООП (на примере C#); 5) теория типов и система типизации в .NET; 6) событийно-ориентированное программирование; 7) применение концепции .NET для реализации ООП; 8) компонентный подход к программированию © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Завершая вторую часть учебного курса, посвященного исследованию современных языков программирования (на примере языка программирования C#) и поддерживающих их сред вычислений (на примере инструментально-технологической платформы .NET), кратко резюмируем содержание рассмотренных вопросов и проблем. Прежде всего, нами был рассмотрен объектно-ориентированный подход к проектированию и реализации программного обеспечения в сопоставлении с другими подходами. Затем было дано представление о важнейших концепциях, которые составляют теоретическое и практическое основание объектно-ориентированного подхода к программированию. В частности, были рассмотрены концепции объекта, класса, метода, абстракции, инкапсуляции, наследования, полиморфизма, а также подходы к их формализации на основе исчисления ламбда-конверсий, комбинаторной логики, теории решеток и концептуализации. Далее, посредством перечисленных теорий были формализованы такие важнейшие аспекты объектно-ориентированных языков программирования, как синтаксис и семантика. Кроме того, было исследовано понятие типа, изучены основы теории типов и типизации в языках программирования, реализованных в среде вычислений .NET. После этого, мы перешли к рассмотрению вопросов, связанных с событийноориентированным программированием. Наконец, было исследована трансформация ООП в приложении к среде .NET, которая привела к появлению компонентного подхода, основанного на объектной модели COM.
Современные языки программирования и .NET: II семестр Лекция 12: Компонентное программирование в .NET
Вопросы для дальнейшего исследования (в рамках двухсеместрового расширенного курса): 1) компонентная разработка интегрированных гетерогенных программных систем на профессиональном уровне (на основе SML и C#); 2) разработка событийно-управляемых приложений; 3) строгий сравнительный анализ функционального и объектно-ориентированного подходов к программированию (на основе computer science); 4) семантика событийно-управляемого (а, возможно, и компонентно-ориентированного) программирования © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Вполне естественно, что, исходя из обширного спектра и существенной глубины рассматриваемой проблематики, ряд важнейших аспектов реализации современных языков программирования (в рамках изложенного курса) был лишь обозначен или изложен весьма конспективно. В связи с этим, в ходе дальнейшего исследования планируется систематическое изучение следующих вопросов: 1) компонентная разработка интегрированных гетерогенных программных систем на профессиональном уровне (на примере языков программирования SML и C#); 2) разработка событийно-управляемых приложений; 3) математически строгий сравнительный анализ функционального и объектноориентированного подходов к программированию на основе изученных теоретических разделов computer science; 4) формализация семантики событийно-управляемого (и, в случае достаточных ресурсов, компонентно-ориентированного) программирования. Дальнейшие исследования, согласно концепции изложения курса, будут проводиться синтетически по направлениям теоретического обоснования программирования на основе изученных формальных систем computer science и современной практики проектирования и реализации программного обеспечения на основе универсальной и прогрессивной программно-инструментальной платформы Microsoft .NET.
Современные языки программирования и .NET: II семестр Лекция 12: Компонентное программирование в .NET
Библиография (1) 1. 2. 3. 4.
Lowy J. Programming .NET Components. O’Reilly, 2003, 480 p.p. Lowy J. COM and .NET Component Services. O’Reilly, 2001, 384 p.p. Thai T.L., Lam H. .NET Framework Essentials, 2nd ed. O’Reilly, 2002, 376 p.p. Schönfinkel M. ‘Über die Bausteine der matematischen Logik, Math. Annalen 92, pp. 305-316, 1924. Translation printed as ‘On the building blocks of mathematical logic’, in van Heijenoort, J. (ed.), From Frege to Gödel, Harvard University Press, 1967 © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду К сожалению, в рамках времени, отведенных на одну лекцию, можно лишь в общих чертах охарактеризовать специфику такого многоаспектного явления, как компонентноориентированный подход к проектированию и реализации программного обеспечения. Для более детального ознакомления с особенностями, достижениями и проблемами в теории моделирования данного подхода и практики реализации связанных с ним механизмов рекомендуется следующий список литературы: 1.Lowy J. Programming .NET Components. O’Reilly, 2003, 480 p.p. 2.Lowy J. COM and .NET Component Services. O’Reilly, 2001, 384 p.p. 3.Thai T.L., Lam H. .NET Framework Essentials, 2nd ed. O’Reilly, 2002, 376 p.p. 4.Schönfinkel M. ‘Über die Bausteine der matematischen Logik, Math. Annalen 92, pp. 305-316, 1924. Translation printed as ‘On the building blocks of mathematical logic’, in van Heijenoort, J. (ed.), From Frege to Gödel, Harvard University Press, 1967 Кратко остановимся на источниках. Работа [1] посвящена программирования .NET.
проектированию
В работе [2] рассматриваются компонентной идеологии.
и
реализации
компонент
для
среды
вопросы проектирования сервисов для .NET в рамках
В работе [3] описываются основные особенности архитектурного решения .NET Framework. Работа [4] является фундаментальным исследованием в области синтаксиса и семантики ламбда-исчисления, основной формализации языков и подходов к программированию, не исключая и компонентный.
Современные языки программирования и .NET: II семестр Лекция 12: Компонентное программирование в .NET
Библиография (2) 5. 6. 7. 8. 9.
Church A. The calculi of lambda-conversion.- Princeton, 1941, ed. 2, 1951 Scott D.S. The lattice of flow diagrams.- Lecture Notes in Mathematics, 188, Symposium on Mathematics of Algorithmic Languages.- Springer-Verlag, 1971, p.p. 311-372 Wolfengagen V.E. Event-driven objects. In: Proc. CSIT’1999, Moscow, Russia, 1999, Vol.1, p.p. 88-96 Wolfengagen V.E. Fuctional notation for indexed concepts. In: Proc. WFLP’2000, Benicassim, Spain, Sept. 2000. http://www.dsic.upv.es/~wflp2000/ Scott D.S. Domains for denotational semantics. ICALP 1982, 577-613 © Учебный Центр безопасности информационных технологий Microsoft Московского инженерно-физического института (государственного университета), 2003
Комментарий к слайду Продолжим обсуждение работ, посвященных исследованию основных элементов событийно управляемого программирования. 5.Church A. The calculi of lambda-conversion.- Princeton, 1941, ed. 2, 1951 6.Scott D.S. The lattice of flow diagrams.- Lecture Notes in Mathematics, 188, Symposium on Mathematics of Algorithmic Languages.- Springer-Verlag, 1971, p.p. 311-372 7.Wolfengagen V.E. Event-driven objects. In: Proc. CSIT’1999, Moscow, Russia, 1999, Vol.1, p.p. 88-96 8.Wolfengagen V.E. Fuctional notation for indexed concepts. In: Proc. WFLP’2000, Benicassim, Spain, Sept. 2000. http://www.dsic.upv.es/~wflp2000/ 9.Scott D.S. Domains for denotational semantics. ICALP 1982, 577-613 Работа [5] является исчерпывающим описанием синтаксиса и семантики ламбдаисчисления, основной формализации языков программирования, в том числе языков компонентного программирования. В работе [6] представлен вариант подхода к семантике динамики и статики объектов в форме теории решеток, по которым «протекает» информация. В работах [7,8] исследуется событийная ориентированность объектных теорий с учетом динамики и статики объектов, а также их взаимовлияния. В работе [9] рассматриваются вопросы, связанные с развитием денотационной семантики, имеющей широкое распространение в теории моделирования объектов, и, в частности, с ее представлением посредством доменов.