Если в блоке try могут возникнуть различные исключения, то обычно используется вторая форма блока except с несколькими обработчиками исключений.
Пример 2. Обработка различных исключений.
var a,b: integer;
assign(f,'a.txt');
try
readln(a,b);
reset(f);
c:=a div b;
except
on System.DivideByZeroException do
writeln('Целочисленное деление на 0');
on System.IO.IOException do
writeln('Файл отсутствует');
end;
Часто необходимо совмещать обработку исключений и освобождение ресурсов независимо от того, произошло исключение или нет. В этом случае используются вложенные операторы try ... except и try ... finally.
Пример 3. Вложенные операторы try ... except и try ... finally.
assign(f,'a.txt');
try
reset(f);
try
try
c:=a div b;
except
on System.DivideByZeroException do
writeln('Целочисленное деление на 0');
end;
finally
close(f);
end;
except
on System.IO.IOException do
writeln('Файл отсутствует');
end;
Обратим внимание, что в данном примере исключение, связанное c целочисленным делением на 0, обрабатывается в самом внутреннем блоке try, а исключение, связанное с отсутствующим файлом - в самом внешнем. При этом, если файл был открыт, то независимо от возникновения исключения деления на 0 он будет закрыт.
Интерфейсы
Интерфейсы: обзор
Интерфейс - это тип данных, содержащий набор заголовков методов и свойств, предназначенных для реализации некоторым классом. Интерфейсы описываются в разделе type следующим образом:
ИмяИнтерфейса = interface
объявления методов и свойств
end;
Для метода приводится только заголовок, для свойства после возвращаемого типа указываются необходимые модификаторы доступа read и write.
Например:
type
IShape = interface
procedure Draw;
property X: integer read;
property Y: integer read;
end;
ICloneable = interface
function Clone: Object;
end;
Поля и статические методы не могут входить в интерфейс.
Класс реализует интерфейс, если он реализует все методы и свойства интерфейса в public-секции. Если класс не реализует хотя бы один метод или свойство интерфейса, возникает ошибка компиляции. Класс может реализовывать также несколько интерфейсов. Список реализуемых интерфейсов указывается в скобках после ключевого слова class (если указано имя предка, то после имени предка).
Например:
type
Point = class(IShape,ICloneable)
private
xx,yy: integer;
public
constructor Create(x,y: integer);
begin
xx := x; yy := y;
end;
procedure Draw; begin end;
property X: integer read xx;
property Y: integer read yy;
function Clone: Object;
begin
Result := new Point(xx,yy);
end;
procedure Print;
begin
write(xx,' ',yy);
end;
end;
Интерфейсы можно наследовать друг от друга:
type
IPosition = interface
property X: integer read;
property Y: integer read;
end;
IDrawable = interface
procedure Draw;
end;
IShape = interface(IPosition,IDrawable)
end;
Интерфейс по-существу представляет собой абстрактный класс без реализации входящих в него методов. Для интерфейсов, в частности, применимы все правила приведения типов объектов: тип объекта, реализующего интерфейс, может быть неявно приведен к типу интерфейса, а обратное преобразование производится только явно и может вызвать исключение при невозможности преобразования:
var ip: IShape := new Point(20,30);
ip.Draw;
Point(ip).Print;
Все методы класса, реализующего интерфейс, являются виртуальными без использования ключевых слов virtual или override. В частности, ip.Draw вызовет метод Draw класса Point. Однако, цепочка виртуальности таких методов обрывается. Чтобы продолжить цепочку виртуальности методов, реализующих интерфейс, в подклассах, следует использовать ключевое слово virtual:
type
Point = class(IShape,ICloneable)
...
function Clone: Object; virtual;
begin
Result := new Point(xx,yy);
end;
end;
Для интерфейсов, как и для классов, можно также использовать операции is и as:
if ip is Point then
...
var p: Point := ip as Point;
if p<>nil then
writeln('Преобразование успешно');
Реализация нескольких интерфейсов
Несколько интерфейсов могут содержать одинаковые методы или свойства. При наследовании от таких интерфейсов такие одинаковые методы или свойства сливаются в один:
type
IShape = interface
procedure Draw;
property X: integer read;
property Y: integer read;
end;
IBrush = interface
procedure Draw;
property Size: integer read;
end;
Brush = class(IShape,IBrush)
// метод Draw реализуется единожды
end;
Чтобы решить проблему с одинаковыми именами в интерфейсах, в .NET классы могут реализовывать методы интерфейсов так называемым явным образом, так что вызов метода интерфейса для переменной класса возможен только после явного приведения к типу интерфейса. В PascalABC.NET такие классы определять нельзя, однако, пользоваться такими классами, реализованными в .NET, можно. Например, тип integer явно реализует интерфейс IComparable:
var i: integer := 1;
var res : integer := IComparable(i).CompareTo(2);
// i.CompareTo(2) - ошибка компиляции
Обобщенные типы
Обобщенные типы: обзор
Обобщенным типом (generic) называется шаблон для создания класса, записи или интерфейса, параметризованный одним или несколькими типами. Класс (запись, интерфейс) образуется из шаблона класса (записи, интерфейса) подстановкой конкретных типов в качестве параметров. Параметры указываются после имени обобщенного типа в угловых скобках. Например, Stack<T> - шаблон класса списка элементов типа T, параметризованный типом T, а Stack<integer> - класс списка с элементами типа integer.
Обобщённые подпрограммы описываются здесь.
Для объявления шаблона класса используется следующий синтаксис:
type
Node<T> = class
data: T;
next: Node<T>;
public
constructor Create(d: T; nxt: Node<T>);
begin
data := d;
next := nxt;
end;
end;
Stack<T> = class
tp: Node<T>;
public
procedure Push(x: T);
begin
tp := new Node<T>(x,tp);
end;
function Pop: T;
begin
Result := tp.data;
tp := tp.next;
end;
function Top: T;
begin
Result := tp.data;
end;
function IsEmpty: boolean;
begin
Result := tp = nil;
end;
end;
Использование шаблона класса иллюстрируется ниже:
var
si: Stack<integer>;
sr: Stack<real>;
begin
si := new Stack<integer>;
sr := new Stack<real>;
for var i := 1 to 10 do
si.Push(Random(100));
while not si.IsEmpty do
sr.Push(si.Pop);
while not sr.IsEmpty do
write(sr.Pop,' ');
end.
Подстановка конкретного типа-параметра в обобщенный тип называется инстанцированием.
Обобщенные подпрограммы: обзор
Обобщенной подпрограммой (generic) называется подпрограмма, параметризованная одним или несколькими типами. Подпрограмма образуется из обобщенной подпрограммы подстановкой конкретных типов в качестве параметров. Параметры указываются после имени подпрограммы в угловых скобках.
Например, следующая обобщённая функция параметризована одним параметром:
function FindFirstInArray<T>(a: array of T; val: T): integer;
begin
Result := -1;
for var i:=0 to a.Length-1 do
if a[i]=val then
begin
Result := i;
exit;
end;
end;
var x: array of string;
begin
SetLength(x,4);
x[0] := 'Ваня';
x[1] := 'Коля';
x[2] := 'Сережа';
x[3] := 'Саша';
writeln(FindFirstInArray(x,'Сережа'));