Try OpenEdge Now
skip to main content
Object-oriented Programming
Programming with Class-based Objects : Instantiating and managing class-based objects : Calling class-based methods : Dynamically invoking a method at run time
 
Dynamically invoking a method at run time
Traditional class-based programming in ABL assumes that classes and their members are strongly typed at compile time. The AVM verifies the type and validity of class-based objects and class-based object references when the class is compiled.
There might be points in your application where the name of the class and the parameters to be passed to it are only known at run time. You can use either the built-in DYNAMIC-INVOKE function or the Invoke( ) method of the Progress.Lang.Class class to dynamically invoke a class-based method at run time.
DYNAMIC-INVOKE is a built-in ABL function that invokes a class-based method whose name is specified by a run-time expression, but whose parameters are defined at compile time. DYNAMIC-INVOKE takes an instance of an object, and an expression for the method name to be invoked, followed by a fixed list of compile-time, bound parameters. Consistent with the functionality provided by the DYNAMIC-NEW statement, DYNAMIC-INVOKE fully supports method overloading.
The Invoke( ) method of the Progress.Lang.Class class provides similar functionality to DYNAMIC-INVOKE. The advantage to the latter is that it has a fixed, compile-time parameter list and does not require the creation of a Progress.Lang.ParameterList object at run time. For more information about the Progress.Lang.ParameterList class, see OpenEdge Development: ABL Reference and Using the Progress.Lang.ParameterList class.
Note: DYNAMIC-INVOKE does not operate on built-in classes. This is analogous to the DYNAMIC-FUNCTION function and the DYNAMIC-NEW statement, which also do not operate on built-in classes.
DYNAMIC-INVOKE can invoke either void or non-void, class-based methods. When invoking a non-void method, the caller can capture the returned value by assigning DYNAMIC-INVOKE to an expression of an appropriate type. This assignment operation follows the existing rules for assigning the return value of a method to an expression. If the caller chooses, the program does not need to capture the returned value. In contrast, when invoking a void method, the caller must not attempt to assign the method return value to an expression—doing so will cause the AVM to generate a run-time error. When invoking a void method with DYNAMIC-INVOKE, it is only permissible to do so with code that does not expect a return value.
This is the syntax for the DYNAMIC-INVOKE function:

Syntax

[data-element = ] DYNAMIC-INVOKE( {class-type-name|object-reference }
  , method-name[ , parameter[ , parameter] ... ] )
The DYNAMIC-INVOKE function accepts either a class type name or an object reference. A class type name is specified when the method to be invoked is static. An object reference is used to identify the object on which the method invocation is to occur.
In this example, the FooDec( ) method in the class instance referenced by rObj expects a DECIMAL value. With data type widening support, an ABL DECIMAL, INTEGER, or INT64 value can be passed to this method:
DEFINE VARIABLE dValue  AS DECIMAL NO-UNDO.
DEFINE VARIABLE iVal32  AS INTEGER NO-UNDO.
DEFINE VARIABLE iVal64  AS INT64   NO-UNDO.
DEFINE VARIABLE iReturn AS INTEGER NO-UNDO.

/* Invoking non-overloaded FooDec (INPUT AS DECIMAL) */
iReturn = DYNAMIC-INVOKE(rObj, "FooDec", INPUT 5).
iReturn = DYNAMIC-INVOKE(rObj, "FooDec", INPUT dValue).
iReturn = DYNAMIC-INVOKE(rObj, "FooDec", INPUT iVal32).
iReturn = DYNAMIC-INVOKE(rObj, "FooDec", INPUT iVal64).
You can use the Invoke( ) method of the Progress.Lang.Class class to invoke a method when the method name and any parameters are only known at run time. This method returns an optional data element which is assigned the return value from the invoked, non-void method. This data element can be any data type. The AVM checks the return value at run time for data type compatibility with what is actually returned by the method.
The Invoke( ) method is one of several reflection methods of the Progress.Lang.Class class that provide type information about a class or interface at run time. For more information about the reflection capabilities of the Progress.Lang.Class class, see Usingthe Progress.Lang.Class class.
The Invoke( ) method has four overloaded constructors. You can use the first version to invoke a class-based static or instance method that does not take any parameters. This is the syntax for using this version of the Invoke( ) method:
[data-element = ]class-reference:Invoke ( object-reference , method-name )
You can use the second overloaded version to invoke a class-based method that takes zero or more parameters. The parameter list is passed as a Progress.Lang.ParameterList object. This is the syntax for using this version of the Invoke( ) method:

[data-element = ]class-reference:Invoke
  ( object-reference , method-name , parameterlist-object )
You can use the third overloaded version to invoke a static method that does not take any parameters (see the ). This is the syntax for using this version of the Invoke( ) method:
[ data-element = ]class-reference:Invoke ( method-name )
You can use the fourth overloaded version to invoke a static method that takes zero or more parameters (see the ). The parameter list is passed as a Progress.Lang.ParameterList object. This is the syntax for using this version of the Invoke( ) method:
[data-element = ]class-reference:Invoke
  ( method-name , parameterlist-object )
Element descriptions for these syntax diagrams follow:
data-element
An optional ABL data element which is assigned the return value from the invoked, non-void method. This data element can be any ABL data type that is compatible with the return value data type.
class-reference
An object reference for the Progress.Lang.Class instance containing the type information.
object-reference
A reference to the object that contains the method you want to invoke, and whose type is compatible with the class-reference object. When invoking a static method, the Unknown value (?) is passed for this parameter.
method-name
A CHARACTER expression that evaluates at run time to the name of the method to be invoked.
parameterlist-object
An instance of the Progress.Lang.ParameterList class. Since a Progress.Lang.ParameterList object can be built with zero or more parameters, this version of the Invoke( ) method can be used to invoke any method, even if it does not take any arguments. See Using the Progress.Lang.ParameterList class for a list of common public properties and methods of the Progress.Lang.ParameterList class.
Note: The DYNAMIC-INVOKE function and the Invoke( ) method of the Progress.Lang.Class class provide similar functionality. They differ in that the former requires a fixed, compile-time parameter list, while the latter requires a instantiated and populated run-time Progress.Lang.ParameterList object.
The following example shows the Invoke( ) method overloading to call an instance method without parameters. It gets the MyClass class type using the GetClass( ) method of the Progress.Lang.Class class. An instance of this class type is created using the New( ) method of Progress.Lang.Class and casting the Progress.Lang.Object result to a MyClass object reference, which is then assigned to rObj. Invoke( ) then calls the MyDynMethod( ) method, specified as a character string, in rObj without parameters:
DEFINE VARIABLE rClass AS CLASS Progress.Lang.Class NO-UNDO.
DEFINE VARIABLE rObj   AS CLASS MyClass             NO-UNDO.

rClass = Progress.Lang.Class:GetClass("MyClass").
rObj   = CAST(rClass:New( ), MyClass).

rClass:Invoke(rObj, "MyDynMethod").
Note: For information on using the New( ) method with casting, see Creatinga class instance.
The following example shows the Invoke( ) method overloading to call an instance method with parameters. It creates an instance of MyClass class assigned to rObj. The rParamList object, an instance of the Progress.Lang.ParameterList class, holds the parameter data. The parameter data is passed to the MyDynMethod( ) method when it is invoked in the rObj object:
DEFINE VARIABLE rClass     AS Progress.Lang.Class         NO-UNDO.
DEFINE VARIABLE rObj       AS MyClass                     NO-UNDO.
DEFINE VARIABLE rParamList AS Progress.Lang.ParameterList NO-UNDO.

rClass     = Progress.Lang.Class:GetClass("MyClass").
rObj       = CAST(rClass:New( ), MyClass).

ASSIGN
  rParamList = NEW Progress.Lang.ParameterList(1)
  rParamList:NumParameters = 1.

rParamList:SetParameter(1, "INTEGER", "INPUT", 5).
rClass:Invoke(rObj, "MyDynMethod", rParamList).
The following example shows the Invoke( ) method overloading to call a static method without parameters. In this case, Invoke( ) is called directly on the instance of Progress.Lang.Class that is returned from GetClass( ) for the MyClass type, which allows it to invoke the specified static MyStaticMethod( ) method on that type:
DEFINE VARIABLE rClass AS CLASS Progress.Lang.Class NO-UNDO.

rClass = Progress.Lang.Class:GetClass("MyClass").

rClass:Invoke("MyStaticMethod").
The following example shows the Invoke( ) method overloading to call a static method with parameters. Again, Invoke( ) is called on a Progress.Lang.Class instance representing the MyClass type, which allows it to invoke the static MyStaticMethod( ) method, this time, with the parameter list specified by rParamList:
DEFINE VARIABLE rClass     AS CLASS Progress.Lang.Class         NO-UNDO.
DEFINE VARIABLE rParamList AS CLASS Progress.Lang.ParameterList NO-UNDO.
ASSIGN
  rClass     = Progress.Lang.Class:GetClass("MyClass")
  rParamList = NEW Progress.Lang.ParameterList(1)
  rParamList:NumParameters = 1.

rParamList:SetParameter(1, "INTEGER", "INPUT", 5).
rClass:Invoke("MyStaticMethod", rParamList).