1

我有一个 Delphi 客户端/服务器项目,它使用 RemObjects 进行客户端和服务器之间的通信。在 remobject 中定义了服务器和公共服务功能并为其生成接口。在某些时候,我们需要从另一个服务调用其他服务。为了做到这一点,我们创建了类方法/函数,传递当前数据库连接和 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;

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

此时,TMyService 也有一个生成的接口 IMyService,但这仅包含公共方法,而不包含实现。这就是我们使用类型而不是接口来设计svc变量的原因。

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

[edit] 顺便说一下,这个项目里也编译了FastMM4,可能对这个有一些影响。使用 Delphi 10.3 编译的项目

4

1 回答 1

2

如果TMyService支持接口,并且你有过早释放的问题,这意味着TMyService类是引用计数类(换句话说,它支持接口,但引用计数没有被禁用)。

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

但是,使用未通过接口公开的方法是对类的潜在滥用。通常,接口包含所有要使用的方法。

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;

是否需要使用 typecastIROObjectActivation取决于IMyService. 可能你不需要 IMyService 接口,你可以使用IROObjectActivation.

于 2021-02-18T15:16:22.873 回答