delphi - 如何在 Delphi 中将常量开放数组分配给 TArray<TVarRec>

标签 delphi

我知道 array of const被“翻译”为array of TVarRec由编译器所以我想知道是否有一种方法可以直接存储开放数组的副本(或者可能使用 const 的引用),我的意思是无需创建循环将每个项目从 const 数组复制到TArray<TVarRec> 。以下代码显示了我正在尝试执行的操作。

TAppMessage = class
private
  FMessage: string;
  FArgs: TArray<TVarRec>;
public
  constructor Create(AMessage: string; Args array of const);
  function ToString: string;
end;

constructor TAppMessage.Create(AMessage: string; Args array of const);
begin
  Self.FMessage := AMessage;
  Self.FArgs := Args; //<-- E2010 Incompatible types: 'System.TArray<System.TVarRec>' and 'array of TVarRec'
end;

function TAppMessage.ToString: string;
begin
  Result := Format(Self.FMessage, Self.FArgs);
end;

var AppMsg: TAppMessage;
AppMsg := TAppMessage.Create('A number %d and a text %s', [10, 'foo']);
ShowMessage(AppMsg.ToString); 

有没有办法将一个常量开放数组分配给 TArray<TVarRec>

注意:我使用的是 Delphi 10.2.3(东京)

最佳答案

不要简单地复制 TVarRecs!

看到已经看到几个建议您复制TVarRec的答案s一一变成TArray<TVarRec>这还不够!

它将适用于可以直接存储在 TVarRec 中的值。 ,例如Integer s,但它不适用于不适合的值。它们在堆栈上分配(换句话说:在临时存储中),然后从 TVarRec 引用。 。看看TVarRec的声明:

type
  TVarRec = record { do not pack this record; it is compiler-generated }
    case Integer of
      0: (case Byte of
            vtInteger:       (VInteger: Integer);
            vtBoolean:       (VBoolean: Boolean);
            vtChar:          (VChar: _AnsiChr);
            vtExtended:      (VExtended: PExtended);
{$IFNDEF NEXTGEN}
            vtString:        (VString: _PShortStr);
{$ENDIF !NEXTGEN}
            vtPointer:       (VPointer: Pointer);
            vtPChar:         (VPChar: _PAnsiChr);
{$IFDEF AUTOREFCOUNT}
            vtObject:        (VObject: Pointer);
{$ELSE}
            vtObject:        (VObject: TObject);
{$ENDIF}
            vtClass:         (VClass: TClass);
            vtWideChar:      (VWideChar: WideChar);
            vtPWideChar:     (VPWideChar: PWideChar);
            vtAnsiString:    (VAnsiString: Pointer);
            vtCurrency:      (VCurrency: PCurrency);
            vtVariant:       (VVariant: PVariant);
            vtInterface:     (VInterface: Pointer);
            vtWideString:    (VWideString: Pointer);
            vtInt64:         (VInt64: PInt64);
            vtUnicodeString: (VUnicodeString: Pointer);
         );
      1: (_Reserved1: NativeInt;
          VType:      Byte;
         );
  end;

如您所见,类型如 Currency , VariantShortString显然不适合 TVarRec ,因此它们被引用(并且真实值由运行时放在堆栈上)。如果您只复制 TVarRec s,您不复制这些值,并且由于这些值仅在调用期间有效,因此该引用将一旦例程结束就无效。因此,您必须将这些引用值复制到您自己的存储中,例如:

SetLength(Copies, Length(Values));
for I := 0 to High(Values) do
begin
  Copies[I] := TVarRec(Values[I]);
  case TVarRec(Values[I]).VType of
  ...
    vtExtended:
      begin
        // Copy the referenced Extended to the heap:
        New(Copies[I].VExtended);
        Copies[I].VExtended^ := TVarRec(Values[I]).VExtended^;
      end;
    // etc...

等等...您还必须注意 UnicodeString 的正确重新计数s,AnsiString s,Variant s、接口(interface)等

所以不要听从那些告诉你复制数组的人的建议!

您必须真正进行深层复制,如我所示in an article I have written exactly about this 。我无法引用整篇文章,但您可以在我的网站上找到它。

注意

不要只复制代码,还要阅读本节的其余部分,因为您必须在使用后释放复制数组引用的值,使用此处显示的函数。

关于delphi - 如何在 Delphi 中将常量开放数组分配给 TArray<TVarRec>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53037121/

相关文章:

delphi - XE7 将文本复制到剪贴板

delphi - 无法获得 Spring4D 加密示例的预期结果

arrays - Delphi:const 对象的 const 列表

delphi - FireMonkey - 在 Windows 中绘制 1 像素线而不进行抗锯齿

delphi - 无法使用 TMemoryStream 读取 bool 值

sql-server - 将 UTF8 字符串插入 SQL Server 2008 表时出现 SQL 错误

multithreading - 如何使用 AsyncCalls 调用无参数类过程?

android - Delphi XE6 和 Android(estimote beacon sdk) ClassCastException

delphi - 调用过程 "delayed"的最佳方法是什么?

Delphi Graphics32 在图层上绘制透明椭圆