According to the Delphi docs,我可以使用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.
答案 0 :(得分:14)
您的界面需要有一个GUID才能使as
运算符正常工作。在IMyInterface = interface
之后,在任何方法定义之前转到第一行,然后按 Ctrl + G 生成新的GUID。
接口的as
运算符需要GUID,因为它调用IUnknown.QueryInterface
,而这又需要GUID。如果在将INTERFACE转换为其他类型的INTERFACE时遇到此问题,那就没问题了。
您不应该首先将TInterfacedObject
强制转换为接口,因为这意味着您同时拥有对实现对象(TInterfacedObject
)的引用和对该接口的引用已实现的接口(IMyInterface
)。这是有问题的,因为你混合了两个生命周期管理概念:TObject
一直存在,直到它们调用.Free
为止;你有理由确定在你不知情的情况下没有在你的对象上调用.Free
。但接口是引用计数的:当您将接口分配给变量时,引用计数器会增加,当该实例超出范围(或分配其他内容)时,引用计数器会减少。当参考计数器命中ZERO时,对象将被丢弃(.Free
)!
这里有一些无辜的代码会快速陷入困境:
procedure DoSomething(If: IMyInterface);
begin
end;
procedure Test;
var O: TMyObjectImplementingTheInterface;
begin
O := TMyObjectImplementingTheInterface.Create;
DoSomething(O); // Works, becuase TMyObject[...] is implementing the given interface
O.Free; // Will likely AV because O has been disposed of when returning from `DoSomething`!
end;
修复非常简单:将O
的类型从TMyObject[...]
更改为IMyInterface
,如下所示:
procedure DoSomething(If: IMyInterface);
begin
end;
procedure Test;
var O: IMyInterface;
begin
O := TMyObjectImplementingTheInterface.Create;
DoSomething(O); // Works, becuase TMyObject[...] is implementing the given interface
end; // `O` gets freed here, no need to do it manually, because `O` runs out of scope, decreases the ref count and hits zero.
答案 1 :(得分:2)
如果要使用As或Supports运算符,则需要向接口添加Guid,例如:
type
IMyInterface = interface
['{00000115-0000-0000-C000-000000000049}']
procedure Foo;
end;
请参阅docwiki
答案 2 :(得分:0)
您可以自动将对象o定义为正确的类型。否则,您可以随时使用supports()
和/或致电QueryInterface
。
var
o: TMyInterfacedObject;
i: IMyInterface;
begin
try
o := TMyInterfacedObject.Create;
i := o;
except
on E:Exception do
Writeln(E.Classname, ': ', E.Message);
end;
end.