понедельник, ноября 13, 2006

Ловкость рук, и ни какого мошенства

Задача: дан класс имеющий приватный TThreadList (список с thread-safe доступом) и содержащий некие объекты. Нужно написать метод предоставляющий безопасный доступ к содержимому списка, без доступа пользователя к объекту-списку.

На первый взгляд задача совсем не простая т.к. для того чтоб обеспечить безопасный доступ необходимо вызывать методы блокировки/разблокировки объекта-списка, а условия нам этого не позволяют. На помощь приходят... интерфейсы (ну если быть точным, то лишь механизм подсчета их ссылок).

Решение: Определяем интерфейс IObjectProvider, который будет возвращать наш метод.

Type

IObjectProvider = Interface

Function GetObject : TObject;

Property Object : TObject Read GetObject;

End;

Затем описываем класс TObjectProvider, который реализует описанный ранее интефейс.

Type

//
TObjectProvider = Class(TInterfacedObject, IObjectProvider)

Private

FList : TThreadList;
FObject : TObject;

Public

Constructor Create(Const AList : TThreadList; AIndex : Integer);
Destructor Destroy; Override;

Function GetObject : TObject;

End;
//

// Реализация конструктора
Begin

FList := AList;
FObject := TObject(FList.LockList.Items[AIndex]);

End;
//

// Реализация деструктора
Begin

FList.UnlockList;
Inherited;

End;
//

// Реализация метода GetObject
Begin

Result := FObject;

End;
//


Теперь можно реализовать и наш метод:

Function SafeGetObject(AIndex : Integer) : IObjectProvider;
Begin

Result := TObjectProvider.Create(ThreadSafeList, AIndex);

End;

Как видно из кода, метод возвращает не сам объект, а интерфейс объекта-провайдера, для обеспечения безопасности. Пользователь вызвав метод и раскрыв его оператором with, получает в эксклюзивное пользование затребованный объект, а после завершения работы с объектом сработает механизм подсчета ссылок и будет вызван деструктор объекта-провайдера, который в свою очередь разблокирует список, после чего объект-провайдер будет разрушен.


Пример:

With SafeGetObject(5) Do
Begin

Object.Method;
...
Object.Method;

End;

воскресенье, ноября 12, 2006

Выравнивание вариантной части

Сегодня столкнулся с интересной штукой: вариантные поля (описанные с использованием case) записи могут быть выровнены по разному (ну компилятору ес-но виднее). В смысле не гарантируется что начало каждого вариантного поля будет сразу после последнего описанного не вариантного (или начала записи). Об этом, по большому счету, можно и не беспокоится до тех пор пока не придется обращаться к полям по смещению ;). Но об этом нужно помнить и быть аккуратным.

p.s. На packed записях не проверял.