我知道编译器会将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);
有什么办法可以将const的开放数组分配给
TArray<TVarRec>
?注意:我使用的是Delphi 10.2.3(东京)
最佳答案
不要简单地复制TVarRecs!
我看到一些答案,建议您将TVarRec
一张一张地复制到TArray<TVarRec>
中。这还不够!
它适用于可以直接存储在TVarRec
中的值,例如Integer
,但是不适用于不合适的值。它们在堆栈上分配(换句话说:在临时存储中),然后从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
,Variant
或ShortString
这样的类型显然不适合TVarRec
,因此它们被引用(并且真实值由运行时放在堆栈上)。如果仅复制TVarRec
,则不会复制值,并且由于这些值仅在调用期间有效,因此例程结束后,引用将无效。因此,您必须将这些引用的值复制到您自己的存储中,例如: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
,AnsiString
,Variant
,接口等的正确引用。因此,请勿遵循那些告诉您复制阵列的建议!
正如我在in an article I have written exactly about this所示,您必须真正进行深拷贝。我无法引用整篇文章,但您可以在我的网站上找到它。
警告
不要只复制代码,还请阅读本节的其余部分,因为使用后必须使用此处显示的功能释放由复制数组引用的值。
关于delphi - 如何在Delphi中将const的开放数组分配给TArray <TVarRec>,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/53037121/