【发布时间】: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