Try OpenEdge Now
skip to main content
GUI for .NET Programming
Accessing and Managing .NET Classes from ABL : Referencing and instantiating .NET classes : Referencing .NET class and interface types : Referencing .NET generic types
 
Referencing .NET generic types
.NET supports a concept of generic (or parameterized) types. A .NET generic type is any .NET class or interface type that uses placeholders for data type names in order to define one or more members or local variables as part of the generic class or interface definition. You determine the actual data types (primitive or object types) for these placeholders by how you reference the generic type name of the class or interface, which includes these placeholders as type parameters. Wherever you reference the generic type name, you substitute each type parameter in the name with an actual data type name. Thus, one generic class actually has multiple implementations based on the possible sets of substitution data types that you can provide for the type parameters in the generic class name. ABL supports references to .NET generic type names using this syntax:

Syntax

"namespace.object-name<Tparm[ , Tparm]...>"
The namespace is any required .NET namespace. The remaining construction specifies the .NET class or interface name for the generic type, where object-name is some identifier and Tparm is a type parameter, of which there can be more than one. The number of type parameters and the data types you can specify for each one depend on the generic type definition, which can include constraints for each type parameter. Note that ABL requires the surrounding quotes ("") to allow for the required angle brackets (<>) and any spaces in the type name. Note also that any number of spaces between type parameters, commas, and angle brackets are allowed but optional.
When you reference the generic type name for a given implementation of the type, you replace each defined Tparm in the name with an appropriate data type for the chosen implementation. This data type must explicitly identify the .NET type that the generic type requires for a given type parameter. Some .NET data types, which represent the primitive data types of any .NET language, map directly to ABL primitive data types, and are therefore referred to as .NET mapped data types. For example, a .NET System.Int32 maps to an ABL INTEGER. For these .NET mapped types, you must specify an ABL data type to identify the corresponding .NET data type. For information on how ABL primitive types map to .NET types, see Implicit data type mappings.
Note that some ABL primitive types correspond to more than one .NET mapped type. To specify a particular .NET mapped type, ABL provides extended type keywords called AS data types that identify a particular .NET mapped type. For example, to identify a .NET System.Int16, which implicitly maps to an ABL INTEGER, you must substitute the SHORT AS data type for the corresponding TParm in a generic type name. For more information on making explicit references to .NET mapped types, see Explicit data type mappings.
Note: Explicit references to .NET mapped types are required when working with several .NET features in ABL.
For references to .NET types other than .NET mapped types (all other object types), you can directly substitute the .NET object type name (for example, System.Drawing.Point or System.Windows.Forms.Button) for the corresponding TParm. You can even substitute another .NET generic type for a TParm, if the specified generic type supports it.
For example, .NET supports a generic stack object that you can use to create a stack of any .NET type. If you want to define an object reference to a .NET stack of System.Int16 objects, you can code the following ABL statement:
DEFINE VARIABLE rSHORTStack AS CLASS
  "System.Collections.Generic.Stack<SHORT>" NO-UNDO.
If you want to define an object reference to a .NET sorted list of key/value pairs (sorted by the key) consisting of System.String keys and System.Int16 values, you can code the following ABL statement:
DEFINE VARIABLE rKeyValueList AS CLASS
  "System.Collections.Generic.SortedList<CHARACTER, SHORT>" NO-UNDO.
Again, the class type names for these .NET generic types in ABL are "System.Collections.Generic.Stack<SHORT>" and "System.Collections.Generic.SortedList<CHARACTER, SHORT>" (respectively), and any reference to them in ABL must be surrounded in quotes to allow angle brackets and spaces in the name. Like any type name, you can also make unqualified references to them with an appropriate USING statement, for example, "SortedList<CHARACTER, SHORT>". Note that you can also use abbreviated ABL type names to specify the Tparm substitution types in the generic type name, for example, "SortedList<CHAR, SHORT>".
Referencing a generic type like this is referred to as constructing the type. Therefore, a reference to a .NET generic type that specifies a particular set of data types for its type parameters is referred to as a reference to its constructed type name. The .NET documentation specifies the type parameters for a given generic type using a generic type definition, which .NET also refers to as an open generic type, or simply an open type. The open type name for a generic type indicates the number and order of its type parameters. The complete definition for an open type also indicates possible substitute data types (constraints) for its type parameters and other information, such as any interfaces that a generic class type implements.
Note that ABL does not support open types and has no support for defining generic types of its own. ABL supports references only to constructed type names for a .NET generic type. You can thus reference a given generic type in ABL for all uses of .NET types, except to:
*Inherit from a .NET generic class
*Implement a .NET interface
*Instantiate a generic class using the DYNAMIC-NEW statement or the New( ) method.
*Cast an object reference to a .NET generic type using the DYNAMIC-CAST function
For example, you cannot specify a .NET generic type for the INHERIT or the IMPLEMENTS options of the ABL CLASS statement or dynamically cast to or instantiate a generic class. However, you can cast an object reference to a generic type using the CAST function and instantiate a generic class using the NEW function. For more information on inheriting .NET classes and implementing .NET interfaces, see Defining ABL-extended .NET objects.
You can also define both .NET and ABL arrays of generic types, and .NET generic types can take .NET array objects as constructed type parameters. For example:
DEFINE VARIABLE rSHORTListArrayObj AS /* .NET array of a generic type */
  CLASS "System.Collections.Generic.List<SHORT>[]" NO-UNDO.
DEFINE VARIABLE rSHORTListArrayExt AS /* ABL array of a generic type */
  CLASS "System.Collections.Generic.List<SHORT>" EXTENT 3 NO-UNDO.
                                         /* .NET array as a constructed */
DEFINE VARIABLE rButtonArrayList AS CLASS /* type parameter              */
  "System.Collections.Generic.List<System.Windows.Forms.Button[]>" NO-UNDO.
In the .NET Framework, the System.Collections.Generic namespace defines many of the generic types in the Framework. However, generic types are also defined in several other .NET object namespaces.
For more information on referencing and working with .NET generic types in ABL, including how to identify the available data types you can substitute for generic type parameters from open types listed in .NET documentation, see Working with .NET generic types.