- •Введение в c# и платформу .Net Философия .Net
- •Введение в строительные блоки платформы .Net (clr, cts и cls)
- •Роль библиотек базовых классов
- •Понятие общей системы типов (cts)
- •Понятие общеязыковой спецификации (cls)
- •Понятие общеязыковой исполняющей среды (clr)
- •Различия между сборками, пространствами имен и типами
- •Лабораторная работа №1. Создание приложений на языке c# без использования ide Роль .Net Framework 4.5 sdk
- •Построение приложений c# с использованием csc.Ехе
- •Указание целевых входных и выходных параметров
- •Ссылка на внешние сборки
- •Компиляция нескольких файлов исходного кода
- •Лабораторная работа №2. Построение приложений .Net с помощью Visual Studio Создание нового проекта
- •Использование утилиты Solution Explorer
- •Ссылка на внешние сборки
- •Утилита Object Browser
- •Фрагменты кода и технология Surround With
- •Утилита Class Designer
- •Лабораторная работа №3. Основы программирования на c# Структура простой программы c#
- •Класс System.Console
- •Форматирование числовых данных
- •Системные типы данных и соответствующие ключевые слова c#
- •Объявление и инициализация переменных
- •Иерархия классов для типов данных
- •Члены числовых типов данных
- •Члены System.Boolean
- •Члены System.Char
- •Работа со строковыми данными
- •Базовые манипуляции строками
- •Управляющие последовательности
- •Итерационные конструкции c#
- •Лабораторная работа №4. Главные конструкции программирования на с# Методы и модификаторы параметров
- •Стандартное поведение передачи параметров по значению
- •Модификатор out
- •Модификатор ref
- •Модификатор params
- •Определение необязательных параметров
- •Вызов методов с использованием именованных параметров
- •Массивы в c# Объявление и инициализация массивов
- •Определение массива объектов
- •Базовый класс System.Array
- •Управление хранилищем, лежащим в основе перечисления
- •Объявление переменных типа перечисления
- •Динамическое извлечение пар “имя/значение” перечисления
- •Типы структур
- •Объектно- ориентированное программирование на c# Лабораторная работа №5. Работа с классами Знакомство с типом класса c#
- •Размещение объектов с помощью ключевого слова new
- •Определение специальных конструкторов
- •Роль ключевого слова this
- •Еще раз о необязательных аргументах
- •Понятие ключевого слова static
- •Определение статических полей данных
- •Определение статических классов
- •Основные принципы объектно-ориентированного программирования
- •Роль инкапсуляции
- •Роль наследования
- •Роль полиморфизма
- •Лабораторная работа №6. Инкапсуляция Модификаторы доступа c#
- •Стандартные модификаторы доступа
- •Первый принцип: службы инкапсуляции c#
- •Инкапсуляция с использованием традиционных методов доступа и изменения
- •Использование свойств внутри определения класса
- •Свойства, доступные только для чтения и только для записи
- •Взаимодействие с автоматическими свойствами
- •Понятие синтаксиса инициализации объектов
- •Работа с данными константных полей
- •Понятие полей, допускающих только чтение
- •Понятие частичных типов
- •Лабораторная работа №7. Наследование Базовый механизм наследования
- •Указание родительского класса для существующего класса
- •Ключевое слово sealed
- •Управление созданием базового класса с помощью ключевого слова base
- •Хранение секретов семейства: ключевое слово protected
- •Добавление запечатанного класса
- •Реализация модели включения/делегации
- •Определения вложенных типов
- •Лабораторная работа №8. Полиморфизм
- •Переопределение виртуальных членов в ide-среде Visual Studio
- •Запечатывание виртуальных членов
- •Абстрактные классы
- •Понятие полиморфного интерфейса
- •Сокрытие членов
- •Правила приведения к базовому и производному классу
- •Ключевое слово as
- •Ключевое слово is
- •Главный родительский класс System.Object
- •Переопределение System.Object.ToString()
- •Переопределение System.Object.Equals()
- •Статические члены System.Object
- •Лабораторная работа №9. Структурированная обработка исключений
- •Роль обработки исключений .Net
- •Строительные блоки обработки исключений в .Net
- •Базовый класс System.Exception
- •Простейший пример
- •Генерация общего исключения
- •Перехват исключений
- •Конфигурирование состояния исключения
- •Исключения уровня приложения (System.ApplicationException)
- •Построение специальных исключений, способ первый
- •Построение специальных исключений, способ второй
- •Обработка нескольких исключений
- •Общие операторы catch
- •Внутренние исключения
- •Какие исключения могут генерировать методы?
- •Результат наличия необработанных исключений
- •Лабораторная работа №10. Работа с интерфейсами Понятие интерфейсных типов
- •Реализация интерфейса
- •Вызов членов интерфейса на уровне объектов
- •Получение ссылок на интерфейсы: ключевое слово as
- •Получение ссылок на интерфейсы: ключевое слово is
- •Использование интерфейсов в качестве параметров
- •Использование интерфейсов в качестве возвращаемых значений
- •Массивы интерфейсных типов
- •Явная реализация интерфейсов
- •Проектирование иерархий интерфейсов
- •Множественное наследование посредством интерфейсных типов
Еще раз о необязательных аргументах
Вспомните,
что необязательные аргументы позволяют
определять стандартные значения для
входных аргументов. Если вызывающий
код удовлетворяют эти стандартные
значения, указывать уникальные значения
не обязательно, но это можно делать,
когда объект требуется снабдить
специальными данными. Рассмотрим
следующую версию класса Motorcycle, который
теперь предоставляет несколько
возможностей конструирования объектов,
используя единственное определение
конструктора.
С помощью этого единственного конструктора можно создать объект Motorcycle, указывая ноль, один или два аргумента.
Хотя применение необязательных/именованных аргументов — очень удобный путь упрощения определения набора конструкторов, используемых заданным классом, следует всегда помнить, что этот синтаксис является допустимым только в .NET 4.0 или последующих версиях. Если требуется строить классы, которые должны выполняться на платформе .NET любой версии, лучше придерживаться классической техники цепочек конструкторов.
Реализуйте в вашем классе конструктор с необязательными параметрами
Понятие ключевого слова static
Класс C#
может определять любое количество
статических членов, которые объявляются
с использованием ключевого слова
static. При этом соответствующий член
должен вызываться непосредственно на
уровне класса, а не на переменной,
хранящей ссылку на объект. Чтобы
проиллюстрировать разницу, обратимся
к System.Console. Как уже было показано, метод
WriteLine() не вызывается на уровне объекта:
Вместо
этого статический член WriteLine() предваряется
именем класса:
Проще говоря, статические члены — это элементы, задуманные (проектировщиком класса) как общие, так что нет нужды создавать экземпляр класса перед их вызовом. Хотя в любом классе можно определять статические члены, чаще всего их можно обнаружить внутри “обслуживающих классов”. По определению обслуживающий класс — это такой класс, который поддерживает состояние на уровне объектов и не создается посредством ключевого слова new. Вместо этого обслуживающий класс открывает всю функциональность в виде членов уровня класса (т.е. статических). Например, если воспользоваться браузером объектов Visual Studio (выбрав пункт меню View→Object Browser (Вид→Браузер объектов)) для просмотра пространства имен System из сборки mscorlib.dll, можно увидеть, что все члены классов Console, Math, Environment и GC (и ряд других) открывают свою функциональность через статические члены. Это лишь несколько обслуживающих классов, определенных в библиотеках базовых классов .NET.
Опять-таки, следует помнить, что статические члены могут находиться не только в обслуживающих классах; они могут быть частью любого определения класса. Просто не забывайте, что статические члены перемещают заданный элемент на уровень класса, а не объекта.
Определение статических полей данных
Большую часть времени при проектировании класса данные определяются на уровне экземпляра; говоря иначе, это нестатические данные. Когда определяются данные уровня экземпляра, известно, что при каждом создании нового объекта этот объект поддерживает собственную независимую копию таких данных. В противоположность этому, если определены статические данные класса, эта память разделяется всеми объектами соответствующей категории. Чтобы увидеть разницу, создайте новый проект консольного приложения по имени StaticDataAndMembers и вставим в него новый класс под названием SavingsAccount.
Начнем с
определения элемента данных уровня
экземпляра (для моделирования текущего
баланса) и специального конструктора
для установки начального баланса:
При создании объектов SavingsAccount память под поле currBalance выделяется для каждого объекта. Таким образом, можно было бы создать пять разных объектов SavingsAccount, каждый с собственным уникальным балансом. Более того, если вы измените баланс на каком-нибудь одном счету, другие объекты не будут затронуты.
С другой
стороны, статические данные
распределяются однажды и разделяются
всеми объектами того же самого класса.
Добавьте в класс SavingsAccount статический
элемент данных по имени currInterestRate,
принимающий стандартное значение
0.04:
Если создать три экземпляра SavingsAccount, как показано ниже:
то размещение
данных в памяти будет выглядеть примерно
так, как показано на рис. 23.
Рис. 23. Статические данные размещаются один раз и разделяются между всеми экземплярами класса
Здесь мы
предполагаем, что все депозитные
счета должны иметь одну и ту же
процентную ставку. Поскольку статические
данные разделяются всеми объектами
той же самой категории, если вы
измените процентную ставку каким-либо
образом, то все объекты будут “видеть”
новое значение при следующем доступе
к статическим данным, поскольку все
они, в сущности, просматривают одно
и то же местоположение в памяти. Чтобы
понять, как изменять (или получать)
статические данные, понадобится
рассмотреть роль статических
методов.
Определение
статических методов
Измените
класс SavingsAccount, добавив к нему два
статических метода. Первый статический
метод (GetInterestRate()) будет возвращать
текущую процентную ставку, а второй
(SetInterestRate())позволит изменять процентную
ставку:
Рассмотрим следующий сценарий использования класса:
Вывод
предыдущего метода Main() показан ниже:
Как видите, при создании новых экземпляров класса SavingsAccount значение статических данных не сбрасывается, поскольку CLR выделяет для них место в памяти только один раз. После этого все объекты типа SavingsAccount оперируют одним и тем же значением в статическом поле currInterestRate. При проектировании любого класса C# одна из задач связана с выяснением того, какие части данных должны быть определены как статические члены, а какие — нет. Хотя на этот счет не существует строгих правил, помните, что поле статических данных разделяется между всеми объектами конкретного класса. Поэтому, если необходимо, чтобы часть данных совместно использовалась всеми объектами, то статические члены будут самым подходящим вариантом. Определение статических конструкторов
Типичный конструктор используется для установки значений данных уровня экземпляра в объекте во время его создания. Однако что случится, если вы попытаетесь присвоить значение статическому элементу данных в типичном конструкторе? Вас может удивить, когда обнаружится, что это значение сбрасывается каждый раз, когда создается новый объект! В целях иллюстрации предположим, что конструктор класса SavingsAccount изменен, как показано ниже (также обратите внимание, что поле currInterestRate больше не устанавливается при объявлении):
Теперь
рассмотрим следующий код в методе
Main():
При
выполнении предыдущего метода Main()
обнаруживается, что переменная
currInterestRate будет сбрасываться при каждом
создании нового объекта SavingsAccount,
всегда возвращаясь к значению 0.04.
Ясно, что установка значений статических
данных в нормальном конструкторе
уровня экземпляра сводит на нет весь
их смысл. Всякий раз, когда создается
новый объект, данные уровня класса
сбрасываются! Один из способов
правильной установки статического
поля состоит в использовании синтаксиса
инициализации члена, как это делалось
изначально:
Этот подход
гарантирует, что статическое поле
будет установлено только однажды,
независимо от того, сколько объектов
будет создано. Однако что, если значение
статических данных нужно получить
во время выполнения? Например, в
типичном банковском приложении значение
переменной, представляющей процентную
ставку, должно быть прочитано из базы
данных или внешнего файла. Решение
подобных задач требует контекста
метода (такого как конструктор), чтобы
можно было выполнить операторы
кода.
Именно по этой причине в C#
предусмотрена возможность определения
статического конструктора, который
позволяет безопасно устанавливать
значения статических данных. Взгляните
на следующее изменение в классе:
Выражаясь упрощенно, статический конструктор — это специальный конструктор, который является идеальным местом для инициализации значений статических данных, когда их значение не известно на момент компиляции (например, когда его нужно прочитать из внешнего файла, базы данных, сгенерировать случайное число или еще каким-то образом получить значение). Если запустить заново предыдущий метод Main(), вы увидите ожидаемый вывод. Обратите внимание, что сообщение "In static ctor!" выводится только один раз, поскольку среда CLR вызывает все статические конструкторы перед первым использованием (и никогда не вызывает их повторно для этого экземпляра приложения):
Ниже приведено несколько интересных моментов, касающихся статических конструкторов.
В отдельном классе может быть определен только один статический конструктор. Другими словами, статический конструктор нельзя перегружать.
Статический конструктор не имеет модификатора доступа и не может принимать параметров.
Статический конструктор выполняется только один раз, независимо от того, сколько объектов отдельного класса создается.
Исполняющая система вызывает статический конструктор, когда создает экземпляр класса или перед первым обращением к статическому члену этого класса.
Статический конструктор выполняется перед любым конструктором уровня экземпляра.
Учитывая сказанное, при создании новых объектов SavingsAccount значения статических данных сохраняются, поскольку статический член устанавливается только один раз внутри статического конструктора, независимо от количества созданных объектов.
Реализуйте статический конструктор для класса SavingsAccount
