Delphi - 带有变体部分的记录

Posted

技术标签:

【中文标题】Delphi - 带有变体部分的记录【英文标题】:Delphi - records with variant parts 【发布时间】:2011-10-26 11:10:17 【问题描述】:

我想要一个带有“多态”的记录(结构)。它将在所有情况下使用几个字段,我只想在需要时使用其他字段。我知道我可以通过在记录中声明的变体部分来实现这一点。我不知道是否有可能在设计时我只能访问我需要的元素。更具体地说,请看下面的示例

program consapp;

$APPTYPE CONSOLE

uses
  ExceptionLog,
  SysUtils;

type
  a = record
   b : integer;
   case isEnabled : boolean of
    true : (c:Integer);
    false : (d:String[50]);
  end;


var test:a;

begin
 test.b:=1;
 test.isEnabled := False;
 test.c := 3; //because isenabled is false, I want that the c element to be unavailable to the coder, and to access only the d element. 
 Writeln(test.c);
 readln;
end.

这可能吗?

【问题讨论】:

【参考方案1】:

无论标签的值如何,变体记录中的所有变体字段都可以随时访问。

为了实现您正在寻找的可访问性控制,您需要使用属性并进行运行时检查来控制可访问性。

type
  TMyRecord = record
  strict private
    FIsEnabled: Boolean;
    FInt: Integer;
    FStr: string;
    // ... declare the property getters and settings here
  public
    property IsEnabled: Boolean read FIsEnabled write FIsEnabled;
    property Int: Integer read GetInt write SetInt;
    property Str: string read GetString write SetString;
  end;
...
function TMyRecord.GetInt: Integer;
begin
  if IsEnabled then
    Result := FInt
  else
    raise EValueNotAvailable.Create('blah blah');
end;

【讨论】:

这是完全正确的,但在这种情况下,我宁愿使用类而不是记录。它将允许添加继承功能,这在这里很有意义(例如,IsEnable 属性通常在父级处理,并在子级之间共享)。【参考方案2】:

即使我听说按照最初的 Niklaus Wirth 的 Pascal 定义,一切都应该像你预期的那样工作,我在 Delphi 中没有看到这样的行为,从它的祖先 Turbo Pascal 2.0 开始。快速查看 FreePascal 表明 its behaviour 是相同的。如Delphi documentation中所说:

您可以随时读取或写入任何变体的任何字段;但是,如果您先写入一个变体中的字段,然后再写入另一个变体中的字段,则可能会覆盖您自己的数据。该标签(如果有的话)作为记录的非变体部分中的一个额外字段(类型为 ordinalType)。”

关于你的意图,据我了解,我会使用两个不同的类,有点

    a = class
      b : Integer
    end;

    aEnabled = class(a)
      c: Integer
    end;

    aDisabled = class(a)
      d: String //plus this way you can use long strings
    end;

这样,即使在设计时,您也可以从 IDE 的代码编辑器中获得一些支持。不过,更有用的是,以后修改和支持会更容易

但是,如果您需要在运行时快速切换记录变量值,@David Heffernan's variant 使用属性并进行运行时检查更合理。

【讨论】:

【参考方案3】:

给出的示例不是变体记录,它始终包含所有字段。

真正的变体记录具有共享相同内存的变体。您只需使用“case discriminator: DiscType of .....”语法,无需单独的字段告诉您哪些变体处于活动状态。

【讨论】:

是变体记录。情况就是这样。 你说的是 absolute 变量,这是另一回事。大卫是对的,这是一个变体记录。 它不包括所有字段,而是提供对case之后的所有部分的访问权限同时,并且所有这些部分共享相同的内存。所以它类似于 absolute vars,除了:它更结构化;你有标签变量;并且,内存对齐可能有点不同

以上是关于Delphi - 带有变体部分的记录的主要内容,如果未能解决你的问题,请参考以下文章

[转]Delphi 变体类型(Variant)的介绍(流与变体类型的相互转换变体类型常用的函数)

使用 Delphi 管理变体中的空值

允许 IP 的每个变体(主机部分)

在 Delphi 中生成带有嵌入图像的 HTML 电子邮件

具有变体返回类型的 Delphi Excel UDF

Delphi中复制带有String的记录结构时不能使用Move之类的内存操作函数