将TInterfacedObject转换为接口

时间:2011-03-27 08:18:59

标签: delphi interface delphi-2007

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.

3 个答案:

答案 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.