Упаковка TStringList в запись
Я склонен использовать Delphi TStringList для манипулирования текстом, поэтому я пишу много процедур / функций, таких как:
var
TempList: TStringList;
begin
TempList:= TStringList.Create;
try
// blah blah blah do stuff with TempList
finally
TempList.Free;
end;
end;
Было бы неплохо отключить создание и освобождение для такого общего служебного класса.
Поскольку теперь у нас есть записи с методами, можно ли обернуть класс, такой как TStringList, в запись, чтобы я мог просто иметь:
var
TempList: TRecordStringList;
begin
// blah blah blah do stuff with TempList
end;
3 ответа
Возможно. Создайте интерфейс, который предоставляет нужные вам методы / объекты:
type
IStringList = interface
procedure Add(const s: string); // etc.
property StringList: TStringList read GetStringList; // etc.
end;
Реализуйте интерфейс и сделайте так, чтобы он был настоящим TStringList
:
type
TStringListImpl = class(TInterfacedObject, IStringList)
private
FStringList: TStringList; // create in constructor, destroy in destructor
// implementation etc.
end;
Затем выполните запись:
type
TStringListRecord = record
private
FImpl: IStringList;
function GetImpl: IStringList; // creates TStringListImpl if FImpl is nil
// returns value of FImpl otherwise
public
procedure Add(const s: string); // forward to GetImpl.Add
property StringList: TStringList read GetStringList; // forward to
// GetImpl.StringList
// etc.
end;
Тот факт, что внутри записи есть интерфейс, означает, что компилятор будет обрабатывать подсчет ссылок автоматически, вызывая _AddRef и _Release, когда копии создаются и уничтожаются, поэтому управление временем жизни происходит автоматически. Это работает для объектов, которые никогда не будут содержать ссылку на себя (создание цикла) - подсчет ссылок требует различных приемов, чтобы преодолеть циклы в графе ссылок.
Если вам повезло перейти на Delphi 2009, проверьте работу Барри с помощью умных указателей.
TSmartPointer<T: class> = record
strict private
FValue: T;
FLifetime: IInterface;
public
constructor Create(const AValue: T); overload;
class operator Implicit(const AValue: T): TSmartPointer<T>;
property Value: T read FValue;
end;
Они действительно классные, но требуют общих и анонимных методов. Если вы не обновились до Delphi 2009, сделайте это сейчас! Особенно, когда они предлагают свое специальное предложение BOGO. Вы также получаете бесплатное руководство Marco Delphi Developer Handbook только для загрузки пробной версии. Я уже купил его копию тоже.
Есть еще один пример, уже реализованный в CC.
StringList - это то же самое, что и TStringList, за исключением того, что это тип значения. Это не должно быть создано, уничтожено или помещено в попытку / наконец. Это сделано компилятором для вас. Для них практически нет специальных штрафов за производительность:
var strings: StringList; astr: string; begin strings.Add('test1'); strings.Add('test2'); aStr := string(strings); RichEdit.Lines.AddStrings(strings); end;
Код можно использовать в качестве шаблона для переноса любого объекта TObject в качестве типа класса значений.
В нем уже есть все для TStringList для вас.