我最近偶然发现了由我编写的一些非常旧的代码引起的问题,这显然假设with
语句中使用的接口引用将在with
- 块被释放后立即释放 - 有点像隐式try-finally
- 块(类似于C#的using
- 语句,如果我理解正确的话)。
显然(在Delphi 2009中)这不是(不再是?)的情况。有谁知道这发生的时间?或者我的代码开始时是完全错误的?
澄清一下,这是一个简化的例子:
type
IMyIntf = interface;
TSomeObject = class(TInterfacedObject, IMyIntf)
protected
constructor Create; override; // creates some sort of context
destructor Destroy; override; // cleans up the context created in Create
public
class function GetMyIntf: IMyIntf; //a factory method, calling the constructor
end;
procedure TestIt;
begin
DoSomething;
with (TSomeObject.GetMyIntf) do
begin
DoStuff;
DoMoreStuff;
end; // <- expected: TSomeObject gets destroyed because its ref.count is decreased to 0
DoSomethingElse;
end; // <- this is where TSomeObject.Destroy actually gets called
每当有人开始陈旧的“with
是邪恶的”论证时,这总是我心中的一个例子让我继续“是的,但......”。好像我错了......任何人都可以确认吗?
答案 0 :(得分:17)
Pascal / Delphi中的with
保留字仅用于轻松访问记录或对象/类的成员(即为了不提记录/对象/类的名称)。它与C#with
与垃圾收集有很大不同。自records
出生之日起,它就以Pascal语言存在,以简化代码调用许多数据成员(当时简称为“字段”)。
总而言之,with
与垃圾收集,内存释放或对象实例的破坏无关。在with
标题处构造的对象之前可能已经在单独的代码行中初始化,它们是相同的。
答案 1 :(得分:3)
此WITH行为从未改变过。要达到预期的行为,您可以通过以下方式更改代码:
procedure TestIt;
var
myIntf: IMyIntf;
begin
DoSomething;
myIntf := TSomeObject.GetMyIntf
DoStuff;
DoMoreStuff;
myIntf := nil; // <- here is where TSomeObject.Destroy called
DoSomethingElse;
end;
或者您可以在程序中执行此操作:
procedure TestIt;
procedure DoAllStuff;
var
myIntf: IMyIntf;
begin
myIntf := TSomeObject.GetMyIntf
DoStuff;
DoMoreStuff;
end; // <- here is where TSomeObject.Destroy called
begin
DoSomething;
DoAllStuff;
DoSomethingElse;
end;