In my VO Code I use Sendclass to modify a SDK constructor's behaviour. This looks like this and worked fine for more than a decade:
(this is part of my dbServer_Subclass INit() method)
if !lFromLocked // no special actions needed
SUPER( )
else
SendClass( self, #Init, #DataServer ) // instead of SUPER:Init
(my own constructor code)
endif
In XSharp SendClass is no longer supported, so I want to try something like this:
if !lFromLocked // no special actions needed
SUPER( )
else
var t := FindClass(#DataServer)
var constructors := t:GetConstructors()
var ctor := constructors:FirstOrDefault()
if ctor != null
try
ctor:Invoke()
(my own constructor code)
catch as Error
throw
catch e as Exception
throw Error{e:GetInnerException()}
end try
endif
endif
Unfortunately, System.Reflection.ConstructorInfo.Invoke wants a handful of parameters which I don't understand. Could someone help me out here - or is my approach wrong anyway?
Sendclass substitute
-
- Posts: 71
- Joined: Thu Jul 15, 2021 10:46 am
- Location: Germany
Sendclass substitute
Stefan,
Smart, but dirty solution.
I would recommend to call the Invoke overload that accepts an array of Objects
and then use the function _ArrayToObjectArray() to convert a normal VO array of arguments to OBJECT[]
and pass that to the constructor.
or
Robert
Smart, but dirty solution.
I would recommend to call the Invoke overload that accepts an array of Objects
and then use the function _ArrayToObjectArray() to convert a normal VO array of arguments to OBJECT[]
and pass that to the constructor.
Code: Select all
ctor:Invoke( _ArrayToObjectArray({})) // for no arguments
Code: Select all
ctor:Invoke( _ArrayToObjectArray({1,2,3})) // with some example arguments.
XSharp Development Team
The Netherlands
robert@xsharp.eu
The Netherlands
robert@xsharp.eu
Sendclass substitute
Hi Stefan,
It's not necessarily wrong, but it's definitely very naughty
It can work though, the CLIPPER calling convention constructors/methods expect (they've been implemented in X# this way) a single ARRAY of USUALs as an argument , containing the actual arguments to be passed to it. The ctor:Invoke() in turn expects the arguments to send to the constructor in an ARRAY of OBJECTs. So you need to send it such an array, containing a single element, the former array of usuals. A little complicated, but this code should do the trick:
Note that in this particular case, the first array is empty, because the constructor of the DataWindow class does not need any params. If you instead wanted to call the constructor of DataWindow for example, you would have to change the code to something like
hth
It's not necessarily wrong, but it's definitely very naughty
It can work though, the CLIPPER calling convention constructors/methods expect (they've been implemented in X# this way) a single ARRAY of USUALs as an argument , containing the actual arguments to be passed to it. The ctor:Invoke() in turn expects the arguments to send to the constructor in an ARRAY of OBJECTs. So you need to send it such an array, containing a single element, the former array of usuals. A little complicated, but this code should do the trick:
Code: Select all
LOCAL aArgsToCtor AS USUAL[] // syntax to define an ARRAY of USUALs
aArgsToCtor := <USUAL>{} // instantiating the array, with zero elements. Also this would do the same: aArgsToCtor := USUAL[]{0}
LOCAL oArgToInvoke AS OBJECT[]
oArgToInvoke := <OBJECT>{aArgsToCtor}
ctor:Invoke(oArgToInvoke)
Code: Select all
aArgsToCtor := <USUAL>{oParent , oResource , _GetInst()}
Chris Pyrgas
XSharp Development Team
chris(at)xsharp.eu
XSharp Development Team
chris(at)xsharp.eu
-
- Posts: 71
- Joined: Thu Jul 15, 2021 10:46 am
- Location: Germany
Sendclass substitute
Thank you - especially - Array2ObjectArray is a very useful hint which suits me for many other occasions.
The reason why I need the dirty trick (I'm telling this because maybe there is a better approach):
We need to stick to DBFs due to a reporting software which we mußte maintain for some more years. We as also need to protect the database against theft or malware Wunder a user account. So we strip the users (clients) of all rights to the directory and redirect all file operations though some server side stored procedures. Since the dbServer class has several internal uses of file functions we use the dirty trick to inject our own Filespec subclass and our file_lockable() functions which mask the deviation.
If there is another way to put a dbServer subclass on top of a filesystem layer like ours I'd be happy to learn about it.
TiA Stefan
The reason why I need the dirty trick (I'm telling this because maybe there is a better approach):
We need to stick to DBFs due to a reporting software which we mußte maintain for some more years. We as also need to protect the database against theft or malware Wunder a user account. So we strip the users (clients) of all rights to the directory and redirect all file operations though some server side stored procedures. Since the dbServer class has several internal uses of file functions we use the dirty trick to inject our own Filespec subclass and our file_lockable() functions which mask the deviation.
If there is another way to put a dbServer subclass on top of a filesystem layer like ours I'd be happy to learn about it.
TiA Stefan
Sendclass substitute
Hi Stefan,
Hard to tell without seeing exactly what you are doing in your own constructor replacement, but for using a custom FileSpec, I think you could just pass it as a first argument to the standard DBServer constructor. But I'm sure you're doing more complicated things than that in the code.
.
Hard to tell without seeing exactly what you are doing in your own constructor replacement, but for using a custom FileSpec, I think you could just pass it as a first argument to the standard DBServer constructor. But I'm sure you're doing more complicated things than that in the code.
.
Chris Pyrgas
XSharp Development Team
chris(at)xsharp.eu
XSharp Development Team
chris(at)xsharp.eu
-
- Posts: 71
- Joined: Thu Jul 15, 2021 10:46 am
- Location: Germany
Sendclass substitute
Hi Chris,
in VO passing a custoim FileSpec didn't suffice to do the job since there were some aditional file()-calls within the SDK dbServer code. In XSharp I'm actually trying to pass the custom FileSpec as a first parameter, which of course compiles because at a first glance I didn't find any direct file accesses beyond FileSpec in the SDK code. If this simple approach tests fine I'll be more than happy to drop one of my "dirty tricks"
in VO passing a custoim FileSpec didn't suffice to do the job since there were some aditional file()-calls within the SDK dbServer code. In XSharp I'm actually trying to pass the custom FileSpec as a first parameter, which of course compiles because at a first glance I didn't find any direct file accesses beyond FileSpec in the SDK code. If this simple approach tests fine I'll be more than happy to drop one of my "dirty tricks"