Como definir a constante string (ou AnsiString) no TVarRec?
-
15-11-2019 - |
Pergunta
Quero passar os argumentos de formatação Args
no Formatar função.Encontrei alguns exemplos disso, mas não consigo descobrir como atribuir uma constante de string no TVarRec membro.O código a seguir falha na compilação com 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;
Alguém pode me sugerir como definir a constante string (ou AnsiString) para o membro TVarRec?Estou usando o Delphi 2009.
Muito obrigado
Solução
Isso parece funcionar no 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;
Outras dicas
Apenas meus dois centavos.A resposta de TOndrej está correta, mas queria apenas enfatizar alguns pontos.E os comentários não são um bom lugar para fazer isso.
Por favor, esteja ciente de que o AnsiString
deve ser referenciado durante todo o tempo TVarRec
será usado.
Por exemplo, se você escrever uma função definindo um array de TVarRec
, você deve garantir que fez uma cópia temporária do AnsiString
criado dentro da função para uma variável que permanecerá até todo o tempo TVarRec
matriz é usada.Caso contrário você poderá ter alguma violação de acesso aleatório (não sempre, mas apenas quando o MM reatribuir o ansistring
memória).
Por exemplo, o código a seguir é incorreta:
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;
Porque o AnsiString
e UnicodeString
variáveis temporárias serão liberadas quando o procedimento terminar, e Results[].VString
ainda apontará para a memória liberada ...
Usar uma classe ou um registro com alguma string privada temporária pode resolver o problema:
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;
Claro, no seu programa você pode já ter uma turma existente.Nesse caso, é melhor usar um método e algumas strings temporárias privadas.Para que o método seja seguro para vários threads (ou seja,reentrante) você deve fornecer as strings temporárias como parâmetros ...
Eu uso esse truque para validar uma matriz dinâmica de TVarData
contendo alguns AnsiString
conteúdo de uma aula.Na verdade, TVarData
e TVarRec
ambos usam ponteiros não referenciados para strings, o que pode ser confuso.
Esteja ciente de que questões envolvendo pointer(S)
declarações semelhantes podem ser difíceis de rastrear.