如何实现具有不同元素类型的链表?

时间:2021-10-08 13:42:39

I want to create a list in which every element must have 3 fields: KeyType, KeyName, Value. The type of Value field should be: String, Cardinal, Integer, Byte, Boolean... depending on value of the KeyType. I need this to make something like windows registry. It is possible ?

我想创建一个列表,其中每个元素必须有3个字段:KeyType,KeyName,Value。 Value字段的类型应为:String,Cardinal,Integer,Byte,Boolean ...取决于KeyType的值。我需要这个来制作像windows注册表这样的东西。有可能的 ?

2 个解决方案

#1


I'd use an off the shelf generic linked list. I'm sure Spring has some, but if you don't want to take on all the dependencies that would entail you could use Chris Rolliston's simple linked list: https://code.google.com/p/ccr-exif/source/browse/blogstuff/CCR.SimpleLinkedList.pas?r=34

我会使用现成的通用链表。我确信Spring有一些,但是如果你不想接受所有依赖,那么你可以使用Chris Rolliston的简单链接列表:https://code.google.com/p/ccr-exif/source /browse/blogstuff/CCR.SimpleLinkedList.pas?r=34

Then you just need to decide on the type of the payload. Use a variant type like, for instance, TValue or Variant, although the latter would constrain you to Windows. Or you could make your own bespoke variant type:

然后你只需要决定有效载荷的类型。使用变体类型,例如TValue或Variant,尽管后者会限制您使用Windows。或者您可以制作自己的定制变体类型:

type
  TMyValue = record
    StringValue: string; // managed type must be outside variant part of record
    case DataType: TDataType of
    dtInteger:
      (IntegerValue: Integer);
    dtCardinal: 
      (CardinalValue: Cardinal);
    ....
  end;

You'd then make a node type like this:

然后,您将创建一个这样的节点类型:

type
  TNode = record
    Name: string;
    Value: TValue; // or TMyValue
  end;

Finally, your linked list is simply TSimpleLinkedList<TNode> and you are done.

最后,您的链接列表只是TSimpleLinkedList ,您就完成了。

In my opinion it is important to use a generic container here for the sake of consistency. Doing so allows you to keep separate the aspects of the container and the element.

在我看来,为了保持一致性,在这里使用通用容器很重要。这样做可以让您将容器和元素的各个方面分开。

#2


There are two options.

有两种选择。

You can use a nornal record/class with a variant type, something like:

您可以使用具有变体类型的nornal记录/类,例如:

type
  TDataType = (dtBoolean, dtString, ....);
  PNode = ^TNode;
  TNode = record
    Prev, Next: PNode;
    Keyname: string;
    DataType: TDataType;
    Data: variant; //or TValue
  end;

Or ue a variant record

或者是一个变体记录

  TNode = record
    Prev, next: PNode;
    DataType: TDataType;
    Keyname: string;
    Datastring:string;
    case DataType of
      dtCardinal: (datacardinal: Cardinal);
      dtBoolean: (databoolean: boolean);
      ....
    end;

Note that managed types such as interfaces and strings cannot be included in the variant part of the record, so you'll have to put those in the normal part before that.

请注意,托管类型(如接口和字符串)不能包含在记录的变体部分中,因此您必须在此之前将它们放在正常部分中。

Registry cannot be captured in a linked list  

无法在链接列表中捕获注册表

Note that the registry is a tree, you you'll need a tree instead of a linked list, that means you'll need 3 links: root, left, right.
And you'll need to use a tree structure. Any tree can be mapped to a binary tree, so 3 is all you need (two if you leave out the root node).

请注意,注册表是树,您需要树而不是链表,这意味着您需要3个链接:root,left,right。而且你需要使用树形结构。任何树都可以映射到二叉树,因此您只需要3个(如果省略根节点则为2个)。

TDictionary<string, TNode>

Will also work. In that case TNode does not include Prev/next members because the dictionary takes care of that.

也会工作。在那种情况下,TNode不包括上一个/下一个成员,因为字典会处理这个问题。

#1


I'd use an off the shelf generic linked list. I'm sure Spring has some, but if you don't want to take on all the dependencies that would entail you could use Chris Rolliston's simple linked list: https://code.google.com/p/ccr-exif/source/browse/blogstuff/CCR.SimpleLinkedList.pas?r=34

我会使用现成的通用链表。我确信Spring有一些,但是如果你不想接受所有依赖,那么你可以使用Chris Rolliston的简单链接列表:https://code.google.com/p/ccr-exif/source /browse/blogstuff/CCR.SimpleLinkedList.pas?r=34

Then you just need to decide on the type of the payload. Use a variant type like, for instance, TValue or Variant, although the latter would constrain you to Windows. Or you could make your own bespoke variant type:

然后你只需要决定有效载荷的类型。使用变体类型,例如TValue或Variant,尽管后者会限制您使用Windows。或者您可以制作自己的定制变体类型:

type
  TMyValue = record
    StringValue: string; // managed type must be outside variant part of record
    case DataType: TDataType of
    dtInteger:
      (IntegerValue: Integer);
    dtCardinal: 
      (CardinalValue: Cardinal);
    ....
  end;

You'd then make a node type like this:

然后,您将创建一个这样的节点类型:

type
  TNode = record
    Name: string;
    Value: TValue; // or TMyValue
  end;

Finally, your linked list is simply TSimpleLinkedList<TNode> and you are done.

最后,您的链接列表只是TSimpleLinkedList ,您就完成了。

In my opinion it is important to use a generic container here for the sake of consistency. Doing so allows you to keep separate the aspects of the container and the element.

在我看来,为了保持一致性,在这里使用通用容器很重要。这样做可以让您将容器和元素的各个方面分开。

#2


There are two options.

有两种选择。

You can use a nornal record/class with a variant type, something like:

您可以使用具有变体类型的nornal记录/类,例如:

type
  TDataType = (dtBoolean, dtString, ....);
  PNode = ^TNode;
  TNode = record
    Prev, Next: PNode;
    Keyname: string;
    DataType: TDataType;
    Data: variant; //or TValue
  end;

Or ue a variant record

或者是一个变体记录

  TNode = record
    Prev, next: PNode;
    DataType: TDataType;
    Keyname: string;
    Datastring:string;
    case DataType of
      dtCardinal: (datacardinal: Cardinal);
      dtBoolean: (databoolean: boolean);
      ....
    end;

Note that managed types such as interfaces and strings cannot be included in the variant part of the record, so you'll have to put those in the normal part before that.

请注意,托管类型(如接口和字符串)不能包含在记录的变体部分中,因此您必须在此之前将它们放在正常部分中。

Registry cannot be captured in a linked list  

无法在链接列表中捕获注册表

Note that the registry is a tree, you you'll need a tree instead of a linked list, that means you'll need 3 links: root, left, right.
And you'll need to use a tree structure. Any tree can be mapped to a binary tree, so 3 is all you need (two if you leave out the root node).

请注意,注册表是树,您需要树而不是链表,这意味着您需要3个链接:root,left,right。而且你需要使用树形结构。任何树都可以映射到二叉树,因此您只需要3个(如果省略根节点则为2个)。

TDictionary<string, TNode>

Will also work. In that case TNode does not include Prev/next members because the dictionary takes care of that.

也会工作。在那种情况下,TNode不包括上一个/下一个成员,因为字典会处理这个问题。