Andersen Chang
Andersen Chang

Reputation: 45

RTTI & Variant Open Array Parameters

Related to the question TVirtualMethodInterceptor.Create doesn't support the class that has overload virtual method. . After the modification of RRUZ's answer I got another problem. How should I call the second overload method "SaveLog(str: string; Args: array of TConst);" . As below codes

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;

The code " ttt.SaveLog('ID = %d', [nID]); " will get compiler error : E2250 There is no overloaded version of 'SaveLog' that can be called with these arguments . How should I do ?

Upvotes: 2

Views: 503

Answers (1)

David Heffernan
David Heffernan

Reputation: 612993

The Args parameter is a dynamic array. Create and populate a dynamic array and pass that.

Your code fails to compile because you attempt to pass an open array constructor. That would be valid if you had an open array, but you don't. You have a dynamic array.

One useful trick you might use is to define a function that accepts a variant open array and returns a dynamic array. Then you can adapt one to the other inline. The function would be declared like this:

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

Note that I am preferring to use the generic dynamic array TArray<T> instead of your TConst. Doing so has benefits of better type compatibility.

Rudy Velthuis covers this in some detail, and shows how to implement the adapter function in this article: Open array parameters and array of const.


That said, TVarRec is not designed for explicit use. It's the runtime support for variant open arrays. As Rudy's article demonstrates, it takes a fair bit of explicit memory management once you've left the safe confines of compiler support for variant open arrays. I would not recommend the use of TArray<TVarRec>.

Instead, I suggest that you use the modern variant type, the type that has been designed for use with new style RTTI. That is TValue. This variant type has been designed for explicit use and memory management is performed automatically. Use TArray<TValue> rather than TArray<TVarRec>.

Upvotes: 1

Related Questions