我在不同版本的 Delphi 中使用界面时遇到一个奇怪的问题。以下最小化代码在 Delphi XE 和更高版本中按预期编译和运行,但在 Delphi 7 中没有。具体来说,在 Delphi 7 中编译时,function TForm1.Load: IMoleculeSubject;
似乎没有返回正确的结果,即对新创建实例的正确引用。你能帮忙评论一下原因和可能的解决方法吗?非常感谢!
uInterface.pas
unit uInterface;
interface
type
IMoleculeSubject = interface
['{BEB4425A-186C-45DF-9DCE-C7175DB0CA90}']
end;
TMoleculeSubject = class(TInterfacedObject, IMoleculeSubject)
end;
implementation
end.
uBusiness.pas
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.
Unit1.pas
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.
最佳答案
Load
函数在所有版本的 Delphi 中都运行良好。问题在于您的转换,即所谓的不安全类型转换。从接口(interface)引用到对象的不安全类型转换在旧版本的 Delphi 中具有错误定义的行为。然而,行为在现代 Delphi 中是明确定义的。 documentation说得更多。
因此,基本问题是您对该行为的期望与该语言的 Delphi 7 版本不兼容。
如果你得到返回ID的接口(interface)你会发现你创建的接口(interface)是符合预期的。
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.
从接口(interface)请求实现对象是相当不寻常的。这样做表明您的设计存在问题。如果您确实需要这样做,有以下几种选择:
- 在现代 Delphi 中,您可以将类型安全的大小写与
as
运算符结合使用。 - 在旧的 Delphi 版本中,有一些 hack 可以检索实现对象:Casting a delphi interface to its implementation class without modifying the interface
- 您可以向返回实现对象的接口(interface)添加一个函数。
后一种选择适用于所有版本的 Delphi,并且无需诉诸诡计。
关于delphi - Delphi 7 和 Delphi XE 及更高版本之间接口(interface)的不同行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14558704/