【问题标题】:Inheritance af list and record fails even though the classes have the same generic types即使类具有相同的泛型类型,继承 af 列表和记录也会失败
【发布时间】:2019-07-14 16:56:16
【问题描述】:

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

我做了一个 TKeyValueList (和一个 TKeyIntValueList = 类(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 identity primary key not null" 以避免在我当前的项目中包含所有 PKs er 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 调用方法时,即带有列表项的 TDBCommTypeIDRecord (TDBCommTypeIDList[StringGridItems.Selected]) 我收到编译器错误:

TDBRecord 与 TDBCommTypeIDRecord 不兼容。

根据泛型(和 Marco Cantú)的文档,泛型与具有完全相同的类型名称无关,而是具有相同的类型。

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

我试图通过以下方式解决它(即规避问题):

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

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 项目来说明问题。

我会 - 基于文档和 Marco Cantú - 期待我的第一次和第二次尝试编译和运行运行时。相反,我收到了作为问题一部分描述的错误消息。

【问题讨论】:

  • 我很确定编译器是正确的,并且您的代码不会被编译。然而,很难看透所有细节。 minimal reproducible example 会有所帮助。
  • 谢谢,但目前我更担心的是,我了解到 Google Play 将终止对 32 位应用程序的支持。这对我的项目来说是一个重大打击,因为 Delphi 不能编译到 Android 64 位。如果我仍然使用 Delphi 并且不重写所有内容,我会回来的。
  • 您需要帮助解决这两个问题中的哪一个?

标签: delphi generics inheritance


【解决方案1】:

TCommDataType 和 FieldIDT 是否兼容?

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

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

TDBCommTypeIDRecord = class(TDBIntIDRecord<TCommDataType>);

进入:

TDBCommTypeIDRecord = class(TDBIntIDRecord<FieldIDT>); 

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

【讨论】:

  • 谢谢,但我相信这样做只会推迟问题。最终我将不得不使它成为 TCommDataType。但目前我有点担心 Google Play 会终止对 32 位应用程序的支持。这对我的项目是一个重大打击。
【解决方案2】:

我自己找到了解决方案:

  TDBListField<FieldIdT> = class(TObject)


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

.......

TDBRecord = 类(TList>)

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

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

// 并在使用它的单元中:

类型

TTestEnumType = (tetNone, tetID, tetName);

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

TEnumIdRecordList = class(TDBRecordList);

//实际使用:

// 像tetID这样的字段ID,例如。

var  
 ID         : Variant;     MyDBRecord : TDBRecord;

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

在晴朗的蓝天上唯一的小黑云是需要使用接口和 Move() 才能使其工作。那为什么还有泛型呢????

这让我想起了我使用汇编程序的日子:

函数 TDBListField.IdToString() : 字符串; var TypInfo :PType信息; TmpInt:整数;大小:整数;

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

case TypInfo^.Kind of 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;

结束;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多