Delphi 中 Form 分发与其生命周期相关的接口对象的安全方法?
我有一个 Delphi 表单,它提供接口对象背后的功能,代码的其他部分也通过属于该表单的属性获取引用。我无法将接口功能委托给子对象,因为太多的功能是由表单上的控件/组件提供的。我无法使用 TAggregateObject 或 TContainedObject 链接传递给 Form 的接口对象的生命周期,因为 TForm 类不从 TinterfacedObject 继承,并且 Delphi 不支持多重继承,因此我无法将 TInterfacedObject 混合到继承链中。如果表单被销毁,而其他一些代码保存着由表单传递的接口引用之一,则这种情况可能会导致访问冲突。有人能想出一个好的解决方案来解决这个问题吗?
I have a Delphi Form that provides the functionality behind an interface object that other parts of the code get references too via a property belonging to the Form. I can't delegate the interface functionality to a child object because too much of that functionality is serviced by controls/components on the form. I can't use TAggregatedObject or TContainedObject to link the lifetime of the interfaced objects being passed around to the Form because the TForm class does not inherit from TinterfacedObject and Delphi does not support multiple inheritance so I can't mix in TInterfacedObject into the inheritance chain. This situation can lead to access violations if a Form gets destroyed while some other code holds one of the interface references passed out by the Form. Can anyone think of a good solution to this problem?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您可以将接口委托给子对象,只需让该对象包含指向表单的内部指针,以便它可以在需要时访问表单的控件,这与您现在已经做的没有什么不同。
您可以根据需要使用
TAggregateObject
或TContainedObject
。它们不需要从TInterfacedObject
派生 Form。它们所需要的只是一个IInterface
接口指针,而TComponent
派生自IInterface
(并覆盖_AddRef()
和_Release()
以禁用引用计数),因此您可以将表单本身(作为TComponent
后代)作为所需的IInterface
指针传递。这就剩下唯一的问题了——当活动接口引用被其他代码持有时,表单关闭。最简单的解决方案是 1) 重写该代码,以便在窗体关闭时不保留这些引用,或者 2) 在释放这些引用之前不允许窗体关闭。
You can delegate the interface to a child object, just have that object contain an internal pointer to the Form so it can access the Form's controls when needed, no different then you are already doing right now.
You can use
TAggregateObject
orTContainedObject
for your needs. They do not require the Form to derive fromTInterfacedObject
. All they do require is anIInterface
interface pointer, andTComponent
derives fromIInterface
(and overrides the_AddRef()
and_Release()
to disable reference counting), so you can pass the Form itself (being aTComponent
descendant) as the requiredIInterface
pointer.That leaves the only issue remaining - the Form closing while active interface references are being held by other code. The simpliest solution is to either 1) rewrite that code to not hold on to those references while the Form is closing, or 2) don't allow the Form to close until those references have been released.
注意:只有当您的使用者也是从 TComponent 派生时,这才有效。
为了避免死引用,您可以从表单查询
IInterfaceComponentReference
(每个 TComponent 都可用),在该接口上调用GetComponent
并将自己附加到FreeNotification
返回的组件/表单的代码>。现在发生的情况是:当表单被销毁时,它将通过调用消费者上的
Notification
方法(将其自身(表单)作为AComponent
AComponent)来通知所有“监听者”它将销毁自己。 code> 和opRemove
作为操作。从而允许您将接口引用归零。但要注意对象引用和接口引用不能相等。
另外,请确保在不再需要通知时调用
RemoveFreeNotification
以避免不必要的调用。Note: This will only work, if your consumer is also derived from TComponent.
To avoid the dead references you can query the
IInterfaceComponentReference
(available on every TComponent) from your form, callGetComponent
on that interface and attach yourself to theFreeNotification
of the returned Component/Form.What happens now is: When the Form gets destroyed it will notify all "listners" that its going to destroy itself by calling the
Notification
method on the consumer with itself (form) asAComponent
andopRemove
as operation. Thus allowing you to nil your interface reference.But be aware that the object references and interface references must not be equal.
Also make sure to call
RemoveFreeNotification
when you don't need the Notification any more to avoid unnecessary calls.