当我使用Delphi Berlin 10.1 [弱](和[unsafe])引用时,"支持"功能和" QueryInterface"当给定一个标有"弱"的接口变量时,两者都递增引用计数。属性(与"不安全"属性相同的行为)。
program WeakReferences;
{$APPTYPE CONSOLE}
{$R *.res}
uses System.SysUtils;
type
IAnInterfacedObject = interface
['{351DFDA3-42CA-4A1D-8488-494CA454FD9C}']
end;
TAnInterfacedObject = class(TInterfacedObject, IAnInterfacedObject)
protected
function GetTheReferenceCount : integer;
public
constructor Create;
destructor Destroy; override;
property TheReferenceCount : integer read GetTheReferenceCount;
end;
constructor TAnInterfacedObject.Create;
begin
inherited Create;
writeln('(create AIO instance)');
end;
destructor TAnInterfacedObject.Destroy;
begin
writeln('(destroy AIO instance)');
inherited Destroy;
end;
function TAnInterfacedObject.GetTheReferenceCount : integer;
begin
Result := FRefCount;
end;
procedure WithoutSupports;
var
AIOinstance : TAnInterfacedObject;
AIOinterfaced : IAnInterfacedObject;
[Weak]
WeakAIOinterfaced : IAnInterfacedObject;
begin
AIOinstance := TAnInterfacedObject.Create;
writeln('created AIO instance; refcount: '+AIOinstance.TheReferenceCount.ToString);
AIOinterfaced := AIOinstance;
writeln('create AIO interfaced; refcount: '+AIOinstance.TheReferenceCount.ToString);
WeakAIOinterfaced := AIOinstance;
writeln('create WEAK AIO interfaced; refcount: '+AIOinstance.TheReferenceCount.ToString);
end;
procedure WithSupports_Weak;
var
AIOinstance : TAnInterfacedObject;
AIOinterfaced : IAnInterfacedObject;
[Weak]
WeakAIOinterfaced : IAnInterfacedObject;
begin
AIOinstance := TAnInterfacedObject.Create;
writeln('created AIO instance; refcount: '+AIOinstance.TheReferenceCount.ToString);
AIOinterfaced := AIOinstance;
writeln('create AIO interfaced; refcount: '+AIOinstance.TheReferenceCount.ToString);
Supports(AIOinstance, IAnInterfacedObject, WeakAIOinterfaced);
writeln('create WEAK AIO interfaced with SUPPORTS; refcount: '+AIOinstance.TheReferenceCount.ToString);
end;
procedure WithSupports_Unsafe;
var
AIOinstance : TAnInterfacedObject;
AIOinterfaced : IAnInterfacedObject;
[Unsafe]
UnsafeAIOinterfaced : IAnInterfacedObject;
begin
AIOinstance := TAnInterfacedObject.Create;
writeln('created AIO instance; refcount: '+AIOinstance.TheReferenceCount.ToString);
AIOinterfaced := AIOinstance;
writeln('create AIO interfaced; refcount: '+AIOinstance.TheReferenceCount.ToString);
Supports(AIOinstance, IAnInterfacedObject, UnsafeAIOinterfaced);
writeln('create UNSAFE AIO interfaced with SUPPORTS; refcount: '+AIOinstance.TheReferenceCount.ToString);
end;
procedure WithQueryInterface_Weak;
var
AIOinstance : TAnInterfacedObject;
AIOinterfaced : IAnInterfacedObject;
[Weak]
WeakAIOinterfaced : IAnInterfacedObject;
begin
AIOinstance := TAnInterfacedObject.Create;
writeln('created AIO instance; refcount: '+AIOinstance.TheReferenceCount.ToString);
AIOinterfaced := AIOinstance;
writeln('create AIO interfaced; refcount: '+AIOinstance.TheReferenceCount.ToString);
AIOinterfaced.QueryInterface(IAnInterfacedObject, WeakAIOinterfaced);
writeln('create WEAK AIO interfaced with QUERYINTERFACE; refcount: '+AIOinstance.TheReferenceCount.ToString);
end;
begin
try
writeln('--Without "Supports"-------------------');
WithoutSupports;
writeln;
writeln('--With "Supports" - weak-------------------');
WithSupports_Weak;
writeln;
writeln('--With "Supports" - unsafe-------------------');
WithSupports_Unsafe;
writeln;
writeln('--With "QueryInterface" - weak-------------------');
WithQueryInterface_Weak;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
readln;
end.
我错过了什么?有没有" WeakSupports"功能?这是一个错误还是新的"弱"的缺点?接口功能?
答案 0 :(得分:8)
Delphi Supports
(重载之一 - 但所有其他都是相同的,考虑out
参数)函数被声明为
function Supports(const Instance: IInterface; const IID: TGUID; out Intf): Boolean;
和QueryInterface
为
function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
out
个参数均未标记为[weak]
。这意味着您无法将[weak]
或[unsafe]
接口引用传递给它们。您只能传递对此类参数的强引用,以便按顺序保持引用计数。
来自文档Weak References:
注意:您只能将[Weak]变量传递给var或out参数 也被标记为[弱]。你不能通过常规强者 参考[弱] var或out参数。
注意:您只能将[Unsafe]变量传递给var或out参数 也被标记为[不安全]。你不能通过常规强者 引用[Unsafe] var或out参数。
此外,您的测试用例还有另一个问题。除非你使用完整的ARC Delphi编译器(目前是Android和iOS),否则你不能存储引用计数对象到对象引用,否则你将搞乱引用计数。更准确地说,非ARC编译器下的对象引用不会引用引用计数,您只能将它们用作临时访问点,以对无法通过声明的接口访问的对象执行某些操作。您应该始终至少有一个对该对象实例的接口引用,以便按顺序保持引用计数,并防止过早的对象破坏或内存泄漏。
而不是
var
AIOinstance : TAnInterfacedObject;
...
AIOinstance := TAnInterfacedObject.Create;
你应该总是使用
var
AIOinstance : IAnInterfacedObject;
...
AIOinstance := TAnInterfacedObject.Create;