TRemotable类中的Delphi XE2泛型

时间:2012-11-01 16:54:21

标签: delphi generics soap delphi-xe2

由于与问题不相关的原因,我想在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;

亲切的问候,

1 个答案:

答案 0 :(得分:1)

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

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

在编译时遇到错误时,您可能会模糊地记得该文件存在某些内容...... 简而言之,就评估影响和适应环境变化而言,这并不是坏事。希望这是你想知道的。