Упаковка TStringList в записи
-
06-07-2019 - |
Вопрос
Я склонен использовать 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;
Решение
Это возможно. Создайте интерфейс, который предоставляет нужные методы / объекты:
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 . Вы также получаете Справочник разработчика Delphi от Марко только за загрузка пробной версии . Я уже купил его копию.
Есть еще один пример, который уже реализован в 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, доступного для вас.