Delphi 太早发布界面

Delphi releases interface too soon

我有一个 Delphi client/server 项目,它使用 RemObjects 在客户端和服务器之间进行通信。在 remobject 中定义了服务器和 public 服务函数并为其生成了接口。在某些时候,我们需要从另一个服务调用其他服务。为了做到这一点,我们创建了 class methods/functions,传递当前数据库连接和 remobjects 会话,调用所需函数的实现。例如:

class function TMyService.GetFoo(session: TROSession; conn: Connection): AnsiString;
var
    svc: TMyService;
begin
    svc := TMyService.Create(nil);
    try
      IROObjectActivation(svc).OnActivate(session.SessionID, nil);
      try
        Result := svc.GetFooImpl();
      finally
        IROObjectActivation(svc).OnDeactivation(session.SessionID);
      end;
    finally
      FreeAndNil(svc);
    end;
end;

有时,看起来是随机的,svc 似乎在 FreeAndNil 调用之前已经被释放,这会导致访问冲突。

此时,TMyService 也有一个生成的接口 IMyService,但这只包含 public 方法,而不包含实现。这就是为什么我们使用类型而不是接口来定义 svc 变量的原因。

据我所知,接口对象应该在方法结束时释放,而不是中途释放。是否有任何可以影响此行为的编译器优化?

[编辑] 对了,这个项目里也编译了FastMM4,可能对这个有一些影响。 使用 Delphi 10.3

编译的项目

如果TMyService支持接口,而你有过早释放的问题,那说明TMyServiceclass是引用计数class(换句话说,它支持接口,但引用计数未禁用)。

在这种情况下,您需要将此类对象实例存储在接口引用中以正确初始化引用计数。另外你不应该手动释放这样的对象,因为它的内存会被自动管理,如果你需要访问一些没有通过接口公开的方法,你可以通过类型转换来实现。

但是,使用未通过接口公开的方法可能会滥用 class。通常,接口包含所有要使用的方法。

class function TMyService.GetFoo(session: TROSession; conn: Connection): AnsiString;
var
    svc: IMyService;
begin
    svc := TMyService.Create(nil);
    IROObjectActivation(svc).OnActivate(session.SessionID, nil);
    try
      Result := svc.GetFooImpl();
      // or
      Result := TMyService(svc).GetFooImpl();
    finally
      IROObjectActivation(svc).OnDeactivation(session.SessionID);
    end;
end;

是否需要为 IROObjectActivation 使用类型转换取决于 IMyService 的声明。可能你不需要 IMyService 接口,你可以只使用 IROObjectActivation.