Loop properties from a class from a method in that class - Forum - OpenEdge Development - Progress Community

Loop properties from a class from a method in that class

 Forum

Loop properties from a class from a method in that class

This question is answered

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

Verified Answer
  • , 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!

    knowledgebase.progress.com/.../

All Replies
  • 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

  • , 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!

    knowledgebase.progress.com/.../

  • 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)

  • @ 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)