记录为空?

Record is empty?

Delphi的记录类型中是否有任何数据?怎么理解?

例如,假设得到这样的记录类型;

type
  TDummy = PACKED record
    Text   : String;
    Number : Integer;
  end;
var
  aRecord : TDummy;
begin
  aRecord := default(TDummy);   // In this state "aRecord" is empty. (Text = '' and Number = 0)
  aRecord.Text := 'TEST';       // This is no longer empty
end;

那么,有什么方法可以在不浏览记录项的情况下解决这个问题吗?

使用成员函数

恕我直言,到目前为止最干净的方法是声明一个方法 TDummy.IsEmpty: Boolean:

type
  TDummy = record
    Text: string;
    Number: Integer;
    function IsEmpty: Boolean;
  end;

{ TDummy }

function TDummy.IsEmpty: Boolean;
begin
  Result := (Text = '') and (Number = 0);
end;

那你可以随时用这个方法查看记录是否为空:

procedure TForm1.FormCreate(Sender: TObject);
var
  D: TDummy;
begin

  D := Default(TDummy);

  if D.IsEmpty then
    ShowMessage('D is empty.');

  D.Number := 394;

  if D.IsEmpty then
    ShowMessage('D is empty.');

end;

使用等号运算符

另一种方法:

type
  TDummy = record
    Text: string;
    Number: Integer;
    class operator Equal(const Left, Right: TDummy): Boolean;
    class operator NotEqual(const Left, Right: TDummy): Boolean;
  end;

const
  EmptyDummy: TDummy = ();

{ TDummy }

class operator TDummy.Equal(const Left, Right: TDummy): Boolean;
begin
  Result := (Left.Text = Right.Text) and (Left.Number = Right.Number);
end;

class operator TDummy.NotEqual(const Left, Right: TDummy): Boolean;
begin
  Result := not (Left = Right);
end;

现在你可以做

procedure TForm1.FormCreate(Sender: TObject);
var
  D: TDummy;
begin

  D := Default(TDummy);

  if D = EmptyDummy then
    ShowMessage('D is empty.');

  D.Number := 394;

  if D = EmptyDummy then
    ShowMessage('D is empty.');

end;

疯狂的东西

如果您绝对不想单独比较每个成员,您可以在某些情况下比较字节。

但请注意,一般情况下,您不能通过比较字节来比较两条记录。仅提及两个明显的原因:

  1. 字符串成员在语义上可能相等,即使它们由两个不同的字符串堆对象表示(因此比较器说“不相等”,而实际上它们是相等的)。

  2. 如果记录不是 packed,则记录可能有填充(因此比较器可能会说“不相等”,而实际上它们是相等的)。

但您只想与“默认”(归零)值进行比较,作为奖励,您的记录类型恰好是 packed,因此您可以逃脱

type
  TDummy = packed record
    Text: string;
    Number: Integer;
  end;

  TZeroRecord<T: record> = record
    class function IsZero([Ref] const ARecord: T): Boolean; static;
  end;

{ TZeroRecord<T> }

class function TZeroRecord<T>.IsZero([Ref] const ARecord: T): Boolean;
begin
  var DefT := Default(T);
  Result := CompareMem(@ARecord, @DefT, SizeOf(T));
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  D: TDummy;
begin

  D := Default(TDummy);

  if TZeroRecord<TDummy>.IsZero(D) then
    ShowMessage('D is empty.');

  D.Number := 394;

  if TZeroRecord<TDummy>.IsZero(D) then
    ShowMessage('D is empty.');

end;

但这太疯狂了。