I have a 'Base class' which contain a 'function' that accept parameter of type 'Array of const' as shown below:-
type
  TBaseClass = class(TObject)
  public
    procedure NotifyAll(const AParams: array of const);
  end;
procedure TBaseClass.NotifyAll(const AParams: array of const);
begin
  // do something
end;
I have another 'Generic class' that is derived from the 'base class' ( defined above )
type
  TEventMulticaster<T> = class(TBaseClass)
  public
    procedure Notify(AUser: T); reintroduce;
  end;
procedure TEventMulticaster<T>.Notify(AUser: T);
begin
  inherited NotifyAll([AUser]);   ERROR HERE
end;
Every time I compile this code it gives error saying:
Bad argument type in variable type array constructor
What does it referring to be wrong?
You cannot pass a Generic argument as a variant open array parameter. The language Generics support simply does not cater for that.
What you can do instead is wrap the Generic argument in a variant type, for instance TValue. Now, you cannot pass TValue instances in a variant open array parameter either, but you can change NotifyAll() to accept an open array of TValue instead:
procedure NotifyAll(const AParams: array of TValue);
Once you have this in place, you can call it from your Generic method like so:
NotifyAll([TValue.From<T>(AUser)]);
Fundamentally, what you are attempting to do here is combine compile-time parameter variance (Generics) with run-time parameter variance. For the latter, there are various options. Variant open array parameters are one such option, but they do not play well with Generics. The alternative that I suggest here, TValue, does have good interop with Generics.
The System.Rtti unit has something exactly for you needs, but not widely known:
TValueArrayToArrayOfConst() and
ArrayOfConstToTValueArray()
So your implementation should be:
procedure TEventMulticaster<T>.Notify(AUser: T);
var
  ParametersAsTValueArray: array[1 .. 1] of TValue;
begin
  ParametersAsTValueArray[1] := TValue.From<T>(AUser);
  NotifyAll(TValueArrayToArrayOfConst(ParametersAsTValueArray));
end;
Notes:
TValueArrayToArrayOfConst()'s result is a non-owning container. It contains memory pointers backed by the source array of the TValue container. ParametersAsTValueArray is alive and not being altered while the array of const is used.Rtti procedures has a bug with regard to TClass values processing. TClass becomes a Pointer on some stage, and string.Format() breaks because Pointer and TClass are not the same thing. Perform tests on all TVarRec.VType, they are not so many, much less that Variant's VType.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With