3

由于与我想在我的 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);

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

过程中的新变量:

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;

亲切的问候,

4

1 回答 1

1

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

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

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

于 2014-03-06T20:14:39.920 回答