Je testais un bloc de code pour un commentaire ici sur StackOverflow et j'ai rencontré une situation où la variable d'interface implicite l'a élevé. Ce que je ne peux pas voir, c'est ce qui le cause dans ce cas. J'ai une mini usine qui retourne une interface pour un objet nouvellement créé. Si j'appelle la méthode dans un bloc de procédure alors j'obtiens seulement un nombre de référence de 1. Si je l'appelle du bloc de programme principal alors j'obtiens un compte de référence de 2.Quand le compilateur Delphi crée-t-il une variable d'interface implicite?
J'ai testé ceci avec Delphi 10 Seattle. Y at-il une ressource qui contient les règles pour la création d'interface implicite et est le modèle où une interface est retournée par une usine pas un modèle fiable?
program TestRefCount;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
Vcl.Dialogs;
type
IMyInterface = interface(IInterface)
['{62EB2C46-9B8A-47CE-A881-DB96E6F6437D}']
procedure DoSomething;
function GetRefCount: Integer;
end;
TMyObject = class(TInterfacedObject, IMyInterface)
strict private
FMyValue: Integer;
public
procedure Init;
procedure DoSomething;
function GetRefCount: Integer;
end;
TMyFactory = class(TObject)
private
function CreateMyInt: IMyInterface;
end;
procedure TMyObject.DoSomething;
begin
MessageDlg(IntToStr(FMyValue), mtInformation, [mbok], 0);
end;
function TMyObject.GetRefCount: Integer;
begin
Result := FRefCount;
end;
procedure TMyObject.Init;
begin
FMyValue := 100;
end;
function TMyFactory.CreateMyInt: IMyInterface;
var
myObject: TMyObject;
begin
myObject := TMyObject.Create;
Assert(myObject.GetRefCount = 0);
myObject.Init;
Assert(myObject.GetRefCount = 0);
Result := myObject;
Assert(myObject.GetRefCount = 1);
Assert(Result.GetRefCount = 1);
end;
procedure WorkWithIntf;
var
myFactory: TMyFactory;
myInt: IMyInterface;
begin
myFactory := TMyFactory.Create;
try
myInt := myFactory.CreateMyInt;
Assert(myInt.GetRefCount = 1);
myInt.DoSomething;
Assert(myInt.GetRefCount = 1);
finally
myFactory.Free;
end;
end;
var
myFactory: TMyFactory;
myInt: IMyInterface;
begin
try
// This case doesn't have an implicit interface variable
WorkWithIntf;
// This case does have an implicit interface variable
myFactory := TMyFactory.Create;
try
myInt := myFactory.CreateMyInt;
Assert(myInt.GetRefCount = 1); // This fails because the refcount is 2
myInt.DoSomething;
Assert(myInt.GetRefCount = 1);
finally
myFactory.Free;
end;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Voici les premiers blocs où il n'y a pas de variable d'interface implict:
TestRefCount.dpr.67: myInt := myFactory.CreateMyInt;
005C6A5A 8D55F8 lea edx,[ebp-$08]
005C6A5D 8B45FC mov eax,[ebp-$04]
005C6A60 E83BFEFFFF call TMyFactory.CreateMyInt
TestRefCount.dpr.68: Assert(myInt.GetRefCount = 1);
005C6A65 8B45F8 mov eax,[ebp-$08]
Voici le deuxième bloc où l'on peut voir la variable d'interface implicite:
TestRefCount.dpr.86: myInt := myFactory.CreateMyInt;
005CF513 8D55EC lea edx,[ebp-$14]
005CF516 A19CB75D00 mov eax,[$005db79c]
005CF51B E88073FFFF call TMyFactory.CreateMyInt
005CF520 8B55EC mov edx,[ebp-$14]
005CF523 B8A0B75D00 mov eax,$005db7a0
005CF528 E8C7E3E3FF call @IntfCopy
TestRefCount.dpr.87: Assert(myInt.GetRefCount = 1); // This fails because the refcount is 2
005CF52D A1A0B75D00 mov eax,[$005db7a0]