Delphi 7与Delphi XE及更高版本之间的接口行为不同

时间:2013-01-28 09:11:04

标签: delphi interface delphi-7 delphi-xe

我遇到了在不同版本的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.

2 个答案:

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

从界面请求实现对象是相当不寻常的。这样做表明您的设计存在问题。如果你真的需要这样做,有几个选择:

后一种选择适用于所有版本的Delphi,并且无需借助于伪装。