Как установить строковую (или AnsiString) константу в TVarRec? - PullRequest
5 голосов
/ 19 мая 2011

Я хочу передать аргументы форматирования Args в функцию Формат .Я нашел несколько примеров этого, но я не могу узнать, как назначить строковую константу в элементе TVarRec .Следующий код завершается неудачно при компиляции с 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;

Может кто-нибудь подсказать, как установить константу строки (или AnsiString) для члена TVarRec?Я использую Delphi 2009.

Большое спасибо

Ответы [ 2 ]

10 голосов
/ 19 мая 2011

Это похоже на работу в 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;
5 голосов
/ 19 мая 2011

Только мои два цента. Ответ Тендрея правильный, но я просто хотел подчеркнуть некоторые моменты. И комментарии не являются хорошим местом для этого.

Обратите внимание, что на AnsiString должна быть ссылка в течение всего времени TVarRec.

Например, если вы пишете функцию, устанавливающую массив TVarRec, вы должны убедиться, что вы сделали временную копию AnsiString, созданную в функции, в переменную, которая будет оставаться до тех пор, пока TVarRec массив используется. В противном случае у вас может возникнуть какое-либо нарушение произвольного доступа (не каждый раз, а только в том случае, если ММ переназначит память ansistring).

Например, следующий код неверен :

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;

Поскольку временные переменные AnsiString и UnicodeString будут освобождены после завершения процедуры, а Results[].VString по-прежнему будет указывать на эту освобожденную память ...

Использование класса или записи с некоторой временной частной строкой может помочь:

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;

Конечно, в вашей программе может быть уже существующий класс. В этом случае вам лучше использовать метод и некоторые частные временные строки. Чтобы метод был многопоточным безопасным (т.е. повторно входящим), вы должны предоставить временные строки в качестве параметров ...

Я использую этот трюк, чтобы иметь действительный динамический массив TVarData, содержащий некоторое содержание AnsiString в классе. Фактически, TVarData и TVarRec оба используют такой не ссылочный указатель на строки, что может сбивать с толку.

Имейте в виду, что проблемы, связанные с pointer(S) подобными утверждениями, могут быть сложными для отслеживания.

...