
- •Программирование и алгоритмические языки. Курс за третий семестр.
- •Введение в объектно-ориентированное программирование (ооп)
- •Идеологический обзор
- •Базовые принципы ооп
- •Наследование имён. Наследование значений.
- •Коллизия
- •Что такое имя процедуры?
- •Ооп как оперирование типами
- •Именование типов в c# Тип данных «класс»
- •Конструкторы и деструкторы
- •И нкапсуляция данных
- •Наследование (краткое введение)
- •Наследование реализации как уточнение семантики типа
- •Пополнение и переопределение методов Отношение пополнения интерфейса
- •Открытие реализации для проектирования классов - опция protected
- •Полиморфизм Полиморфизм как уточнение семантики типа переменной
- •Динамические методы как поддержка полиморфизма- опции static, virtual, override
- •Событийное программирование Обработка событий
- •Идея: Когда что-то вставляется, срабатывает некоторый предикат. Например, после вызывается команда проверки, каскадного удаления или какая-нибудь другая команда. Генераторы и приёмники сообщений
- •Событийное программирование нужно:
- •Событийный стиль в процедурном программировании - управление данными (на примере)
- •Событийное программирование в c# (delegate, event)
- •Введение в компонентное программирование
- •Объекты, реализующие интерфейсы
- •Частный случай общей проблемы взаимодействия программного обеспечения разных производителей на уровне исполняемого кода
- •Базовый интерфейс компонент
- •Проблема множественности иерархий
- •Коллизия имён
- •Коллизия реализации
- •«Симметричное» решение – агрегаты (декартовы произведения классов)
- •Множественное наследование
- •«Асимметричное» решение - именованные интерфейсы
- •Основные отличия интерфейса и абстрактного класса
- •Наследование интерфейса (компонентный подход)
- •Обработка исключений в ооп
- •Определение и генерация исключений в c#
- •Выбрасывание исключений
- •Захват исключения
- •Блок finally
- •Коды программ
Выбрасывание исключений
В теле try-блока может возникнуть исключительная ситуация, приводящая к выбрасыванию исключений.
throw – оператор, выбрасывающий исключения.
Но throw может быть частью программного текста try-блока и выполняться, когда в результате проведенного анализа становится понятным, что дальнейшая нормальная работа невозможна.
Синтаксически оператор throw имеет вид:
throw [выражение]
Выполнение оператора throw приводит к тому, что нормальный процесс вычислений на этом прекращается. Если это происходит в охраняемом try-блоке, то начинается этап «захвата» исключения одним из обработчиков исключений.
Захват исключения
Catch- блок - обработчик исключения имеет следующий синтаксис:
catch (T e)
{
...
}
Класс T, указанный в заголовке catch-блока, должен принадлежать классам исключений.
Блок catch с формальным аргументом e класса T потенциально способен захватить текущее исключение, если и только если объект текущего исключения совместим по присваиванию с объектом e.
Потенциальных захватчиков может быть много, исключение захватывает лишь один - тот из них, кто стоит первым в списке проверки. Каков порядок проверки? Он довольно естественный. Вначале проверяются обработчики в порядке следования их за try-блоком, и первый потенциальный захватчик становится активным, захватывая исключение и выполняя его обработку. Отсюда становится ясно, что порядок следования в списке catch-блоков крайне важен. Первыми идут наиболее специализированные обработчики, далее по мере возрастания универсальности.
try-блок может быть вложен в другой try-блок. Когда же будут исчерпаны списки вложенных блоков, а потенциальный захватчик не будет найден, то произойдет подъем по стеку вызовов.
Цепочка вызовов, хранящаяся в стеке вызовов
(цепочка вызовов начинается с процедуры Main).
Исключение возникло в последнем вызванном методе цепочки - на рисунке метод r5. Если у этого метода не нашлось обработчиков события, способных обработать исключение, то это пытается сделать метод r4, вызвавший r5. Если вызов r5 находится в охраняемом блоке метода r4, то начнет проверяться список обработчиков в охраняемом блоке метода r4. Этот процесс подъема по списку вызовов будет продолжаться, пока не будет найден обработчик, способный захватить исключение, или не будет достигнута начальная точка - процедура Main. Если и в ней нет потенциального захватчика исключения, то сработает стандартный обработчик, прерывающий выполнение программы с выдачей соответствующего сообщения.
Таким образом, обработку возникшей исключительной ситуации могут выполнять несколько обработчиков, которые принадлежат разным уровням цепочки вызовов.
Блок finally
Синтаксис:
Что делать, когда не видно метода обработки исправления ошибки?
Как минимум, завершить процедуру с наименьшими потерями, в идеале, деинициализировать, сделать откат, не навредить (понятие транзакции).
try P
finally Pfin
Процедура Pfin работает в любом случае, вне зависимости от того, произошла ошибка или нет.
Освобождение ресурсов, занятых try-блоком, выполняет finally-блок. Если try-блок присутствует, то finally-блок выполняется всегда (сразу же после завершения работы try-блока (как бы последний ни завершился)).
Блок try может завершиться вполне нормально (без всяких происшествий), т.е. управление достигнет конца блока.
Впрочем, выполнение try-блока может быть:
- прервано оператором throw
- управление может быть передано другому блоку из-за выполнения таких операторов, как goto, return
Прежде чем произойдет захват исключения, предварительно будет выполнен finally-блок, который освобождает ресурсы, занятые try-блоком, а параллельно будет происходить освобождение стека от локальных переменных.
Схема обработки исключительных ситуаций, предложенная в языке C#, обладает одним существенным изъяном - ее можно применить некорректно. Она позволяет, в случае возникновения исключительной ситуации, уведомить о ее возникновении и спокойно продолжить работу, что, в конечном счете, приведет к неверным результатам. Из двух зол - прервать вычисление с уведомлением о невозможности продолжения работы или закончить вычисления с ошибочным результатом вычисления - следует выбирать первое. Некорректно применённая схема C# приведет к ошибочным результатам.
Обработчик исключения должен позаботиться о восстановлении состояния, предшествующего вызову модуля, который привел к исключительной ситуации, и это гарантирует нахождение всей системы в корректном состоянии.
//Задача: обработка исключительной ситуации
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class MyException : Exception // класс Exception- возможность получать пользоватеьские исключения
{
string Info; // некая информация об ошибке (исключительной ситуации)
public MyException(); // конструктор по умолчанию
public MyException(string Message) // конструктор для порождения ошибок
{
}
}
class ExceptionHandlingPattern //стандартная схема обработки исключительных ситуаций
{
//Заглушки. По умолчанию параметр - текущее состояние
//В конкретной ситуации - относящаяся к ней часть
private void MakeJob() { } // сделать некую работу
private void MakeOtherJob() { } // продолжить работу
private bool CheckState() { return true; } // проверить состояние
private void CorrectState() { Console.WriteLine("Попытка самостоятельно исправить ситуацию"); }//исправить состояние
public void TryToMakeJob() //попытаться сделать работу
{
bool Success; //успех выполнения
bool Danger; // риск невыполнения
int MaxCount = 0; //максимальное число попыток выполнения
int Count = 0; // фактическое число попыток выполнения
do
{
Success = true; //успех
try
{
MakeJob();
Danger = CheckState(); //возможно ли продолжение
if (Danger)
{
MyException ThisException = MyException(); //оформирование исключения
throw (ThisException);
}
MakeOtherJob(); //нормальное продолжение
}
catch (MyException me)
{
Success = false;
if (Count <= MaxCount)
{
Count++;
//level+=1; стек вызовов
CorrectState(); //корректировка ситуации
}
else
{
//level-=1 //откат
MyException ThisException = new MyException();
throw (ThisException);
}
}
}
while (!Success);
}
}//class
class Program
{
static void Main(string[] args)
{
//int level=0;
// конкретный пример- открыть и обработать файл
ExceptionHandlingPattern test = new ExceptionHandlingPattern();
try
{
test.TryToMakeJob();
}
catch (MyException ThisException)
{
// изменить начальное состояние
Console.WriteLine(ThisException.Message);
}
//catch() {} ...catch() {}
finally
{// финализация. Получилось или нет - восстановление среды
}
}
}
}
В теле охраняемого блока анализируется возможность возникновения исключительной ситуации и, в случае обнаружения опасности, выбрасывается собственное исключение, класс которого задан программно. В соответствии с этим тело try-блока содержит вызов метода MakeJob. Поскольку остается истинной переменная Success, которой установлено значение true в начале try-блока, то цикл while, окаймляющий охраняемый блок, и его обработчики исключений также успешно завершаются.
В программе реализован только один catch-блок. В общем случае их может быть несколько, но все они строятся по единому образцу. Предполагается, что обработчик исключения может сделать несколько попыток исправить ситуацию, после чего повторно выполняется охраняемый блок. Если же число попыток, за которым следит переменная count, превосходит максимально допустимое, то обработчик выбрасывает новое исключение, задавая дополнительную информацию и передавая тем самым обработку ошибки на следующий уровень - вызываемой программе.
Когда число попыток еще не исчерпано, обработчик исключения переменной Success выдает значение false, гарантирующее повтор выполнения try- блока, увеличивает счетчик числа попыток и пытается исправить ситуацию.
Использование обработчиков исключений, как и любых других событий, предполагает явно или неявно деление «клиент-сервер».