7

我有一个 Delphi 表单,它提供接口对象背后的功能,代码的其他部分也通过属于表单的属性获取引用。我不能将接口功能委托给子对象,因为表单上的控件/组件提供了太多的功能。我不能使用 TAggregatedObject 或 TContainedObject 将被传递的接口对象的生命周期链接到 Form,因为 TForm 类不继承自 TinterfacedObject 并且 Delphi 不支持多重继承,所以我不能将 TInterfacedObject 混合到继承链中. 如果表单被破坏,而其他一些代码持有表单传递的接口引用之一,这种情况可能会导致访问冲突。谁能想到一个很好的解决这个问题的方法?

4

2 回答 2

9

您可以将接口委托给子对象,只需让该对象包含指向表单的内部指针,以便它可以在需要时访问表单的控件,与您现在已经在做的没有什么不同。

您可以使用TAggregateObjectTContainedObject满足您的需要。它们不需要从TInterfacedObject. 他们只需要一个IInterface接口指针,并且TComponent派生自IInterface(并覆盖_AddRef()and_Release()以禁用引用计数),因此您可以将 Form 本身(作为TComponent后代)作为所需的IInterface指针传递。

这留下了唯一的问题 - 当其他代码持有活动接口引用时表单关闭。最简单的解决方案是 1) 重写该代码以在 Form 关闭时不保留这些引用,或者 2) 在释放这些引用之前不允许 Form 关闭。

于 2011-10-10T23:57:01.590 回答
2

注意:这只有在你的消费者也是从 TComponent 派生的情况下才有效。

为了避免死引用,您可以IInterfaceComponentReference从表单中查询(在每个 TComponent 上可用),调用GetComponent该接口并将自己附加到FreeNotification返回的组件/表单的。

现在发生的事情是:当表单被销毁时,它会通知所有“侦听器”它会通过调用消费者上的方法来销毁自己(Notification表单)作为操作。从而允许您将您的接口引用归零。但请注意,对象引用和接口引用不能相等。另外,请确保在您不再需要通知时拨打电话,以避免不必要的电话。AComponentopRemoveRemoveFreeNotification

TSomeConsumer = class(TComponent)
private
  FInterfaceToAService: ISomeInterface;        
protected
  procedure Notification(AComponent: TComponent; Operation: TOperation); override;
public
  procedure SetService(const Value: ISomeInterface); 
end;

procedure TSomeConsumer.Notification(AComponent: TComponent; Operation: TOperation);
begin
  inherited;
  if (Operation = opRemove) and (AComponent = TObject(FInterfaceToAService)) then
    SetService(nil); // Takes care of niling the interface as well.
end;

procedure TSomeConsumer.SetService(const Value: ISomeInterface);
var
  comRef: IInterfaceComponentReference;
begin
  if Supports(FInterfaceToAService, IInterfaceComponentReference, comRef) then
    comRef.GetComponent.RemoveFreeNotification(self);

  FInterfaceToAService := Value;

  if Supports(FInterfaceToAService, IInterfaceComponentReference, comRef) then
    comRef.GetComponent.FreeNotification(self);
end;
于 2011-10-11T09:48:27.737 回答