I have wrapper methods for database calls, so I can handle and more particularly log errors, and not have to pad out the main logic for every database call. So, for ExecuteSQL, I might have this:
dbexec (Extends dbh as sqlitedatabase, sql as string, ParamArray args as Variant) as Boolean
try
dbh.ExecuteSQL (sql, args)
Return True // Worked fine, just return
Catch e as DatabaseException
dblogargs (args) // Log argument values here
end try
.
What I want to do in dblogargs is to pick out the args which are integers, and log only those, so I might end up with a message in the log file something like:
arg0=27, arg3=5, arg4=7
(in this picture, I skip arg1 and arg2 because they are strings)
Where I’m getting into trouble is getting the type of each element of args, the ParamArray. If I look at VarType(arg) or arg.Type(), then each arg appears to be type 9 (Object). And if I have an arg that I know to be an integer, then something like:
Var i as Integer = arg.IntegerValue
just gives me a TypeMismatchException. How do I get at the integer that must be hidden in there somehow?
msg3 = " "
i = 0
for each arg in args
nxtype = arg.Type () - 4096
//if (nxtype<>Variant.TypeInt32 and nxtype<>Variant.TypeInt64) then Continue
if (i>0) then msg3 = msg3 + ", "
nxtval = arg.IntegerValue
msg3 = msg3 + "arg" + i.ToString + "=" + nxtval.ToString
i = i + 1
next
Edit: of course, the i.ToString is wrong but I’ll sort that out later.
for each arg in args
select case VarType( arg )
case Variant.TypeInt32, Variant.TypeInt64
// Do your logging output
end select
next
Yes, you could do it with an If, but this scales nicely if you also want to deal with other types (for example double or singles). There’s no need for “- 4096” as an element of the array is never going to be an array itself.
Public Sub TheMethod(Paramarray Args As Variant)
Dim arg As Variant, s As String
For Each arg In Args
s = s + Str(arg.Type) + EndOfLine
Next
MessageBox s
End Sub
Thanks for checking that. The thing is, I’m passing the ParamArray (args) down to another method, which your working examples didn’t do, thus not quite mirroring my case. So I wondered about that. Turns out, if you do that, that in that next method down (dblogargs, see my OP), you no longer declare args as a ParamArray - you just declare it: args() as Variant - and all the issues I was having went away.
So, what I have is:
dbexec (Extends dbh as sqlitedatabase, sql as string, ParamArray args as Variant) as Boolean
try
dbh.ExecuteSQL (sql, args)
Return True // Worked fine, just return
Catch e as DatabaseException
dblogargs (args) // Log argument values here
end try
.
and:
dblogargs (args() as Variant)
// code to log the args.
If you are passing a param array into another function as a param array then I can see why you get an array, as the whole array would likely get passed into a single element of the second param array.
You are boxing the object, you need to unbox it to use it as
Public Function unboxPA(boxedPA As Variant) As String
Var args() As Variant = boxedPA
var msg As String
for each arg as variant in args
msg = msg + arg.StringValue + " = type(" + arg.Type.ToString + ")" + EndOfLine
Next
Return msg
End Function
Public Function pa(paramarray args() As Variant) As String
Return unboxPA(args)
// MessageBox pa("aa", 1, 2)
End Function
Yes. The first use of ParamArray gathers up the list of parameters and puts them into an array, from which they can be taken and analysed just as @Julia_Truchsess and @Rick_Araujo showed. (Seeing that was most helpful). What I was doing was then passing that array through to the next level. But using ParamArray there, caused the one item (the array of parameters) to become the one item in an encompassing array, which is where my troubles started. Perhaps if I’d done:
Var myArray() as variant = args(0)
then all may have worked earlier. But simply omitting the second level ParamArray keyword is better.
A common paradigm is to have a method that does all the work and accepts an array as its parrameter. Then you override it with a method of the same name that accepts a ParamArray as its parameter. All it does is call the first version.
Sub someMethod(a() as variant)
// do the work
End Sub
Sub someMethod(ParamArray pa() as variant)
someMethod(pa)
End Sub
Public Function receive_pa_args(args() As Variant) As String
var msg As String
for each arg as variant in args
msg = msg + arg.StringValue + " = type(" + arg.Type.ToString + ")" + EndOfLine
Next
Return msg
End Function
Public Function pa(paramarray args() As Variant) As String
Return receive_pa_args(args)
End Function
// Use like:
MessageBox pa("aa", 1, 2)