Hi,
I want to loop all properties defined in a class from a method in that same class.
I also want that all the properties are private (so they can not be assigned a value from outside that class).
I found a way to loop those properties but my problem is that the properties needs to be public (and i do not want that).
Is there some way to loop all properties from a class (private/public)?
I tried with the following class:
/*------------------------------------------------------------------------
File : GetPropertiesFromClass
Purpose :
Syntax :
Description :
Author(s) : didier.d
Created : Fri Sep 20 14:54:04 CEST 2019
Notes :
----------------------------------------------------------------------*/
using Progress.Lang.*.
block-level on error undo, throw.
class GetPropertiesFromClass:
define private property pPrivateProperty as character no-undo
get.
set.
define public property pPublicProperty as character no-undo
get.
set.
define protected property pProtectedProperty as character no-undo
get.
set.
/*------------------------------------------------------------------------------
Purpose:
Notes:
------------------------------------------------------------------------------*/
constructor public GetPropertiesFromClass ( ):
SUPER ().
this-object:mLoopProperties().
end constructor.
/*------------------------------------------------------------------------------
Purpose:
Notes:
------------------------------------------------------------------------------*/
method private void mLoopProperties( ):
define variable oProperty as Progress.Reflect.Property no-undo extent.
define variable i as integer no-undo.
assign oProperty = cast(this-object, Progress.Lang.Object):Getclass():GetProperties().
do i = 1 to extent(oProperty):
message oProperty[i] skip oProperty[i]:name skip oProperty[i]:datatype
view-as alert-box info buttons ok.
end.
return.
end method.
end class.
Regards
Didier
[mention:60b86d3c60124129adc86cb35b53ac5b:e9ed411860ed4f2ba0265705b8793d05] , did you add "OR Flags:Instance OR Flags:DeclaredOnly" as well? These are needed to get the required properties.
This just gives you a Properties array. If you want to get the actual values, you need to loop over all items and call Get(Object) on them, where Object is your actual object instance of which you want to get the property values...
You are not calling the GetProperties() from "this class". You're calling it on the "Class" of the current instance of your object, which is not your object itself, hence you have no access to its private properties. Using reflection you can get them, if you provide the correct parameters to GetProperties().
GetProperties default to only public instance properties when not passing flags!
Hi Didier,
you can make the properties public with private setters.
/Torben
- You can make a property read-only by making the setter private.
- You can pass Flags to the GetProperties method to only get what you want, e.g GetClass():GetProperties(Flags:Private OR Flags:Instance OR Flags:DeclaredOnly).
Hi,
Yes, damn forgot about that :-(
But otherwise, is this not possible
I find that strange because I call the method from this class so then the private properties should be available. or I'm a wrong here?
@Lieven: yes I know, I already tried with the private-flag but that also did not work
[mention:60b86d3c60124129adc86cb35b53ac5b:e9ed411860ed4f2ba0265705b8793d05] , did you add "OR Flags:Instance OR Flags:DeclaredOnly" as well? These are needed to get the required properties.
This just gives you a Properties array. If you want to get the actual values, you need to loop over all items and call Get(Object) on them, where Object is your actual object instance of which you want to get the property values...
You are not calling the GetProperties() from "this class". You're calling it on the "Class" of the current instance of your object, which is not your object itself, hence you have no access to its private properties. Using reflection you can get them, if you provide the correct parameters to GetProperties().
It appears you can't get the value of a private property using reflection, which is a bit strange (it can be done in other languages so why was this designed this way?)
USING Progress.Reflect.Flags FROM PROPATH.
USING Progress.Reflect.Property FROM PROPATH.
BLOCK-LEVEL ON ERROR UNDO, THROW.
CLASS TestReflection.TestReflection:
DEFINE PRIVATE PROPERTY PrivateProperty AS CHARACTER NO-UNDO INITIAL "Hello!"
GET.
SET.
METHOD PUBLIC VOID PrintPrivates():
DEFINE VARIABLE Properties AS Property NO-UNDO EXTENT.
Properties = GetClass():GetProperties(Flags:Private OR Flags:Instance OR Flags:DeclaredOnly).
MESSAGE Properties[1]:Name SKIP
Properties[1]:Get(THIS-OBJECT)
VIEW-AS ALERT-BOX.
END METHOD.
END CLASS.
GetProperties default to only public instance properties when not passing flags!
Hi Lieven,
I do not completely understand what you wrote but I will test a bit
Thanks
It appears you can't get the value of a private property through reflection, which is a weird design choice, since you can with Java or C#...
USING Progress.Reflect.Flags FROM PROPATH.
USING Progress.Reflect.Property FROM PROPATH.
BLOCK-LEVEL ON ERROR UNDO, THROW.
CLASS TestReflection.TestReflection:
DEFINE PRIVATE PROPERTY PrivateProperty AS CHARACTER NO-UNDO INITIAL "Hello!"
GET.
SET.
METHOD PUBLIC VOID PrintPrivates():
DEFINE VARIABLE Properties AS Property NO-UNDO EXTENT.
Properties = GetClass():GetProperties(Flags:Private OR Flags:Instance OR Flags:DeclaredOnly).
MESSAGE Properties[1]:Name SKIP
Properties[1]:Get(THIS-OBJECT)
VIEW-AS ALERT-BOX.
END METHOD.
END CLASS.
Thanks guys
For some reason my answers don't get posted, so this is another (3rd) attempt...
It appears the value of private properties can't be read using reflection, which is a strange design choice, since this is possible in Java or c#...
Example code:
USING Progress.Reflect.Flags FROM PROPATH.
USING Progress.Reflect.Property FROM PROPATH.
BLOCK-LEVEL ON ERROR UNDO, THROW.
CLASS TestReflection.TestReflection:
DEFINE PRIVATE PROPERTY PrivateProperty AS CHARACTER NO-UNDO INITIAL "Hello!"
GET.
SET.
METHOD PUBLIC VOID PrintPrivates():
DEFINE VARIABLE Properties AS Property NO-UNDO EXTENT.
Properties = GetClass():GetProperties(Flags:Private OR Flags:Instance OR Flags:DeclaredOnly).
MESSAGE Properties[1]:Name SKIP
Properties[1]:Get(THIS-OBJECT)
VIEW-AS ALERT-BOX.
END METHOD.
END CLASS.
Hi Lieven,
I agree it was the wrong choice to not allow private access to reflection. We hope to add that capability soon.
Thanks
-Shelley
Flags:Private OR Flags:Instance OR Flags:DeclaredOnly - Is this OR in this case a bitwise operation? Is this a special case implementation, or we can start foregoing the use of the Progress helper class for bitwise operation?
Thanks,
This is a bitwise operation.
You no longer need EnumHelper or the likes to do this kind of things since the more recent OE 11 versions...
But you can use dynamic property:
DYNAMIC-PROPERTY(THIS-OBJECT, Properties[1]:Name)
@[mention:c4bc59ca912947f48646dd9e9ff4acd5:e9ed411860ed4f2ba0265705b8793d05] DYNAMIC-PROPERTY will only work from within the object. Trying to access a private property through DYNAMIC-PROPERTY from outside the class will give you error 13833:
Property PrivateProperty has a PRIVATE GET accessor so can be read only from within the class where it's defined. (13833)
Lieven: I agree with what Shelley said. However, in your TestReflection example, you are trying to access a private data member of the class that owns that variable. This should be allowed now. i.e., I believe this is a bug. Otherwise, what would be the point in providing the Flags:Private enum if it will never allow you to get the property anyway! If you can't access it from its own class, then where would you be able to access it from? Please log a bug so we can look into this.
As noted by Shelley and Laura the AVM’s reflection infrastructure can be enhanced to support accessing non-public data members via reflection. From a historical perspective, when this feature was designed and built during the 11.6.0 time-frame we reviewed .NET’s and Java’s reflection capabilities. These two frameworks approach this facility differently. Via reflection, .NET provides functionality to access non-public data members and Java by default prohibits this access. There are facilities within Java to mimic the .NET functionality.
The approach we identified at the time was to introduce a more restrictive solution in 11.6.0 (access to Public data member values only) with the possibility of relaxing this restriction in a future release.
One area of discussion was to better understand the use case for accessing non-public data members via reflection. Can the Community comment on how they plan on using such a facility?
Hi [mention:644b32c9259141d2b1b21a2813ab7487:e9ed411860ed4f2ba0265705b8793d05] I personally never had to access ABL private members through reflection (yet), but that's probably because we don't have 3rd party ABL without access to the source (and ability to adapt it). Accessing these through reflection would seem like a code smell to me in that case.
But I did have to use reflection on occasion to get a .NET private value (stackoverflow.com/.../how-to-get-the-real-value-of-the-visible-property).