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