将 TInterfacedObject 转换为接口
根据Delphi文档,我可以转换TInterfacedObject
使用 as
运算符连接到接口。
但这对我不起作用。强制转换会产生编译错误:“运算符不适用于此操作数类型”。
我正在使用 Delphi 2007。
这是一些代码(控制台应用程序)。包含错误的行已被标记。
program Project6;
{$APPTYPE CONSOLE}
uses
SysUtils;
type
IMyInterface = interface
procedure Foo;
end;
TMyInterfacedObject = class(TInterfacedObject, IMyInterface)
public
procedure Foo;
end;
procedure TMyInterfacedObject.Foo;
begin
;
end;
var
o: TInterfacedObject;
i: IMyInterface;
begin
try
o := TMyInterfacedObject.Create;
i := o as IMyInterface; // <--- [DCC Error] Project6.dpr(30): E2015 Operator not applicable to this operand type
except
on E:Exception do
Writeln(E.Classname, ': ', E.Message);
end;
end.
According to the Delphi docs, I can cast a TInterfacedObject
to an interface using the as
operator.
But it doesn't work for me. The cast gives a compile error: "Operator not applicable to this operand type".
I'm using Delphi 2007.
Here is some code (a console app). The line that contains the error is marked.
program Project6;
{$APPTYPE CONSOLE}
uses
SysUtils;
type
IMyInterface = interface
procedure Foo;
end;
TMyInterfacedObject = class(TInterfacedObject, IMyInterface)
public
procedure Foo;
end;
procedure TMyInterfacedObject.Foo;
begin
;
end;
var
o: TInterfacedObject;
i: IMyInterface;
begin
try
o := TMyInterfacedObject.Create;
i := o as IMyInterface; // <--- [DCC Error] Project6.dpr(30): E2015 Operator not applicable to this operand type
except
on E:Exception do
Writeln(E.Classname, ': ', E.Message);
end;
end.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
快速回答
您的界面需要有一个 GUID,
as
运算符才能工作。转到IMyInterface = interface
之后、任何方法定义之前的第一行,然后按 Ctrl+G 生成新的 GUID。更长的注释
接口的
as
运算符需要 GUID,因为它调用IUnknown.QueryInterface
,而后者又需要 GUID。如果您在将 INTERFACE 转换为其他类型的 INTERFACE 时遇到此问题,那也没关系。首先,您不应该将
TInterfacedObject
转换为接口,因为这意味着您同时持有对实现对象 (TInterfacedObject
) 的引用和对已实现接口 (IMyInterface
) 的引用。这是有问题的,因为您混合了两个生命周期管理概念:TObject
一直存在,直到有东西调用.Free
为止;您有理由确信没有任何东西会在您不知情的情况下调用您的对象上的.Free
。但是接口是引用计数的:当您将接口分配给变量时,引用计数器会增加,当该实例超出范围(或分配了其他内容)时,引用计数器会减少。当引用计数器为零时,该对象将被释放(.Free
)!下面是一些看似无辜的代码,但很快就会遇到很多麻烦:
修复方法非常简单:将
O
的类型从TMyObject[...]
O 的类型> 到IMyInterface
,如下所示:Quick answer
Your interface needs to have a GUID for the
as
operator to work. Go to the first line afterIMyInterface = interface
, before any method definitions and hit Ctrl+G to generate a new GUID.Longer comment
The
as
operator for interfaces requires a GUID because it callsIUnknown.QueryInterface
, and that in turn requires a GUID. That's all right if you run into this problem when casting an INTERFACE to an other kind of INTERFACE.You're not supposed to cast an
TInterfacedObject
to an interface in the first place, because that means you're holding both a reference to the implementing object (TInterfacedObject
) and a reference to the implemented interface (IMyInterface
). That's problematic because you're mixing two lifecycle management concepts:TObject
live until something calls.Free
on them; You're reasonably sure nothing calls.Free
on your objects without your knowledge. But interfaces are reference-counted: when you assign your interface to a variable the reference counter increases, when that instance runs out of scope (or is assigned something else) the reference counter is decreases. When the reference counter hits ZERO the object is disposed of (.Free
)!Here's some innocent-looking code that's going to get into a real lot of trouble fast:
The fix is very simple: Change the
O
's type fromTMyObject[...]
toIMyInterface
, like this:如果要使用 As 或 Supports 运算符,则需要向接口添加 Guid,例如:
请参阅 docwiki
If you want to use the As or Supports operator you need to add a Guid to the Interface, example:
See the docwiki
如果您将对象 o 定义为正确的类型,则强制转换将自动进行。否则,您始终可以自己使用
supports()
和/或调用QueryInterface
。The cast will be automatic of you define the object o as the correct type. Otherwise, you can always use
supports()
and/or callQueryInterface
yourself.