Skip to content

generics with specialization to <class, constructor> do not accept overriding methods of Tobject

The idea was to write a generic class that would add interface support to classes that are not derived from TinterfacedObject, like TStringlist. If I apply below code in non-generic way, this works fine, but: This fails, but the compiler could know by the restriction that all methods of TObject are available?

{$mode delphi}{$modeswitch typehelpers}
uses classes;

Procedure HandleError (Errno : TExitCode); external name 'FPC_HANDLEERROR';

type
  TInterfaced<T:class,constructor> = class(T,Iinterface)
  private
    frefcount:integer;
    FDestroyCount:integer;
  public
    function QueryInterface(
      {$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
    function _AddRef : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
    function _Release : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
    destructor destroy;override;// fails
    constructor create;
    procedure AfterConstruction;override;// fails    
    procedure BeforeDestruction;override;// fails
    class function NewInstance : TObject;override;// fails
  end;

    constructor TInterfaced<T>.create;
    begin
      inherited;
      frefcount := 0;
      FDestroyCount:=0;
    end;

    function TInterfaced<T>.QueryInterface(
      {$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
     begin
       if getinterface(iid,obj) then
         result:=S_OK
       else
         result:=longint(E_NOINTERFACE);
     end;

    function TInterfaced<T>._AddRef : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
    begin
       _addref:=interlockedincrement(frefcount);
    end;

    function TInterfaced<T>._Release : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
    begin
      _Release:=interlockeddecrement(frefcount);
      if _Release=0 then
      begin
        if interlockedincrement(fdestroycount)=1 then
          self.destroy;
      end;
    end;

   destructor TInterfaced<T>.Destroy;
   begin
     FRefCount:=0;
     FDestroyCount:=0;
     inherited Destroy;
   end;

   procedure TInterfaced<T>.AfterConstruction;
   begin
     inherited;
     { we need to fix the refcount we forced in newinstance }
     { further, it must be done in a thread safe way        }
     if frefcount > 0 then
       interlockeddecrement(frefcount);
   end;

    procedure TInterfaced<T>.BeforeDestruction;
    begin
      if frefcount<>0 then
        HandleError(204);
      inherited;
    end;

    class function TInterfaced<T>.NewInstance : TObject;
    begin
      NewInstance:=inherited NewInstance;
      if NewInstance<>nil then
        TInterfaced<T>(NewInstance).frefcount:=1;
    end;
   
var
  list:iinterface;
begin
  List := TInterfaced<TStringList>.create;
  assert(assigned(list));
  with list as tstringlist do
  begin
    add('some text');
    writeln(text);
  end;
end.

This fails, but the compiler could know by the restriction that all methods of TObject are available.

Edited by Thaddy de Koning
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information