即使类具有相同的泛型类型,列表和记录的继承也会失败

时间:2019-07-14 16:56:16

标签: delphi generics inheritance

我的目标是使用相同的代码创建多个类似的列表(因此,我不必多次编写LoadFromString()和LoadFromXML()。

我做了一个TKeyValueList (和     TKeyIntValueList = class(TKeyValueList

TKeyValueItem<T> = class(TLockObject)

protected
  FKey   : T;
  FValue : Variant;
  ....... etc

TKeyValueList<T> = class(TLockObject)

protected
  FList : TList<TKeyValueItem<T>>;
  ------ etc

那很好。...

但是,当我想创建一个列表列表来保存通过TCP / IP(使用我自己的“ RESTFUL”协议)发送的数据库记录中的值时,它会失败。

基类:

TDBRecord<IDT, FieldIDT> = class(TKeyValueList<FieldIDT> );
// Any ID type (i.e. Primary key from DB kan be int/string etc)
// Any type of field identifier, e.g. string for field name or my own 
// TCommDataType (enumeration like cdtTextID....)

基本列表定义为

TDBRecordList<IDT, FieldIDT> = class(TList<TDBRecord<IDT, FieldIDT>)

然后,我定义了一个通用后代,以使用int主键保存数据库中的记录,例如SQL Server“ t_TextID int身份主键不为null”,以避免必须将其包含在当前项目中,其中所有PK都为int。

TDBIntIDRecord<FieldIDT> = class(TDBRecord<Integer, FieldIDT>);

TDBIntIDRecordList<FieldIDT, T : TDBIntIDRecord<FieldIDT>> = class(TDBRecordList<Integer, FieldIDT, T>);

要对此进行专门说明,而不必指定字段名称的类型(这是一个枚举),我这样做是:

TDBCommTypeIDRecord = class(TDBIntIDRecord<TCommDataType>);

TDBCommTypeIDList = class(TDBIntIDRecordList<TCommDataType>) 

当我尝试使用单个TDBRecord调用方法时,即带有列表项(TDBCommTypeIDList [StringGridItems.Selected])的TDBCommTypeIDRecord时,出现编译器错误:

  

TDBRecord与TDBCommTypeIDRecord不兼容。

根据泛型(和MarcoCantú)的文档,泛型不限于具有完全相同的类型名称,而是具有相同的类型。

那为什么那部分不起作用?????

我尝试通过以下方法解决该问题(即规避问题):

///////////////

TDBRecord<IDT, FieldIDT> = class(TKeyValueList<FieldIDT> );

TDBRecordList<IDT, FieldIDT, T : TDBRecord<IDT, FieldIDT>> = class(TList<T>);


TDBIntIDRecord<FieldIDT> = class(TDBRecord<Integer, FieldIDT>);

TDBIntIDRecordList<FieldIDT, T : TDBIntIDRecord<FieldIDT>> = class(TDBRecordList<Integer, FieldIDT, T>);


///////////////

这给了我一个编译时错误,表明IDT与FieldIDT不兼容。好吧,显然不是! 现在,IDT是Integer而不是FieldIDT(在TCommDataType定义的流中更晚)

但是声明 -TDBRecord和 -TDBRecordList

如我所见,应该消除IDT。

我在做什么错? 我误会了什么?

请帮助...

问题中描述了我解决这个问题的尝试。

问题描述中包含的代码。我可以提供完整的POC项目来说明问题。

基于文档和MarcoCantú,我希望我的第一次和第二次尝试都是编译和运行运行时。相反,我得到了描述为问题一部分的错误消息。

2 个答案:

答案 0 :(得分:0)

TCommDataType和FieldIDT是否兼容?

有几种违反兼容性的可能性,请参考:http://docwiki.embarcadero.com/RADStudio/Rio/en/Type_Compatibility_and_Identity_(Delphi)

我建议您尝试修改以下行:

TDBCommTypeIDRecord = class(TDBIntIDRecord<TCommDataType>);

进入:

TDBCommTypeIDRecord = class(TDBIntIDRecord<FieldIDT>); 

看看是否仍然存在相同的错误。

答案 1 :(得分:0)

我自己找到了解决方案:

  TDBListField<FieldIdT> = class(TObject)


    property ID    : FieldIdT read GetId;
    property Value : Variant read GetValue write SetValue;

.......

  

TDBRecord = class(TList>)

 TDBRecordList<FieldIdT> = class(TList<TDBRecord<FieldIdT>>)

// --------------------------------------------- ------------------

//在使用它的单元中:

  

类型

     

TTestEnumType =(tetNone,tetID,tetName);

     

type //字段ID,例如0、1、2、3等,类似于   TQuery.Fields [0] .Value等。TIntIdRecordList =   class(TDBRecordList);

     

TEnumIdRecordList = class(TDBRecordList);

//实际使用情况:

//字段ID,例如tetID,例如

var  
 ID         : Variant;     MyDBRecord : TDBRecord;

  begin
 MyDBRecord   := FRecordList[0];   ID           := MyDBRecord[tetID].Value;
  end;

否则,湛蓝的天空上唯一的小乌云就是需要使用接口和Move()使其起作用。然后为什么要泛型呢??

这让我想起了我在汇编程序方面的日子:

  

function TDBListField.IdToString():字符串; var TypInfo   :PTypeInfo; TmpInt:整数;大小:整数;

     

开始尝试TypInfo:= PTypeInfo(TypeInfo(FieldIdT)); TmpInt   := 0;

     

案例TypInfo ^。种类        tkUnknown:引发Exception.Create('Whoops');

 tkInteger,
 tkInt64       : begin

                  Size   := SizeOf(FieldIdT);
                  Move(FId, TmpInt, Size);
                  Result := IntToStr(TmpInt);
                 end;


 tkEnumeration : begin

.....

  

类函数TDBListField.IDsEqual(AA:FieldIdT; AB:   FieldIdT):布尔值; var Cmp:IComparer;

     

开始Cmp:= TComparer.Default;

     

结果:= Cmp.Compare(AA,AB)= 0;

     

end;