【问题标题】:Acessing several units implementing a Interface with equal names访问几个实现同名接口的单元
【发布时间】:2016-08-24 23:01:15
【问题描述】:

当您的版本发生更改时,我需要从第三方下载两个或更多单元。

我使用 xml 数据绑定来生成单位。它们是:

unit tissV01;

interface

uses .....;

type
  IXMLMensagemTISS = interface(IXMLNode)
    ['{11773827-F0A1-42E0-99E1-E221DFAF8542}']
    { Property Accessors }
  end;


function GetmensagemTISS(Doc: IXMLDocument): IXMLMensagemTISS;

implementation

function GetmensagemTISS(Doc: IXMLDocument): IXMLMensagemTISS;
begin
  Result := XXXX as IXMLMensagemTISS;
end;

end.

单位tissV02

unit tissV02;

interface

uses .....;

type
  { IXMLMensagemTISS }
  IXMLMensagemTISS = interface(IXMLNode)
    ['{11773827-F0A1-42E0-99E1-E221DFAF8542}']
    { Property Accessors }
    property Cabecalho: string read Get_Cabecalho;
  end;

function GetmensagemTISS(Doc: IXMLDocument): IXMLMensagemTISS;

implementation

function GetmensagemTISS(Doc: IXMLDocument): IXMLMensagemTISS;
begin
  Result := XXXX as IXMLMensagemTISS;
end;

end.

在我的应用中,我需要选择我必须使用的单位:

unit test;

interface

uses tissV01,tissV02, .......;

type 
  TMyform = class(TForm)
  public
    msg3:IXMLMensagemTISS;   
  end;

implementation

procedure TMyform.ExecuteMessage:
var 
  xmlTISS : TXmlDocument;
begin
  xmlTISS := TXmlDocument.Create(nil); 
  if condition  then
    msg3 := tissV01.GetmensagemTISS(xmlTISS)
  else msg3 := tissV02.GetmensagemTISS(xmlTISS);
  with msg3.Cabecalho do  something;
end; 

end.

从逻辑上讲,它不起作用,因为 IXMLMensagemTISS 对两个单元都是通用的。

是否有一些解决方法可以在我不必更改接口名称 (IXMLMensagemTISS) 的情况下执行此操作?

我想简化我的代码,并且我需要在未来维护许多这种类型的单元。问题是所有都实现了 IXMLMensagemTISS,我无能为力。

我不想创建很多 msg 变量,例如 msgV01:=tissv01.GetmensagemTISS、msgV01:=tissv02.GetmensagemTISS 等等

【问题讨论】:

  • 我不明白您为什么要在多个单元中声明相同的接口。在一个通用单元中声明一次,然后在整个程序中使用该单元。
  • 因为,它不是我的。它来自其他开发人员。他在每个新版本中更改版本号,以及其他一些小事情。但是,除了版本号和一些函数结果值之外,我需要从该单元中使用的内容仍然相同。但我总是需要决定在运行时使用什么版本。

标签: delphi delphi-units


【解决方案1】:

如果您在不同的单位中有两个相同的标识符,您可以在单位名称前加上前缀以区分它们。

var
  a: tissV01.IXMLMensagemTISS;
  b: tissV02.IXMLMensagemTISS;

但是,在您的示例代码中,您需要明确选择要使用的接口。

uses
  tissV01, tissV02;  //last unit in uses clause gets priority.

type 
  TMyform = class(TForm)
  public
    msg3: tissV01.IXMLMensagemTISS;   //allowed
    msg2: tissV02.IXMLMensagemTISS;   //allowed
    msgx: IXMLMensagemTISS; //ambigous, will evaluate to tissV02.IXMLMensagemTISS;
  end;

uses 子句中的最后一个单元获得优先级。
这个事实经常被滥用来用自定义的类和接口覆盖内置的类和接口。

如果您希望根据某些条件延迟选择,可以使用条件编译。
无论是在uses子句中(利用uses子句顺序的优先效果),

unit DoWork;

interface

uses
 {$ifdef V01HasPriority}
 tissV02, tissV01;
 {$else}
 tissV01, tissV02;
 {$endif}

或在声明中明确

var
  a: {$ifdef useV01} tissV01.IInt {$else} tissV02.IInt {$endif}

然后,您使用在 {$ifdef ...} 之前编译的 {$define V01HasPriority} 在其他地方进行选择。
您还可以在 IDE 中声明 {$define ...}

Project > Options > Delphi Compiler > Conditional defines

只有在接口兼容的情况下,才能在运行时选择接口。
这意味着接口继承自一个共同的祖先。
每个接口在IInterface 中都有一个共同的祖先,但是最好选择一个尽可能接近两者的接口。

然后你声明一个变量作为那个共同的祖先:

var
  a: ICommonInterface;
begin
  if x=1 then a:= tissV01.NewXMLInterface
  else a:= tissV02.NewXMLInterface;
  if Supports(a, tissV01.IXMLInt) then tissV01.IXMLInt(a).DoV01Things
  else tissV02.IXMLInt(a).DoV02Things;  

如果两个接口具有相同的签名,那么事情就容易多了(也更理智了)。

var
  a: IXMLCommon;
begin
  if x=1 then a:= tissV01.NewXMLInterface
  else a:= tissV02.NewXMLInterface;
  a.DoCommonThings(param1, param2);

集中决策
当然,如果您有很多决定(有时)最好将它们集中起来,然后将它们分散到您的程序中。

那么为什么不创建一个可以完成所有决策的单元,就像这样:

unit IvoryTower;

interface

function InterfaceXorY(const person: TPerson): ICommonIntf;

implementation

function InterfaceXorY(const person: TPerson): ICommonIntf;
var
  WhatToDo: TSomething;
begin
  WhatToDo:= DatabaseY.TableX.GetData(Person);
  case WhatToDo of
    XYZolog: Result:= Unit1.I1;
    Galaga: Result:= Unit2.I2;
    Twinbee: Result:= Unit3.I4;
    else Assert(false, 'what to do outside of valid range');
  end; {case}
end;

【讨论】:

  • 是的,我知道。这就是我现在正在做的事情。但是我有许多使用“a”变量的程序和函数。我必须复制多行代码才能从“a”变量更改为“b”变量。我需要根据条件加入这两个单位。我希望只有一个变量来访问接口,因为它们是相似的,只是改变你的版本和其他不重要的事情。
  • 好的,但是我需要在运行时选择单位,编译时不需要
  • 噗噗,现在我已经涵盖了所有内容。我已经厌倦了输入接口和方法名称,所以最后我有点创意。
  • 谢谢约翰先生,但我需要在运行时选择单位。
  • 这是不可能的,只有使用 dll 才能做到这一点。单位没有动态加载。
猜你喜欢
  • 2016-06-28
  • 2011-01-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-18
  • 2023-03-04
  • 2017-12-19
  • 2015-11-21
相关资源
最近更新 更多