delphi 临时变量的记录类型

bksxznpy  于 2023-02-04  发布在  其他
关注(0)|答案(1)|浏览(151)

如何将记录存储到临时变量中并通过函数传递?
如果我有两条记录:

TMyRec1 = packed record
  SomeValue : Integer;
end;

TMyRec2 = packed record
  ThisIsMessage : String;
end;

现在我希望能够做这样的事情:

function GetRec(recId: Integer) : Variant;
begin
  case (recId) of
    1 : Result := TMyRec1.Create();
    2 : Result := TMyRec2.Create();
    //... many
  else
    
  end;
end;

也可以将其返回到原始类型,如:

function GetRec1(rec: Variant) : TMyRec1;
begin
  Result := TMyRec1(rec);
  // here I do lots of default things with this record type
end;

function GetRec2(rec: Variant) : TMyRec2;
begin
  Result := TMyRec2(rec);
  // here I do lots of default things with this record type
end;

最后,一个完整的函数应该能够完成以下操作:

procedure MainFunction();
var myRec : Variant; //I want to avoid to specify each T here
begin
  myRec := GetRec(1);
  PrintRec1(GetRec1(myRec));

  myRec := GetRec(2);
  PrintRec2(GetRec2(myRec));
end;

procedure PrintRec1(rec: TMyRec1);
begin
  Print(IntToStr(rec.SomeValue));
end;

procedure PrintRec2(rec: TMyRec2);
begin
  Print(rec.ThisIsMessage);
end;

我试过使用变体、TObject、NativeUInt铸造,但似乎都不起作用。
谢谢你的帮助。

    • 编辑**
TMyRec = record
end;

TMyRec1 = TMyRec
  SomeValue : Integer;
end;

TMyRec2 = TMyRec
  ThisIsMessage : String;
end;

会做出这样的事吗?
我不需要安全检查和上升的异常,我会照顾,以确保我通过正确的一个需要。

hwamh0ep

hwamh0ep1#

默认情况下,record不像class那样具有Create()构造函数,因此TMyRec1.Create()TMyRec2.Create()不会像下面所示那样工作。
但是,在 Delphi 2006及更高版本中,您可以手动添加一个静态Create()方法,该方法返回一个新的record示例(一些Delphi自己的原生RTL记录会这样做,如TFormatSettingsTRttiContext等),例如:

TMyRec1 = packed record
  SomeValue : Integer;
  class function Create: TMyRec1; static;
end;

TMyRec2 = packed record
  ThisIsMessage : String;
  class function Create: TMyRec2; static;
end;

...

class function TMyRec1.Create: TMyRec1;
begin
  Result.SomeValue := ...;
end;

class function TMyRec2.Create: TMyRec2;
begin
  Result.ThisIsMessage := ...;
end;

否则,对于早期版本,您将不得不使用独立函数,例如:

TMyRec1 = packed record
  SomeValue : Integer;
end;

TMyRec2 = packed record
  ThisIsMessage : String;
end;

function CreateRec1: TMyRec1;
function CreateRec2: TMyRec2;

...

function CreateRec1: TMyRec1;
begin
  Result.SomeValue := ...;
end;

function CreateRec2: TMyRec2;
begin
  Result.ThisIsMessage := ...;
end;

但是,不管怎样,要知道默认情况下,你不能在Variant中存储任意的record类型,它不知道如何存储和检索它们。你必须教它如何做。你可以从TCustomVariantType派生一个类,并覆盖它的各种操作方法,如强制转换、比较等。然后用RTL注册该类,这样Variant基础结构就知道它了。有关详细信息,请参阅 Delphi 文档中的Defining Custom Variants。只有这样,您的GetRec()GetRec1()GetRec2()函数能够完全按照您编写的代码工作。
否则,请考虑另一种方法,例如定义自定义标记记录,类似于Variant的内部工作方式,例如:

PMyRec1 = ^TMyRec1;
TMyRec1 = packed record
  SomeValue : Integer;
end;

PMyRec2 = ^TMyRec2;
TMyRec2 = packed record
  ThisIsMessage : String;
end;

TMyRec = record
  case Tag: Integer of
    1 : (Rec1: PMyRec1);
    2 : (Rec2: PMyRec2);
    ...
end;

function GetRec(recId: Integer) : TMyRec;
begin
  Result.Tag := recId;
  case recId of
    1 : New(Result.Rec1);
    2 : New(Result.Rec2);
    ...
  else
    raise ...;    
  end;
end;

function DisposeRec(var rec: TMyRec);
begin
  case rec.Tag of
    1 : Dispose(rec.Rec1);
    2 : Dispose(rec.Rec2);
    ...
  end;
  rec.Tag := 0;
end;

function GetRec1(var rec: TMyRec) : TMyRec1;
begin
  if rec.Tag <> 1 then raise ...;
  Result := rec.Rec1^;
  // here I do lots of default things with this record type
end;

function GetRec2(var rec: TMyRec) : TMyRec2;
begin
  if rec.Tag <> 2 then raise ...;
  Result := rec.Rec2^;
  // here I do lots of default things with this record type
end;

procedure MainFunction;
var
  myRec : TMyRec;
begin
  myRec := GetRec(1);
  try
    PrintRec1(GetRec1(myRec));
  finally
    DisposeRec(myRec);
  end;

  myRec := GetRec(2);
  try
    PrintRec2(GetRec2(myRec));
  finally
    DisposeRec(myRec);
  end;
end;

procedure PrintRec1(const rec: TMyRec1);
begin
  Print(IntToStr(rec.SomeValue));
end;

procedure PrintRec2(const rec: TMyRec2);
begin
  Print(rec.ThisIsMessage);
end;

相关问题