2

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

单元1.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.
    
    
4

2 回答 2

5

自 Delphi 2010 起就可以将接口转换为对象。旧版本的 Delphi 的解决方法在哪里,请参见示例How to cast a Interface to a Object in Delphi

于 2013-01-28T09:19:46.777 回答
5

Load功能在所有版本的 Delphi 中都运行良好。问题在于您的演员表,这就是所谓的不安全类型转换。从接口引用到对象的不安全类型转换在旧版本的 Delphi 中具有不明确的行为。然而,这种行为在现代 Delphi 中是明确定义的。文档说得更多。

因此,基本问题是您对行为的期望与该语言的 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 中都有效,并且无需使用诡计。

于 2013-01-28T09:20:55.903 回答