对this question的跟进问题:(请注意,这不是重复,我在这里要求替代方案)。
有没有办法做以下工作:
type
List <T> = record
private
FList : TList <T>;
FGuard : IInterface,
procedure CheckCreated;
public
procedure Add(const Value : T);
end;
procedure List <T>.CheckCreated;
begin
if (FGuard = nil) then
begin
FList := TList <T>.Create;
FGuard := TGuard.Create (FList); // guard calls free on list in destructor
end;
end;
procedure List <T>.Add (const Value : T);
begin
CheckCreated;
FList.Add (Value);
end;
理想情况下,我想像这样使用它:
function ReturnHandles : List <THandle>;
begin
Result.Add (2);
Result.Add (3);
end;
如链接问题的答案中所解释的那样,这不起作用(这实际上很棘手)。它不会在每次调用时创建新列表。
不幸的是,这也不起作用:
function ReturnHandles : List <THandle>;
begin
Initialize (Result);
Result.Add (2);
Result.Add (3);
end;
它会泄漏保护接口和所有列表,因为Initialize
只会覆盖接口引用而不会减少引用计数。
有没有办法让这项工作?或者你会建议把这个作为一个界面而不是一个记录,只是住在施工线上?
function ReturnHandles : List <THandle>;
begin
Result := List <T>.Create;
Result.Add (2);
Result.Add (3);
end;
感谢您的帮助!
答案 0 :(得分:2)
如果我理解正确的话,这应该可以正常工作:
function ReturnHandles : List <THandle>;
begin
Finalize(Result);
Result.Add (2);
Result.Add (3);
end;
Finalize
调用将确保将所有托管类型设置为nil
,我认为这是您的意图。
此问题与您之前的问题密切相关,我认为您可以使用out
参数来简化代码。函数结果隐式为var
参数,但如果您使用显式out
参数,则会根据需要初始化托管类型。
procedure InitializeHandles(out Handles : List <THandle>);
begin
Handles.Add (2);
Handles.Add (3);
end;
就个人而言,既然你要在混合中引入一个接口,我想我会倾向于一路走下去并专门使用接口。或者使用标准类并接受try / finally life管理的需要。