泛型中永远不会调用基类的 Free() 过程

Wes*_*ato 0 delphi generics

在我的代码中,当我调用Free()该方法时,永远不会调用该类的方法。是否可以在不强制演员的情况下解决这个问题?我尝试使用RTTI,但没有成功。TFirstReleaseInstance()TFirst

这可行,但它没有正确使用泛型:

TFirst(Self.FInstance).Free;
Run Code Online (Sandbox Code Playgroud)

欢迎任何建议,谢谢。

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TSingleton<T: class, constructor> = class
  strict private
    class var FInstance: T;
  public
    class function GetInstance: T;
    class procedure ReleaseInstance;
  end;

type
  TFirst = class
  public
    procedure Free;
  end;

type
  TSecond = class(TFirst)
  end;

type
  TMySingleton = TSingleton<TSecond>;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TSingleton<T> }

class function TSingleton<T>.GetInstance: T;
begin
  if not Assigned(Self.FInstance) then
    Self.FInstance := T.Create;

  Result := Self.FInstance;
end;

class procedure TSingleton<T>.ReleaseInstance;
begin
  if Assigned(Self.FInstance) then
    FreeAndNil(T(TClass(Self.FInstance)));
end;


{ TFirst }

procedure TFirst.Free;
begin
  // It's not called
  inherited Free;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
   TMySingleton.GetInstance;
   TMySingleton.ReleaseInstance;
end;

end.
Run Code Online (Sandbox Code Playgroud)

Rem*_*eau 10

您的TFirst.Free()方法隐藏了继承的TObject.Free()方法,这并不是virtual说后代无法覆盖它。

TFirst.Free()你根本不需要你的方法,你应该重写虚拟Destroy()析构函数,它TObject.Free()(因此FreeAndNil())需要你:

type
  TFirst = class
  public
    destructor Destroy; override;
  end;

destructor TFirst.Destroy;
begin
  // ...
  inherited Destroy;
end;
Run Code Online (Sandbox Code Playgroud)

另外,声明:

FreeAndNil(T(TClass(Self.FInstance)));
Run Code Online (Sandbox Code Playgroud)

当您将对象指针类型转换为类类型时,它既过于冗长又完全错误。它应该简单地是这样的:

FreeAndNil(Self.FInstance);
Run Code Online (Sandbox Code Playgroud)

因为FInstance是一个对象指针,并且FreeAndNil()释放对象。

另外,您不需要Assigned()在使用FreeAndNil()(或TObject.Free()) 之前进行检查,因为它会在内部为您处理该问题。所以,ReleaseInstance()可以简单地这样代替:

class procedure TSingleton<T>.ReleaseInstance;
begin
  FreeAndNil(Self.FInstance);
end;
Run Code Online (Sandbox Code Playgroud)

  • @WesleyBobato“*调用 FreeAndNil(Self.FInstance);它不会调用 TFirst 类的 Free 方法*” - 不应该这样做,因为它会调用 `TObject.Free` 。“*我需要流程通过 TFirst 类的 Free 方法*” - 那么你不能使用`FreeAndNil()`,你必须直接调用`TFirst.Free`,例如:`Self.FInstance 。自由的; Self.FInstance := nil;` 否则,请按照我在答案中所述更改您的设计。“*这是强制性的,因为它已声明*” - 这是一个糟糕/不正确的设计,恕我直言 (5认同)
  • @WesleyBobato 不要抱怨你错误的类设计不起作用,按照雷米描述的那样修复它,然后它就会按预期工作! (3认同)