Search code examples
delphipropertiesstaticdelphi-xe6finalize

Use private method/var in finalization


i have (static) Class GT_MyClass

GT_MyClass = class
private
  class var FImage : TJpegImage;

  class function GetImage: TJpegImage;
public
  property Image : TJpegImage  read GetImage;
end;

in function GetImage I´m creating FImage if it doesnt exists yet.

class function GT_Myclass.GetImage: TJpegImage;
begin
    if not Assigned(FImage) then
    begin
      FImage := TJpegImage.Create;
    end;
    Result := FImage;
end;

and in finalization i want to FreeAndNil(FImage)

finalization
  if Assigned(FImage) then
    FreeAndNil(FImage);

but in finalization block i cant see private var FImage...

Please can you help me?

Thanks!

BTW: I want to property Image be absolutely static


Solution

  • This is due to a difference in scope. In the class method, GT_MyClass.GetImage your code is in the scope of the class and so can see the class members. The finalization section executes in global scope. So you could make your code compile by qualifying the name:

    finalization
      if Assigned(GT_MyClass.FImage) then
        FreeAndNil(GT_MyClass.FImage);
    

    In fact, testing for GT_MyClass.FImage being assigned is pointless since Free already does that. So you would write:

    finalization
      FreeAndNil(GT_MyClass.FImage);
    

    Or you could provide another method of the class which better encapsulates this:

    type
      GT_MyClass = class
      private
        class var FImage : TJpegImage;
        class function GetImage: TJpegImage;
        class procedure Finalize;
      public
        property Image : TJpegImage  read GetImage;
      end;
    ....
    class procedure GT_MyClass.Finalize;
    begin
      FreeAndNil(FImage); // in scope of class, no need to qualify
    end;
    ....
    finalization
      GT_MyClass.Finalize;
    

    But this still leaves you calling a private method from outside the class which is not ideal. So you could use a class destructor, which is executed from the unit's finalization code:

    type
      GT_MyClass = class
      private
        class var FImage : TJpegImage;
        class function GetImage: TJpegImage;
        class destructor ClassDestroy;
      public
        property Image : TJpegImage  read GetImage;
      end;
    ....
    class destructor GT_MyClass.ClassDestroy;
    begin
      FreeAndNil(FImage); // in scope of class, no need to qualify
    end;
    

    No finalization code is needed, the compiler automatically makes sure the class destructor is called.