Comment définir une constante chaîne (ou AnsiString) dans TVarRec ?
-
15-11-2019 - |
Question
Je veux transmettre les arguments de formatage Args
dans le Format fonction.J'en ai trouvé quelques exemples, mais je n'arrive pas à savoir comment attribuer une constante de chaîne dans le TVarRec membre.Le code suivant échoue lors de la compilation avec E2089 Invalid typecast
.
procedure TForm1.Button1Click(Sender: TObject);
var Arguments: array of TVarRec;
begin
SetLength(Arguments, 2);
Arguments[0].VInteger := 111;
Arguments[1].VAnsiString := PAnsiString('Text'); // I want to set this member
ShowMessage(Format('Decimal: %d, String: %s', Arguments));
end;
Quelqu'un peut-il me suggérer comment définir la constante chaîne (ou AnsiString) sur le membre TVarRec ?J'utilise Delphi 2009.
Merci beaucoup
La solution
Cela semble fonctionner sous XE :
var
Args: array[0..1] of TVarRec;
S: AnsiString;
U: UnicodeString;
begin
S := 'Hello';
U := 'world';
Args[0].VType := vtAnsiString;
Args[0].VAnsiString := Pointer(S);
Args[1].VType := vtUnicodeString;
Args[1].VUnicodeString := Pointer(U);
Writeln(Format('%s, %s!', Args));
end;
Autres conseils
Juste mes deux cents.La réponse de TOndrej est correcte, mais je voulais juste souligner certains points.Et les commentaires ne sont pas un bon endroit pour le faire.
Veuillez noter que le AnsiString
doit être référencé à tout moment TVarRec
sera utilisé.
Par exemple, si vous écrivez une fonction définissant un tableau de TVarRec
, vous devez vous assurer que vous avez fait une copie temporaire du AnsiString
créé au sein de la fonction à une variable qui restera jusqu'à tout moment TVarRec
tableau est utilisé.Sinon, vous risquez d'avoir une violation d'accès aléatoire (pas à chaque fois, mais seulement lorsque le MM réaffecte le ansistring
mémoire).
Par exemple, le code suivant est Incorrect:
type
TVarRec2 = array[0..1] of TVarRec;
procedure SetVarRec(a,b: integer; var Result: TVarRec2);
begin
Result[0].VType := vtAnsiString;
Result[0].VString := pointer(AnsiString(IntToStr(a)));
Result[1].VType := vtUnicodeString;
Result[1].VString := pointer(UnicodeString(IntToStr(b)));
end;
Parce que le AnsiString
et UnicodeString
les variables temporaires seront libérées à la fin de la procédure, et Results[].VString
pointera toujours vers la mémoire libérée...
Utiliser une classe ou un enregistrement avec une chaîne privée temporaire peut faire l'affaire :
type
TMyVar2 = record
private
tmpA: AnsiString;
tmpB: UnicodeString;
public
VarRec: TVarRec2;
procedure SetVarRec(a,b: integer);
end;
procedure TMyVar2.SetVarRec(a,b: integer);
begin
VarRec[0].VType := vtAnsiString;
tmpA := AnsiString(IntToStr(a));
VarRec[0].VString := pointer(tmpA);
VarRec[1].VType := vtUnicodeString;
tmpB := UnicodeString(IntToStr(b));
VarRec[1].VString := pointer(tmpB);
end;
Bien entendu, dans votre programme, vous pouvez avoir une classe déjà existante.Dans ce cas, vous feriez mieux d'utiliser une méthode et des chaînes temporaires privées.Pour que la méthode soit multi-thread sécurisée (c'est-à-direréentrant), vous devez fournir les chaînes temporaires comme paramètres...
J'utilise cette astuce pour avoir un tableau dynamique valide de TVarData
contenant quelques AnsiString
contenu dans une classe.En fait, TVarData
et TVarRec
les deux utilisent un tel pointeur non référencé vers des chaînes, ce qui peut prêter à confusion.
Soyez conscient que les problèmes impliquant pointer(S)
des déclarations similaires peuvent être difficiles à suivre.