如何解决界面乱七八糟的问题
我一直认为接口是一种为不同的不相关类提供通用功能的方法。但是接口的属性 - “当 RefCOunt 降至零时释放对象”不允许我按照我想要的方式工作。
例如:假设我有两个不同的类:TMyObject 和 TMyDifferentObject。它们都支持这个接口:
const
IID_MyInterface: TGUID = '{4D91C27F-510D-4673-8773-5D0569DFD168}';
type
IMyInterface = Interface(IInterface)
['{4D91C27F-510D-4673-8773-5D0569DFD168}']
function GetID : Integer;
end;
type
TMyObject = class(TInterfacedObject, IMyInterface)
function GetID: Integer;
end;
function TMyObject.GetID: Integer;
begin
Result := 1;
end;
type
TMyDifferentObject = class(TInterfacedObject, IMyInterface)
function GetID: Integer;
end;
function TMyDifferentObject.GetID: Integer;
begin
Result := 2;
end;
现在,我想在我的程序中创建此类的实例,然后将这些实例传递给这个方法:
procedure ShowObjectID(AObject: TObject);
var
MyInterface: IMyInterface;
begin
if Supports(AObject, IID_MyInterface, MyInterface) then
begin
ShowMessage(IntToStr(MyInterface.GetID));
end;
end; //Interface goes out of scope and AObject is freed but I still want to work with that object!
这是一个示例。一般来说,我想将对象的实例传递给某个过程并检查该对象是否支持接口,如果是,我想执行该接口的方法。但当接口超出范围时,我不想完成该对象的工作。如何做到这一点?
问候。
I was always thinking about interfaces as a way to give different unrelated classes a common functionality. But the property of interface - "free an object when RefCOunt drops to zero" does not allow me to work as I want to.
For example: lets assume that I have two different classes: TMyObject and TMyDifferentObject. They both support this interface:
const
IID_MyInterface: TGUID = '{4D91C27F-510D-4673-8773-5D0569DFD168}';
type
IMyInterface = Interface(IInterface)
['{4D91C27F-510D-4673-8773-5D0569DFD168}']
function GetID : Integer;
end;
type
TMyObject = class(TInterfacedObject, IMyInterface)
function GetID: Integer;
end;
function TMyObject.GetID: Integer;
begin
Result := 1;
end;
type
TMyDifferentObject = class(TInterfacedObject, IMyInterface)
function GetID: Integer;
end;
function TMyDifferentObject.GetID: Integer;
begin
Result := 2;
end;
Now, I would like to create instances of this classes in my program, and then pass those instances to this method:
procedure ShowObjectID(AObject: TObject);
var
MyInterface: IMyInterface;
begin
if Supports(AObject, IID_MyInterface, MyInterface) then
begin
ShowMessage(IntToStr(MyInterface.GetID));
end;
end; //Interface goes out of scope and AObject is freed but I still want to work with that object!
This is an example. In general I want to pass instance of object to some procedure and check if this object supports an interface, if yes I want to execute method of this interface. But I don't want to finish work with that object when interface goes out of scope. How to do this?
Regards.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您的问题可能源于您使用对象引用创建对象的事实:
这样做意味着创建后的 RefCount 为零。只要您需要,就可以将您的对象分配给接口引用,
或者按照 David 在评论中建议的那样禁用引用计数。这本质上意味着声明您自己的“TInterfacedObject”并实现三个 IInterface 方法:
本质是为 _AddRef 和 _Release 返回
-1
。正如 David 所说:看看 TComponent 是如何做到的。当 FVCLComObject 为零时,就看它正在做什么。Your problem probably stems from the fact that you create your objects using an object reference:
Doing it like this means the RefCount after creation is zero. Either assign your object to an interface reference as well for as long as you need it,
or disable refcounting as David suggested in the comments. Which essentially means declaring your own "TInterfacedObject" and implementing the three IInterface methods:
The essence is to return
-1
for both _AddRef and _Release. As David said: have a look at how TComponent does it. And just take what it is doing when FVCLComObject is nil.解决问题的一种方法是更改代码,以便仅通过接口引用来引用对象。换句话说,代替
你写
这可能会很不方便,所以相反,禁用自动生命周期管理会更方便。您需要为您的实现对象执行此操作:
然后您可以从此类派生您的类。
这种方法有一个非常重要的警告。假设您在变量(本地、全局、类成员)中保存由派生自
TInterfacedObjectWithoutLifetimeManagement
的类实现的任何接口。所有此类接口变量都必须在在对实现对象调用Free
之前完成。如果你不遵循这个规则,你会发现当这些接口变量超出范围时,编译器仍然会发出代码来调用
_Release
,并且在对象被释放后调用该对象的方法是错误的。被毁了。这是一种特别令人讨厌的错误类型,因为在您的代码在最重要的客户端计算机上运行之前,它通常不会表现为运行时故障!换句话说,此类错误可能是间歇性的。One approach to solve your problem is to change your code so that you only ever refer to the object through an interface reference. In other words instead of
you write
This can be inconvenient, so instead it can be more convenient to disable automatic lifetime management. You need to do this for your implementing object:
You can then derive your classes from this class.
There is one very major caveat with this approach. Suppose that you hold in variables (local, global, class member) any interfaces that are implemented by a class derived from
TInterfacedObjectWithoutLifetimeManagement
. All such interface variables must be finalised before you callFree
on the implementing object.If you do not follow this rule you will find that when those interface variables go out of scope, the compiler still emits code to call
_Release
and it's an error to call a method on an object after it has been destroyed. This is a particularly nasty type of error because it commonly will not manifest itself with a runtime failure until your code runs on your most important client's machine! In other words such errors can be of intermittent nature.到目前为止没有人提到的另一个选项是在对象实例上显式调用
_AddRef
以使其在需要时保持活动状态,然后调用_Release
。Another option nobody mentioned so far is to explicitly call
_AddRef
on the object instance to keep it alive as long as you need it, then call_Release
.