由于与问题不相关的原因,我想在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 Importer使所有这些类在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;
亲切的问候,
丹
答案 0 :(得分:1)
进行此类修改时需要考虑两件事。 首先,这种变化是否会对现有功能产生影响。在这种情况下,我会说它是安全的,因为该操作的功能是新的,所以不应该有任何意外的行为。 第二部分是进化发展环境。环境演变的问题在于,操作之间的绑定可能会发生变化,从而导致出现意外情况。在这一刻,可以假设XE2已经拥有它的更新份额。如果不这样做,则必须在修补或更新时留意。可以更好地处理从XE2到XE3的第二种变化。只需将以下内容放在 Soap.OPToSOAPDomConv.pas 的顶部:
{$IFNDEF VER230}
{$MESSAGE ERROR 'Intended to be used with XE2'}
{$ENDIF}
在编译时遇到错误时,您可能会模糊地记得该文件存在某些内容...... 简而言之,就评估影响和适应环境变化而言,这并不是坏事。希望这是你想知道的。