【问题标题】:Delphi XE2 generics in TRemotable classesTRemotable 类中的 Delphi XE2 泛型
【发布时间】:2012-10-22 07:43:22
【问题描述】:

由于与我想在我的 TRemotable 类中使用泛型的问题无关的原因。我发现 Soap.OPToSOAPDomConv.pas 有一些问题。它使用的是旧的 RTTI,我猜它无法处理泛型,因此类不会序列化为 xml。

我已设法更改 Soap.OPToSOAPDomConv.pas 以便它与泛型一起使用。我的主要问题是是否可以对 Delphi 源文件进行更改? 如果不是,有没有更好的方法来做到这一点?只要是我自己用的,我想应该没有什么大问题,但是很难把源码分发给别人,然后还有Delphi未来的变化需要考虑。 这篇冗长的帖子的其余部分只是关于我实际在做什么的细节:-)

我已在 Soap.OPToSOAPDomConv.pas(第 3759 行)中对此进行了更改

if SerializeProps then
begin
  { Serialized published properties }
  Count := GetTypeData(Instance.ClassInfo)^.PropCount;
  if Count > 0 then
  begin
    CheckedElemURI := False;
    GetMem(PropList, Count * SizeOf(Pointer));
    try
      GetPropInfos(Instance.ClassInfo, PropList);

致:(我猜这不是最漂亮的实现)

过程中的新变量:

Context: TRttiContext;       
RttiProperty:  TRttiProperty;

第 3759 行:

if SerializeProps then
begin
  { Serialized published properties }
  Count := 0;
  for RttiProperty in Context.GetType(Instance.ClassInfo).GetProperties do
  begin
    if RttiProperty.Visibility = mvPublished then //The old method only read published
      Count := Count + 1;                         //RTTI scoping [mvPublished] requires changes to
  end;                                            //soap.InvRegistry
  begin
    CheckedElemURI := False;
    GetMem(PropList, Count * SizeOf(Pointer));
    try
      I := 0;
      for RttiProperty in Context.GetType(Instance.ClassInfo).GetProperties do
        if RttiProperty.Visibility = mvPublished then
        begin
          PropList[I] := TRttiInstanceProperty(RttiProperty).PropInfo;
          I := I + 1;
        end;

关于我在做什么的一些细节可能会有所帮助。背景是从 SOAP Web 服务导入的 wsdl 生成了一个巨大的单元,它由大约 2000 个类和 300k 行代码组成。 Web 服务设计是我无法控制的。 WSDL 导入器使所有这些类在 RTTI 中可见,这会占用 RTTI 空间并且单元不会编译。

我在这里和那里重构了代码,现在有了一个有效的实现。在重构时,我发现我可以通过使用泛型删除大约 50000 行冗余代码。由于 Delphi 不会“按原样”编译导入的 wsdl,因此每当 Web 服务中出现新方法时,我都必须手动维护该单元,所以我想让它尽可能可读。

基本上我是根据下面的变化。该示例具有非常简化的类,并且该示例实际上在重构代码中具有更多行,但考虑到原始类有很多程序等,这种方法确实使单元更具可读性,并且也更容易组合类。

TLCar = class(TRemotable)
private
  FEngine: string;
  FName: string;
published
  property Name: string read FName write FName;
  property Engine: string read FEngine write FEngine;
end;

TLBicycle = class(TRemotable)
private
  FPedals: string;
  FName: string;
published
  property Name: string read FName write FName;
  property Pedals: string read FPedals write FPedals;
end;

TListCarRequest = class(TRemotable)
private
  FreturnedTags: TLCar;
published
  property returnedTags: TLCar read FreturnedTags write FreturnedTags;
end;

TListBiCycleRequest = class(TRemotable)
private
  FreturnedTags: TLBicycle;
published
  property returnedTags: TLBicycle read FreturnedTags write FreturnedTags;

收件人:

TCommonReturnedTags = class(TRemotable)
private
  FName: string;
published
  property Name: string read FName write FName;
end;

TLCar = class(TCommonReturnedTags)
private
  FEngine: string;
published
  property Engine: string read FEngine write FEngine;
end;

TLBicycle = class(TCommonReturnedTags)
private
  FPedals: string;
published
  property Pedals: string read FPedals write FPedals;
end;

TGenericListRequest<T: TCommonReturnedTags, constructor> = class(TRemotable)
private
  FreturnedTags: T;
published
  property returnedTags: T read FreturnedTags write FreturnedTags;
end;

TListCarRequest = class(TGenericListRequest<TLCar>)
end;

TListBiCycleRequest = class(TGenericListRequest<TLBicycle>)
end;

亲切的问候,

【问题讨论】:

  • 哇。勇敢的。是否有某些原因为什么您不只是序列化您的泛型然后远程它们?由于 SOAP Remoting 代码通常由想要解决其错误的人修复和更新,因此更改和重建它不像更改 System.pas 那样有问题。如果是我,如果我要更改它,我希望对这段代码进行单元测试覆盖。
  • @Warren。谢谢,关于 SOAP Remoting 代码的要点。我觉得这对自己来说有点大胆......我真的不明白你在远程处理泛型之前通过序列化泛型来表达什么(我刚刚了解了泛型),你能进一步解释一下吗?除了减少代码量以及限定 RTTI 空间不会用完之外,我基本上没有其他理由。
  • 不是远程处理 TGenericList,而是远程存储在字符串参数中的 TLCARS 的 JSON 字符串。
  • @Warren。好,谢谢。恐怕这有点过头了(我现在不知道从哪里开始...... :-))我想我会坚持使用“正常”类定义并将子类隐藏在其中。然后只需在 wsdl 导入器生成的单元中进行剪切和粘贴,以限制子类的范围。既费时又无聊,但似乎奏效了。

标签: delphi generics soap delphi-xe2


【解决方案1】:

在进行此类修改时需要考虑两件事。 首先,更改是否会对现有功能产生影响。在这种情况下,我会说它是安全的,因为该功能是此操作的新功能,因此不应出现任何意外行为。 第二部分是进化开发环境。环境演变的问题是动作之间的绑定可能会发生变化,这可能会导致意想不到的事情。此时可以假设 XE2 已经分享了更新。如果不是,则在修补或更新时必须密切注意。第二种变化,如从 XE2 到 XE3 的变化可以更好地处理。只需将以下内容放在 Soap.OPToSOAPDomConv.pas 之上:

{$IFNDEF VER230}
   {$MESSAGE ERROR 'Intended to be used with XE2'}
{$ENDIF}

当编译时出错时,你可能会模糊地记得那个文件有一些东西...... 所以简而言之,尝试评估影响并适应环境变化并不是一件坏事。希望这是您想知道的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-11-20
    • 2015-09-11
    • 1970-01-01
    • 1970-01-01
    • 2014-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多