Record 与 Class, Delphi有部分类改为记录了,他们是怎么释放的!


记得我是在delphi2005里面看到Record可以和Class一样定义方法(Function、Procedure)的,最近几年不像年轻时太爱看语言新特性了。Delphi XE2将正则表达式加入到了系统,成为体系的一部分 System.RegularExpressions,但是它表现出来的是TRegEx记录,对,是记录,不是类,也许是为了效率考虑,之后也从没有看过实现,虽然我们大家都知道Delhpi是最大的开源软件(从1~现在26既 DX10.3所有的代码都是公开的)!

最近想将一小片lazarus代码转回Delhpi,由于Lazarus系统自带正则表达式目前主推的是 RegExpr 类(很早就开源),将其转换到TRegEx记录,在实现上确实有改动较大举个列子,至少没有释放!

function FindOutRex(const aString: string; const aRex: string): string;
var
{$IFDEF fpc}
  RegEx: TRegExpr;
{$ELSE}
  RegEx: TRegEx;
  vM:TMatch;
{$ENDIF}
begin
  Result := ''; // 表示没有匹配的,Indicates that there is no match.
{$IFDEF fpc}
  try
    RegEx := TRegExpr.Create;
    RegEx.Expression := aRex;
    if RegEx.Exec(aString) then
      Result := RegEx.Match[0];
  finally
    RegEx.Free;
  end;
{$else}
  RegEx:=TRegEx.Create(aRex);
  vM:=RegEx.Match(aString);
  if vM.Success then
    Result := vM.Value;
{$ENDIF}
end;

如果代码中大量使用正则表达式,由于一个是类一个是记录,一个存在建立、释放,一个只用形式上的建立也就是初始化,这这样更改量太大了。

进一步跟踪发现Delphi在实现这个记录时其实用还是调用System.RegularExpressionsCore的类,也就是我们我们很早就用过的TPerlRegEx类,其实这个和lazarus里面就是一样一样的,类名现在稍有不同而已,好!现在关于这个项目中正则表达式类快速转换的问题可以很快解决了,我直接用继承类即可。

但再看看Delphi代码你应该会想到,Delphi实现类的记录化,类是要实例化为对象,然后非接口的对象要可视化释放!这个在转化后的记录是怎么释放资源的呢!

原来他是利用了”通告”,还是利用的接口特性——FNotifier: IInterface;!

其代码定义在实现段

TScopeExitNotifier = class(TInterfacedObject)
  private
    FRegEx: TPerlRegEx;
  public
    constructor Create(const ARegEx: TPerlRegEx);
    destructor Destroy; override;
    property RegEx: TPerlRegEx read FRegEx;
  end;
..
// Helper to extract RegEx object
function GetRegEx(const Notifier: IInterface): TPerlRegEx; inline;
begin
  Result := TScopeExitNotifier(Notifier).RegEx;
end;
{ TScopeExitNotifier}
constructor TScopeExitNotifier.Create(const ARegEx: TPerlRegEx);
begin
  FRegEx := ARegEx;
end;

destructor TScopeExitNotifier.Destroy;
begin
  FRegEx.Free; // 在这里释放 ,This is where the release is
  inherited;
end;
..
{ TRegEx }
constructor TRegEx.Create(const Pattern: string; Options: TRegExOptions);
begin
  FOptions := Options;
  FRegEx := TPerlRegEx.Create;
  FRegEx.Options := RegExOptionsToPCREOptions(FOptions);
  if (roNotEmpty in Options) then
    FRegEx.State := [preNotEmpty];
  FRegEx.RegEx := Pattern;
  FNotifier := TScopeExitNotifier.Create(FRegEx);
  if (roCompiled in FOptions) then
    FRegEx.Compile;
end;

那么在记录离开作用域将要释放的时候,FNotifier 自然会被nil,利用接口贴特性,这时正则表达类对象资源自然也就释放了。