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
- stefan.ungemach
- Posts: 81
- 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![Smile :)](https://dt9qzg9h465rt.cloudfront.net/phpBB3/images/smilies/icon_e_smile.gif)
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
![Smile :)](https://dt9qzg9h465rt.cloudfront.net/phpBB3/images/smilies/icon_e_smile.gif)
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
- stefan.ungemach
- Posts: 81
- 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
- stefan.ungemach
- Posts: 81
- 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"![Wink ;)](https://dt9qzg9h465rt.cloudfront.net/phpBB3/images/smilies/icon_e_wink.gif)
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"
![Wink ;)](https://dt9qzg9h465rt.cloudfront.net/phpBB3/images/smilies/icon_e_wink.gif)
Re: Sendclass substitute
Hi Chris,Chris wrote: Tue Feb 21, 2023 1:22 pm 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
Please forgive my ignorance but I am struggling a bit with "ctor" and "Invoke". Neither of these is in the index of the X# help and because I am also looking for an alternative for the missing SendClass() function I would like to learn more about the solution that is in this thread, involving "ctor" and "Invoke". Where can I find an explanation of these concepts?
Kees.
Re: Sendclass substitute
Hi Kees,
"ctor" is just a local variable name defined by Stefan in his code. And Invoke() is a method of the object type that this variable holds (ConstructorInfo).
The code posted by Stefan is specif to a very specific need of his, not a general alternative for SendClass(), and it's possibly not needed at all, if the alternative solution discussed earlier worked as well.
In what case does your VO code need to call SendClass()? It's very likely that it's possible to also use a simple alternative for it.
"ctor" is just a local variable name defined by Stefan in his code. And Invoke() is a method of the object type that this variable holds (ConstructorInfo).
The code posted by Stefan is specif to a very specific need of his, not a general alternative for SendClass(), and it's possibly not needed at all, if the alternative solution discussed earlier worked as well.
In what case does your VO code need to call SendClass()? It's very likely that it's possible to also use a simple alternative for it.
Chris Pyrgas
XSharp Development Team
chris(at)xsharp.eu
XSharp Development Team
chris(at)xsharp.eu
Re: Sendclass substitute
Hi Chris,Chris wrote: Mon Feb 03, 2025 1:55 pm Hi Kees,
"ctor" is just a local variable name defined by Stefan in his code. And Invoke() is a method of the object type that this variable holds (ConstructorInfo).
The code posted by Stefan is specif to a very specific need of his, not a general alternative for SendClass(), and it's possibly not needed at all, if the alternative solution discussed earlier worked as well.
In what case does your VO code need to call SendClass()? It's very likely that it's possible to also use a simple alternative for it.
Thank you for your reply. I thought that I had seen "ctor" and "Invoke" used elsewhere by other people as well, so I thought it was some undocumented feature. Thanks for explaining. The SendClass() is used in the "inheritance madness" in the application I am working on. Imagine 6 classes, all inheriting from each other so for example class F inherits from class E, E inherits from D, D inherits from C, C inherits from B and B inherits from A. All 6 classes have a method called OKButton(). At some point we are in F:OKButton(). This method then wants to execute B:OKButton() and this was done with the SendClass() function. As an alternative I created a method with a unique name in class B, go to that method and from there do a SELF:OKButton() thinking that it would go to the nearest OKButton() method but it does not. It just executes F:OKButton() again, causing a stack overflow.
Kees.
Re: Sendclass substitute
Hi Kees,
You can do something similar to what you already did:
- Create a METHOD OKButton_class_B() CLASS B (or with a different name) and put there all the code that is currently in included in OKButton() of this class B
- In OKButton() of this class put only a simple call to this new OKButton_class_B() method.
- When you need to call the OKButton() method of that level in a subclass (from F as you mentioned), simply call SELF:OKButton_class_B(), instead of using SendClass().
That should do the trick.
You can do something similar to what you already did:
- Create a METHOD OKButton_class_B() CLASS B (or with a different name) and put there all the code that is currently in included in OKButton() of this class B
- In OKButton() of this class put only a simple call to this new OKButton_class_B() method.
- When you need to call the OKButton() method of that level in a subclass (from F as you mentioned), simply call SELF:OKButton_class_B(), instead of using SendClass().
That should do the trick.
Chris Pyrgas
XSharp Development Team
chris(at)xsharp.eu
XSharp Development Team
chris(at)xsharp.eu