我的目标是使用相同的代码创建多个类似的列表(因此,我不必多次编写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ú,我希望我的第一次和第二次尝试都是编译和运行运行时。相反,我得到了描述为问题一部分的错误消息。
答案 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;