我希望引用计数应该在接口(interface)实现中的外部聚合对象上工作。 如果我可以引用另一个例子:Clarity in classes implementing multiple interfaces (alternative to delegation):
这是该行为的最小再现:
program SO16210993;
{$APPTYPE CONSOLE}
type
IFoo = interface
procedure Foo;
end;
TFooImpl = class(TInterfacedObject, IFoo)
procedure Foo;
end;
TContainer = class(TInterfacedObject, IFoo)
private
FFoo: IFoo;
public
constructor Create;
destructor Destroy; override;
property Foo: IFoo read FFoo implements IFoo;
end;
procedure TFooImpl.Foo;
begin
Writeln('TFooImpl.Foo called');
end;
constructor TContainer.Create;
begin
inherited;
FFoo := TFooImpl.Create;
end;
destructor TContainer.Destroy;
begin
Writeln('TContainer.Destroy called');//this line never runs
inherited;
end;
procedure Main;
var
Foo : IFoo;
begin
Foo := TContainer.Create;
Foo.Foo;
end;
begin
Main;
Readln;
end.
如果我不使用 implements
,而是在 TImplementor
类中实现接口(interface),那么析构函数就会运行。
最佳答案
这里发生的是,您调用TContainer.Create
并创建对象的实例。但随后您将该实例分配给接口(interface)引用,即全局变量 Foo。由于该变量的类型为 IFoo
,因此接口(interface)委托(delegate)意味着实现对象是 TFooImpl
的实例,而不是 TFooImpl 的实例TContainer
。
因此,没有任何东西会引用 TContainer
的实例,它的引用计数永远不会增加,因此它永远不会被销毁。
我认为没有一个非常简单的方法可以解决这个问题。您也许可以使用TAggreatedObject
,但它可能无法解决您的问题。它会迫使您将 TContainer.FFoo
声明为 TFooImpl
类型,我想您不想这样做。无论如何,这就是以这种方式重铸的样子:
program SO16210993_TAggregatedObject;
{$APPTYPE CONSOLE}
type
IFoo = interface
procedure Foo;
end;
TFooImpl = class(TAggregatedObject, IFoo)
procedure Foo;
end;
TContainer = class(TInterfacedObject, IFoo)
private
FFoo: TFooImpl;
function GetFoo: IFoo;
public
destructor Destroy; override;
property Foo: IFoo read GetFoo implements IFoo;
end;
procedure TFooImpl.Foo;
begin
Writeln('TFooImpl.Foo called');
end;
destructor TContainer.Destroy;
begin
Writeln('TContainer.Destroy called');//this line does run
FFoo.Free;
inherited;
end;
function TContainer.GetFoo: IFoo;
begin
if not Assigned(FFoo) then
FFoo := TFooImpl.Create(Self);
Result := FFoo;
end;
procedure Main;
var
Foo : IFoo;
begin
Foo := TContainer.Create;
Foo.Foo;
end;
begin
Main;
Readln;
end.
documentation确实谈到了这一点:
The class you use to implement the delegated interface should derive from TAggregationObject.
最初我找不到此 TAggregationObject
的任何文档。最后我意识到它实际上被命名为 TAggregatedObject
并且是 documented .
TAggregatedObject provides the functionality for an inner object of an aggregate by implementing the IInterface methods to delegate to the controlling IInterface.
An aggregated object is an object composed of several interfaced objects. Each object implements its own behavior and interfaces, but all the objects share the same reference count, which is that of the controller object. In the container pattern, the controller is the container object.
TAggregatedObject does not itself support any interfaces. However, as is typical of an aggregate, it does implement the methods of IInterface, which are used by the objects that descend from it. TAggregatedObject, therefore, serves as a base for classes that implement interfaces for creating objects that are part of an aggregate.
TAggregatedObject is used as a base for classes that create contained objects and connecting objects. Using TAggregatedObject ensures that calls to the IInterface methods delegate to the controlling IInterface of the aggregate.
The controlling IInterface is specified in the constructor for TAggregatedObject and is indicated by the Controller property.
此外,源代码注释中有这样的内容:
TAggregatedObject and TContainedObject are suitable base classes for interfaced objects intended to be aggregated or contained in an outer controlling object. When using the "implements" syntax on an interface property in an outer object class declaration, use these types to implement the inner object.
Interfaces implemented by aggregated objects on behalf of the controller should not be distinguishable from other interfaces provided by the controller. Aggregated objects must not maintain their own reference count - they must have the same lifetime as their controller. To achieve this, aggregated objects reflect the reference count methods to the controller.
TAggregatedObject simply reflects QueryInterface calls to its controller. From such an aggregated object, one can obtain any interface that the controller supports, and only interfaces that the controller supports. This is useful for implementing a controller class that uses one or more internal objects to implement the interfaces declared on the controller class. Aggregation promotes implementation sharing across the object hierarchy.
TAggregatedObject is what most aggregate objects should inherit from, especially when used in conjunction with the "implements" syntax.
关于Delphi接口(interface)实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16210993/