Try OpenEdge Now
skip to main content
GUI for .NET Programming
Using .NET data types in ABL : .NET boxing support : Manual boxing
 

Manual boxing

ABL provides a BOX function to manually convert an ABL primitive value or array to a particular .NET mapped data type or .NET array object type, and return the result as a .NET System.Object reference. ABL also provides an UNBOX function to manually unbox a .NET mapped data type or array object type from a System.Object or array object and return it as a matching ABL primitive or array type. This is the syntax for the BOX and UNBOX functions:

Syntax

BOX ( ABL-expression [ , AS-data-type-expression] )
UNBOX ( object-reference )
ABL-expression is the primitive value or array that you want to box as a .NET mapped data type or array object type. You can use AS-data-type-expression only for a primitive value or primitive array. This character expression indicates the .NET mapped data type or the element type of the primitive array that you want to box for ABL-expression. This character expression contains the AS data type keyword in Table 11 that matches the .NET type you want to specify. Without AS-data-type-expression, the function boxes ABL-expression to its default matching .NET mapped data type or array of mapped type elements. The object-reference is a reference to a System.Object or .NET array object from which you want to unbox the .NET mapped data type or array object type.
You can optionally use these functions appropriately where ever ABL does automatic boxing and unboxing (see Automatic boxing). However, in certain cases, you must use these functions to box or unbox an ABL data type.
You must use the BOX function to manually box an ABL value or array into a .NET System.Object or .NET array object:
*When you assign an ABL primitive or primitive array type to a System.Object and you want the ABL value or array boxed as a .NET mapped data type or .NET array of mapped type elements other than the default match—for example, in order to assign an ABL INTEGER or INTEGER array to the target .NET data element as a System.Byte or "System.Byte[]".
*When you pass an ABL primitive array type to a System.Object INPUT parameter of a .NET method or constructor and you want to box the ABL array as a .NET array of mapped type elements other than the default match.
*When you pass an ABL primitive or array type to a System.Object or .NET array object INPUT parameter of any ABL routine (method, constructor, procedure, or user-defined function). You must invoke the BOX function for the ABL data type directly on the INPUT parameter, casting as necessary using the CAST function. The passing of ABL array to .NET array parameters represents an array mapping. For more information, see Accessing and using .NET arrays.
You must use the UNBOX function to manually unbox the ABL value or array from a .NET System.Object or .NET array object:
*When you use a System.Object in an ABL expression, such as a numeric or date expression.
*When you want to assign a System.Object to a compatible ABL array.
*When you pass a System.Object or .NET array object to a compatible ABL primitive or array INPUT parameter of any ABL routine (method, constructor, procedure, or user-defined function). You must invoke the UNBOX function for the System.Object or array object directly on the ABL INPUT parameter. The passing of .NET array to ABL array parameters represents an array mapping. For more information, see Accessing and using .NET arrays.
As an example of needing the BOX function, the following code fragment raises a run-time error on an assignment statement (rcList:Item[0] = 5) because the .NET indexed property to which an ABL INTEGER is being assigned is a System.Object that requires the data type, System.Byte, which is different from the default match for an ABL INTEGER (System.Int32). In this case, the property represents the elements of a .NET array object defined to hold System.Byte element values. However, .NET does not allow you to store the System.Int32 to which ABL automatically converts the value. So, .NET raises an error when ABL attempts to complete the assignment, as shown:
USING Progress.Util.* FROM ASSEMBLY.

DEFINE VARIABLE rcArray AS CLASS System.Array             NO-UNDO.
DEFINE VARIABLE rcList  AS CLASS System.Collections.IList NO-UNDO.
DEFINE VARIABLE iValue  AS INTEGER                        NO-UNDO.

ASSIGN
  rcArray        = System.Array:CreateInstance
                     (TypeHelper:GetType("System.Byte"), 1)
  rcList         = rcArray

  /* This line raises a run-time error that the source type (System.Int32)
     cannot narrow to the target type (System.Byte) */
  rcList:Item[0] = 5 /* Run-time ERROR */
  iValue         = rcList:Item[0].

MESSAGE "rcList:Item[0] = " iValue VIEW-AS ALERT-BOX.
Note: For more information on using .NET array objects (based on the System.Array class), see Accessing and using .NET arrays. The Item property is actually an explicit member of an interface (System.Collections.IList) that System.Array implements. For more information on explicit interface members, see Accessing members of .NET interfaces.
However, the following code fragment runs to completion using the BOX function to convert the INTEGER value to a System.Byte before boxing the value in the System.Object array element:
USING Progress.Util.* FROM ASSEMBLY.

DEFINE VARIABLE rcArray AS CLASS System.Array             NO-UNDO.
DEFINE VARIABLE rcList  AS CLASS System.Collections.IList NO-UNDO.
DEFINE VARIABLE iValue  AS INTEGER                        NO-UNDO.

ASSIGN
  rcArray        = System.Array:CreateInstance
                    (TypeHelper:GetType("System.Byte"), 1)
  rcList         = rcArray
  rcList:Item[0] = BOX(5, "UNSIGNED-BYTE")
  iValue         = rcList:Item[0].

MESSAGE "rcList:Item[0] = " iValue VIEW-AS ALERT-BOX.
The second parameter of the BOX function specifies an AS data type that corresponds to the .NET mapped data type into which you want to box the value (5) specified by the first parameter. In this case, the AS data type, UNSIGNED-BYTE (specified for BOX as a character string) corresponds to a .NET System.Byte. For more information on the AS data types that you can use to specify the explicit .NET conversion for each ABL primitive type passed to the BOX function, see Explicit data type mappings.
As an example of needing the UNBOX function, the following code fragment raises a compile-time error on the MESSAGE statement because it is attempting to use a .NET System.Object directly in expressions:
USING Progress.Util.* FROM ASSEMBLY.

DEFINE VARIABLE rcArray AS CLASS System.Array             NO-UNDO.
DEFINE VARIABLE rcList  AS CLASS System.Collections.IList NO-UNDO.

ASSIGN
  rcArray        = System.Array:CreateInstance
                     (TypeHelper:GetType("System.Int32"), 1)
  rcList         = rcArray
  rcList:Item[0] = 10. /* Automatic boxing */

MESSAGE
  "A circle with a diameter of "             /*Compile-time Error*/
  rcList:Item[0] " has an area = "
  System.Math:PI * EXP(rcList:Item[0] / 2 , 2)
  VIEW-AS ALERT-BOX.
In this case, the first element of a System.Int32[] array is set to an ABL INTEGER value (10) through the default indexed property (Item) of the System.Collections.IList interface that the .NET array object implements. (Note that the assignment performs automatic boxing to assign the value to the System.Object property as a System.Int32.) When the value is accessed from the indexed property (rcList:Item[0]) directly in an expression, ABL does not automatically recognize that it needs to unbox a System.Object value in order for it to work in an expression. Thus, this code generates an incompatible data type error at compile time.
By using the UNBOX function, you tell ABL that the specified .NET expression (rcList:Item[0]) represents a System.Object that it needs to unbox and convert to an ABL data type, as in the following update to the same code fragment:
USING Progress.Util.* FROM ASSEMBLY.

DEFINE VARIABLE rcArray AS CLASS System.Array             NO-UNDO.
DEFINE VARIABLE rcList  AS CLASS System.Collections.IList NO-UNDO.

ASSIGN
  rcArray        = System.Array:CreateInstance
                     (TypeHelper:GetType("System.Int32"), 1)
  rcList         = rcArray
  rcList:Item[0] = 10. /* Automatic boxing */

MESSAGE
  "A circle with a diamter of "
  UNBOX(rcList:Item[0]) " has an area = "
  System.Math:PI * EXP(UNBOX(rcList:Item[0]) / 2 , 2)
  VIEW-AS ALERT-BOX.
This code then compiles and runs to completion, displaying a message with the area of the circle represented by the diameter stored in the .NET array. For more examples using the BOX and UNBOX functions, see the reference entry for each ABL function in OpenEdge Development: ABL Reference.