
- •С# и объектно-ориентированное программирование. Содержание
- •Разбор простой программы на с#.
- •Варианты метода Main ()
- •Формальное определение класса в с#
- •2.1Ссылки на самого себя
- •Построение цепочки вызовов конструкторов с использованием this.
- •Модификаторы доступа с#
- •Средства инкапсуляции с#
- •Инкапсуляция с использованием традиционных методов доступа и изменения
- •Инкапсуляция с использованием свойств .Net
- •Свойства, доступные только для чтения и только для записи
- •Статические свойства
- •Статические конструкторы
- •Наследование в с#
- •Работа с конструктором базового класса
- •Множественное наследование.
- •Ключевое слово sealed
- •Поддержка полиморфизма в с#
- •Ключевые слова virtual и override
- •Абстрактные классы
- •Полиморфный интерфейс
- •Сокрытие методов
- •Правила приведения к базовому и производному классу
- •Ключевое слово as
- •Ключевое слово is
- •Применение модели включения – делегирования.
- •Определение вложенных типов
- •Обработка исключений
- •Роль обработки исключений в .Net
- •Составляющие процесса обработки исключений в .Net
- •Генерация общего исключения
- •Перехват исключений
- •Создание специальных исключений, способ первый
- •Обработка нескольких исключений.
- •Блок finally
- •Замечания по работе с исключениями
- •Время жизни объектов
- •Базовые сведения о времени жизни объектов
- •Роль корневых элементов приложения
- •Поколения объектов
- •Параллельная сборка мусора в версиях .Net 1.0 - .Net 3.5
- •Фоновая сборка мусора в версии .Net 4.0
- •Создание финализируемых объектов
- •Описание процесса финализации
- •Создание высвобождаемых объектов
- •Повторное использование ключевого слова using в с#
- •Взаимодействие со сборщиком мусора
- •Принудительная активизация сборки мусора
- •Создание финализируемых и высвобождаемых типов
- •Формализованный шаблон очистки
Повторное использование ключевого слова using в с#
При работе с управляемым объектом, который реализует интерфейс IDisposable, довольно часто требуется применять структурированную обработку исключений, гарантируя, что метод Dispose() типа будет вызываться даже в случае возникновения какого-то исключения:
static void Main(string [ ] args)
{
MyResourceWrapper rw = new MyResourceWrapper ();
try
{
// Использование членов rw.
}
finally
{
// Обеспечение вызова метод Dispose() в любом случае,
//в том числе при возникновении ошибки.
rw.Dispose ();
}
}
Хотя это является замечательными примером "безопасного программирования", истина состоит в том, что очень немногих разработчиков прельщает перспектива заключать каждый очищаемый тип в блок try/finally лишь для того, чтобы гарантировать вызов метода Dispose(). Для достижения аналогичного результата, но гораздо менее громоздким образом, в С# поддерживается специальный фрагмент синтаксиса, который выглядит следующим образом:
static void Main(string [ ] args)
{
// Метод Dispose() вызывается автоматически
// при выходе за пределы области действия using.
using(MyResourceWrapper rw = new MyResourceWrapper ())
{
// Использование объекта rw
}
}
Метод Main:
static void Main(string [ ] args)
{
// Метод Dispose() вызывается автоматически
// при выходе за пределы области действия using.
using(MyResourceWrapper rw = new MyResourceWrapper())
{
// Использование объекта rw.
}
}
Если теперь просмотреть CIL-код этого метода Main() с помощью утилиты ildasm.ехе, то обнаружится, что синтаксис using в таких случаях на самом деле расширяется до логики try/finally, которая включает в себя и ожидаемый вызов Dispose():
.method private hidebysig static void Main(string [ ] args) cil managed
{
............
.try
{
} // end .try
finally
{
..........
IL_0012: callvirt instance void
SimpleFinalize. MyResourceWrapper::Dispose()
} // end handler
...........
} // end of method Program::Main
На заметку! При попытке применить using к объекту, который не реализует интерфейс IDisposable, на этапе компиляции возникнет ошибка.
Важно! В настоящее время, к сожалению, ключевое слово using в С# имеет двойное значение (поскольку служит и для добавления ссылки на пространства имен, и для вызова метода Dispose()). Тем не менее, при работе с типами .NET, которые поддерживают интерфейс IDisposable, данная синтаксическая конструкция будет гарантировать автоматический вызов метода Dispose() в отношении соответствующего объекта при выходе из блока using.
Взаимодействие со сборщиком мусора
В библиотеках базовых классов доступен класс по имени System.GC, который позволяет программно взаимодействовать со сборщиком мусора за счет обращения к его статическим членам. Необходимость в непосредственном использовании этого класса в разрабатываемом коде возникает крайне редко (а то и вообще никогда). Обычно единственным случаем, когда нужно применять члены System.GC, является создание классов, предусматривающих использование на внутреннем уровне неуправляемых ресурсов. Это может быть, например, класс, работающий с основанным на С интерфейсом Windows API за счет применения протокола вызовов платформы .NET, или какая-то низкоуровневая и сложная логика взаимодействия с СОМ. В табл. 3 приведено краткое описание некоторых наиболее интересных членов класса System.GC (полные сведения можно найти в документации .NET Framework 4.0 SDK).
Таблица 3.
Член |
Назначение |
AddMemorуPressure(), RemoveMemoryPressure() |
Позволяют указывать числовое значение, отражающее "уровень срочности", который вызывающий объект применяет в отношении к сборке мусора. Следует иметь в виду, что эти методы должны изменять уровень давления в тандеме и, следовательно, никогда не устранять больше давления, чем было добавлено |
Collect() |
Заставляет сборщик мусора провести сборку мусора. Должен быть перегружен так, чтобы указывать, объекты какого поколения подлежат сборке, а также какой режим сборки использовать (с помощью перечисления GCCollectionMode) |
CollectionCount() |
Возвращает числовое значение, показывающее, сколько раз объектам данного поколения удалось переживать процесс сборки мусора |
GetGeneration() |
Возвращает информацию о том, к какому поколению в настоящий момент относится объект |
GetTotalMemory() |
Возвращает информацию о том, какой объем памяти (в байтах) в настоящий момент занят в управляемой куче. Булевский параметр указывает, должен ли вызов сначала дождаться выполнения сборки мусора, прежде чем возвращать результат |
MaxGeneration |
Возвращает информацию о том, сколько максимум поколений поддерживается в целевой системе. В .NET 4.0 поддерживается всего три поколения: 0, 1 и 2 |
SuppressFinalize() |
Позволяет устанавливать флаг, указывающий, что для данного объекта не должен вызываться его метод Finalize() |
WaitForPendingFinalizers() |
Позволяет приостанавливать выполнение текущего потока до тех пор, пока не будут финализированы все объекты, предусматривающие финализацию. Обычно вызывается сразу же после вызова метода GC.Collect() |
Рассмотрим применение System.GC для получения касающихся сборки мусора деталей на примере следующего метода Main(), в котором используются сразу несколько членов System.GC:
static void Main(string [ ] args)
{
// Вывод подсчитанного количества байтов в куче.
Console.WriteLine("Estimates bytes on heap: {0}",
GC.GetTotalMemory(false));
// Отсчет для MaxGeneration начинается с нуля,
//поэтому для удобства добавляется 1.
Console.WriteLine("This OS has @} object generations.\n",
(GC.MaxGeneration + 1));
Car refToMyCar = new Car("Zippy", 100);
Console.WriteLine(refToMyCar.ToString());
// Вывод информации о поколении объекта refToMyCar.
Console.WriteLine("Generation of refToMyCar is: @ 1",
GC.GetGeneration(refToMyCar));
}