Выбрать главу

writeln(Person.Count); // обращение к классовому методу Count

end.

В отличие от классовых полей и методов, обычные поля и методы называются экземплярными. Из обычных методов можно обращаться к экземплярным и классовым полям, но из классовых методов можно обращаться только к классовым полям.

Аналогично можно определить также классовый (статический) конструктор, предназначенный для автоматической инициализации классовых полей. Классовый конструктор описывается с ключевым словом class и гарантированно вызывается перед вызовом любого статического метода и созданием первого объекта этого класса.

Например, определим в классе Person классовое поле - массив объектов типа Person - и инициализируем его в классовом конструкторе. Потом указанный массив можно использовать в реализации классовой функции RandomPerson, возвращающей случайный объект типа Person:

type

Person = class

private

class arr: array of Person;

name: string;

age: integer;

public

class constructor;

begin

SetLength(arr,3);

arr[0] := new Person('Иванов',20);

arr[1] := new Person('Петрова',19);

arr[2] := new Person('Попов',35);

end;

//...

class function RandomPerson: Person;

begin

Result := arr[Random(3)];

end;

end;

const cnt = 10;

begin

var a := new Person[cnt];

for var i:=0 to a.Length-1 do

a[i] := Person.RandomPerson;

end.

Методы расширения

Любой существующий класс, хранящийся во внешней dll, и все классы стандартной библитеки .NET можно расширить новыми методами. Такие методы расширения отличаются от обычных подпрограмм тем. что перед именем подпрограммы ставится имя расширяемого класса с точкой. Например:

procedure integer.Print;

begin

write(Self)

end;

begin

var i := 1;

i.Print;

end.

Можно расширить интерфейс, тогда все классы, реализующие этот интерфейс, получат этот метод. Например, в системном модуле PABCSystem так расширен стандартный интерфейс IEnumerable<T> методом Print:

function System.Collections.Generic.IEnumerable<T>.Print(): IEnumerable<T>;

begin

var g := Self.GetEnumerator();

if g.MoveNext() then

write(g.Current);

while g.MoveNext() do

write(' ', g.Current);

Result := Self;

end;

В результате все классы, реализующие интерфейс IEnumerable<T>, расширяются методом Print:

function System.Collections.Generic.IEnumerable<T>.Print(): IEnumerable<T>;

begin

var g := Self.GetEnumerator();

if g.MoveNext() then

write(g.Current);

while g.MoveNext() do

write(' ', g.Current);

Result := Self;

end;

С помощью методов расширения можно перегружать операции.

Для методов расширения имеется ряд ограничений:

* Методы расширения не могут быть виртуальными.

* Если метод расширения имеет то же имя, что и обычный метод, то предпочте5ние отдаётся обычному методу.

Анонимные классы

Иногда необходимо сгенерировать объект класса на лету, не описывая класс. У такого класса нет имени (он анонимный), но известен набор полей.

Объект анонимного класса создаётся следующим образом:

var p := new class(Name := 'Иванов', Age := 20);

Println(p.Name,p.Age);

У объекта p автоматически генерируются публичные поля Name и Age соответствующих типов.

Два объекта принадлежат к одному анонимному классу если они имеют одинаковый набор полей, и эти поля принадлежат к одинаковым типам. Например:

var p1 := new class(Name := 'Петров', Age := 21);

p1 := p;

Если поля безымянного класса инициализируются переменными, то имена полей можно не писать - они генерируются автоматически и их имена и типы совпадают с именами и типами переменных. Например:

var Name := 'Попова';

var Age := 23;

var p := new class(Name, Age);

Println(p.Name,p.Age);

Поля безымянного класса можно также инициализировать переменной с составным именем, имеющим точечную нотацию. В этом случае в качестве имен полей берутся последние имена в точечной нотации. Например:

var d := new DateTime(2015,5,15);

var p := new class(d.Day, d.Month, d.Year);

Println(p.Day, p.Month, p.Year);

Println(p);

Автоклассы

При описании класса перед словом class можно поставить слово auto. Такие классы называются автоклассами. Для автоклассов автоматически генерируется конструктор с параметрами, инициализирующими все поля класса, а также метод ToString, выводящий значения всех полей класса. Например:

type Person = auto class

name: string;

age: integer;

end;

var p := new Person('Иванов',20); // конструктор автокласса генерируется автоматически

writeln(p); // вызывается сгенерированный автоматически метод ToString

Здесь в отличие от действия writeln по умолчанию выводятся значения не только публичных, а всех полей.

Обработка исключений

Обработка исключений: обзор

Когда во время выполнения программы происходит ошибка, генерируется так называемое исключение, которое можно перехватить и обработать. Исключение представляет собой объект класса, производного от класса Exception, создающийся при возникновении исключительной ситуации.

Имеется ряд стандартных типов исключений. Можно также определять пользовательские типы исключений.

Если исключение не обработать, то программа завершится с ошибкой. Для обработки исключений используется оператор try ... except.

Обычно исключения возбуждаются в подпрограммах, поскольку разработчик подпрограммы, как правило, не знает, как обработать ошибочную ситуацию. В месте вызова подпрограммы уже, как правило, известно, каким образом следует обрабатывать исключение. Например, пусть разработана следующая функция:

function mymod(a,b: integer): integer;

begin

Result := a - (a div b) * b;

end;

Если вызвать mymod(1,0), то будет возбуждено исключение System.DivideByZeroException целочисленного деления на 0.

Рассмотрим наивную попытку обработать ошибочную ситуацию внутри функции mymod:

function mymod(a,b: integer): integer;

begin

if b = 0 then

writeln('Функция mymod: деление на 0');

Result := a - (a div b) * b;

end;

Подобное решение является плохим, поскольку программист, разрабатывающий функцию mymod, не знает, как она будет использоваться. Например, при вызове функции mymod в цикле мы увидим на экране многократное сообщение об ошибке.

Простейший способ - оставить исходный вариант функции и обрабатывать исключение System.DivideByZeroException: