RTTI 和变体开放数组参数

RTTI & Variant Open Array Parameters

与问题相关。 RRUZ的答案修改后又遇到了一个问题。 我应该如何调用第二个重载方法 "SaveLog(str: string; Args: array of TConst);" 。 如下代码

type

  TConst = array of TVarRec;

  TLog = class
  public
    constructor Create();

    procedure SaveLog(str: string); overload; virtual;
    procedure SaveLog(str: string; Args: TConst); overload;  virtual;
  end;

constructor TLog.Create(str: string);
begin

end;

procedure TLog.SaveLog(str: string);
begin
  MessageBox(GetFocus(), PChar(str), 'Test Message', MB_OK);
end;

procedure TLog.SaveLog(str: string; Args: TConst);
var
  buf: string;

begin
  buf:=Format(str, Args);
  SaveLog(buf);
end;


procedure MyTest(nID: Integer);
var
  ttt: TLog;
  vmi: TVirtualMethodInterceptor;

begin
  ttt:=TLog.Create();
  try
    ttt.SaveLog('ID = %d', [nID]);
    vmi:=TVirtualMethodInterceptor.Create(ttt.ClassType);
    try
      //
    finally
      vmi.Free();
    end;
  finally
    ttt.Free();
  end;
end;

代码“ttt.SaveLog('ID = %d',[nID]);”将得到 编译器错误:E2250 没有可以用这些参数调用的 'SaveLog' 的重载版本。 我该怎么办?

Args参数是一个动态数组。创建并填充一个动态数组并传递它。

您的代码无法编译,因为您试图传递一个开放数组构造函数。如果你有一个开放数组,那将是有效的,但你没有。你有一个动态数组。

您可能会使用的一个有用的技巧是定义一个接受变体开放数组和 returns 动态数组的函数。然后你可以使一个适应另一个内联。该函数将像这样声明:

function VariantOpenArrayToDynArray(const Args: array of const): TArray<TVarRec>;

请注意,我更喜欢使用通用动态数组 TArray<T> 而不是您的 TConst。这样做有更好的类型兼容性的好处。

Rudy Velthuis 对此进行了一些详细介绍,并展示了如何在本文中实现适配器功能:Open array parameters and array of const


也就是说,TVarRec 并非专为明确使用而设计。它是对变体开放数组的运行时支持。正如 Rudy 的文章所展示的那样,一旦您离开编译器对变体开放数组的支持的安全范围,就需要相当多的显式内存管理。我不推荐使用 TArray<TVarRec>.

相反,我建议您使用现代变体类型,该类型专为与新型 RTTI 一起使用而设计。即TValue。此变体类型专为显式使用而设计,内存管理是自动执行的。使用 TArray<TValue> 而不是 TArray<TVarRec>.