我遇到了在不同版本的Delphi中使用界面的奇怪问题。以下最小化代码在Delphi XE及更高版本中编译和运行,但在Delphi 7中没有。具体来说,在Delphi 7中编译时,function TForm1.Load: IMoleculeSubject;
似乎没有返回正确的结果,即正确引用新创建的实例。你能帮忙评论一下原因和可能的解决方法吗?非常感谢!
unit uInterface;
interface
type
IMoleculeSubject = interface
['{BEB4425A-186C-45DF-9DCE-C7175DB0CA90}']
end;
TMoleculeSubject = class(TInterfacedObject, IMoleculeSubject)
end;
implementation
end.
unit uBusiness;
interface
uses
uInterface;
type
TMoleculeDecorator = class(TMoleculeSubject)
private
FID: Integer;
public
property ID: Integer read FID;
constructor Create;
end;
implementation
{ TMoleculeDecorator }
constructor TMoleculeDecorator.Create;
begin
inherited Create;
FID := Random(100);
end;
end.
unit Unit1;
interface
uses
uInterface, uBusiness,
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls,
Forms, Dialogs;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
function Load: IMoleculeSubject;
public
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
var
MolSubject: IMoleculeSubject;
begin
MolSubject := Load;
// The down-cast is to show the returned result is wrong in Delphi 7!
Caption := IntToStr(TMoleculeDecorator(MolSubject).ID);
end;
function TForm1.Load: IMoleculeSubject;
var
MolSubject: IMoleculeSubject;
begin
MolSubject := TMoleculeDecorator.Create;
Result := MolSubject;
end;
end.
答案 0 :(得分:5)
自Delphi 2010以来,可以使用对象的接口转换。旧版Delphi版本的解决方法在哪里,例如参见How to cast a Interface to a Object in Delphi
答案 1 :(得分:5)
Load
函数在所有版本的Delphi中都能很好地工作。问题是你的演员,这就是所谓的 unsafe typecast 。来自对象的接口引用的不安全类型转换在旧版本的Delphi中具有不明确的行为。但是,这种行为在现代Delphi中得到了很好的定义。 documentation说的更多。
因此,基本问题是您对该行为的期望与该语言的Delphi 7版本不兼容。
如果您获得了返回ID的界面,您会发现您正在创建的界面符合预期。
program InterfaceDemo;
{$APPTYPE CONSOLE}
uses
Classes;
type
IMyIntf = interface
function GetID: Integer;
end;
TImplementingObject = class(TInterfacedObject, IMyIntf)
private
FID: Integer;
function GetID: Integer;
public
constructor Create;
end;
{ TImplementingObject }
constructor TImplementingObject.Create;
begin
FID := Random(100);
Writeln(FID);
end;
function TImplementingObject.GetID: Integer;
begin
Result := FID;
end;
var
MyIntf: IMyIntf;
begin
Randomize;
MyIntf := TImplementingObject.Create;
Writeln(MyIntf.GetID);
Readln;
end.
从界面请求实现对象是相当不寻常的。这样做表明您的设计存在问题。如果你真的需要这样做,有几个选择:
as
运算符的类型安全案例。后一种选择适用于所有版本的Delphi,并且无需借助于伪装。