Try OpenEdge Now
skip to main content
GUI for .NET Programming
Accessing and Managing .NET Classes from ABL : Defining ABL-extended .NET objects : Deriving .NET classes in ABL : Overriding .NET methods
 
Overriding .NET methods
In ABL, you can override any ABL method inherited by an ABL class using the OVERRIDE option of the METHOD statement. You use a similar ABL mechanism to override a .NET method. However in .NET, you can only override inherited methods that are defined to be overrideable. Similarly in ABL, you can only override an inherited .NET method that has been defined (in C#) as virtual or abstract.
Note: In .NET documentation, some methods that you can override might be declared with the C# override keyword instead of the virtual or abstract keyword. This simply means that the .NET method is itself an override of a virtual or abstract super class method higher up in the class hierarchy.
In addition, the method must be defined with one of the following .NET access level modifiers, which correspond to access modes in ABL:
*public
*protected
*protected internal
The overriding ABL method must have an ABL access mode that is equivalent to or less restrictive than the access level of the overridden .NET method. So, the ABL method access mode can correspond to the .NET access level modifier as follows:
*You can only override a public .NET method with a PUBLIC ABL method.
*You can override a protected or a protected internal .NET method with either a PROTECTED or a PUBLIC ABL method.
You cannot override a .NET method defined as any of the following:
*static
*sealed (FINAL)
*DestroyHandle( ) method
*Dispose( ) method
*Finalize( ) method
*GetHashCode( ) method
The listed methods are all defined as overrideable in .NET. However, ABL defines these methods as FINAL for an ABL session.
Caution: Although you can override the WndProc( ) method, doing so can be risky. The method will be called for every event, like WM_MOUSEMOVE and WM_PAINT, so it can be called thousands of times for a single form, causing performance issues. It can also be called at unexpected times and cause unexpected behavior. Overriding WndProc( ) when using ABL embedded windows with .NET forms can be especially problematic. For more information, see Using .NET Forms with ABL Windows.
As with overriding an inherited ABL method, the name, return type, and the signature of the overriding ABL method must match the overridden .NET method with respect to the number of parameters, the corresponding parameter modes, and the corresponding data types. For information on identifying .NET parameter modes, see Specifying .NET constructor and method parameters.
You can also define the overriding ABL method with or without the ABSTRACT option, whether or not the overridden .NET method is abstract. Note that to use the ABSTRACT option the inheriting ABL class must also be abstract. However, as for an inherited ABL abstract method, the first non-abstract ABL subclass that inherits a .NET abstract method must implement the inherited .NET abstract method unless an abstract ABL subclass implements the method higher in the class hierarchy.
As described previously, when you call an overloaded .NET method, you must explicitly indicate the .NET parameter data types that correspond to the particular method overloading you want to call (see Passing ABL data types to .NET constructor and method parameters). When overriding a .NET method, you must follow similar rules for how to define the parameters and return type in ABL based on how the parameters are defined in .NET. If the data type of a method element is a .NET mapped data type, and this mapped type is the default match for a given ABL primitive data type, you must specify the corresponding ABL primitive data type. However, if a .NET mapped type is not the default match of any ABL primitive data type, you must specify the data type using an AS data type keyword that represents the required .NET mapped type. See Table 11 for information on both the .NET mapped types you must specify as default mappings and those you must specify using a corresponding AS data type.
For example, this is the C# declaration for a .NET method you can override:
/* C# overridable method declaration */
public virtual double Calculate( byte arg )
This is the ABL method prototype required to override this .NET method:
/* ABL overriding method */
METHOD PUBLIC OVERRIDE DOUBLE Calculate(piArg AS UNSIGNED-BYTE):
  ...
END.
Note that at run time, ABL interprets these parameter and return values as the corresponding ABL data types that map to their .NET equivalents. So, for example, ABL interprets piArg as an INTEGER and the return type as a DECIMAL value. So, to call this method in ABL, you might use the following code, where derivedInstance is a reference to an ABL class instance that defines the ABL override of Calculate( ):
/* ABL call to overriding method */
DEFINE VARIABLE dVar AS DECIMAL NO-UNDO.
DEFINE VARIABLE iVar AS INTEGER NO-UNDO.
...
ASSIGN
  iVar = 42  dVar = derivedInstance:Calculate( iVar ).
...
To override .NET methods that pass and return .NET object types, including .NET array types, you must define the parameters and return types using the equivalent .NET object types.
For example, this is the declaration for a .NET method you can override:
/* C# overridable method declaration */
public virtual System.IAsyncResult BeginReceiveFrom (
  byte[] buffer,
  int offset,
  int size,
  System.Net.Sockets.SocketFlags socketFlags,
  ref System.Net.EndPoint remoteEP,
  System.AsyncCallback callback,
  System.Object state
)
You might override this BeginReceiveFrom( ) method in ABL as follows:
/* ABL overriding method */
METHOD PUBLIC OVERRIDE System.IAsyncResult BeginReceiveFrom
 (INPUT  prByteBuffer     AS "System.Byte[]",
  INPUT  piOffset         AS INTEGER,
  INPUT  piSize           AS INTEGER,
  INPUT  prSocketFlags    AS System.Net.Sockets.SocketFlags,
  INPUT-OUTPUT prRemoteEP AS System.Net.EndPoint,
  INPUT  prCallback       AS System.AsyncCallback,
  INPUT  prState          AS System.Object):
  ...
END.
Note: The Microsoft .NET Framework provides a BeginReceiveFrom( ) method with a similar prototype that is not declared as virtual. Its prototype is borrowed and modified here in order to illustrate overriding.
Note that most of the .NET object type names for the BeginReceiveFrom( ) method override transfer exactly. However, the C# primitive array type, byte[], maps to the .NET array object type with the type name, "System.Byte[]". You also cannot specify this .NET array type in ABL using the corresponding AS data type, such as in this case UNSIGNED-BYTE EXTENT. The C# primitive type, int, maps to the .NET System.Int32. However, because the default match for the ABL primitive type, INTEGER, is System.Int32, you simply use INTEGER to define the parameters with that .NET type. Finally, the .NET ref directive declares a parameter access level that corresponds to the ABL access mode, INPUT-OUTPUT. (In this example, the remaining parameter definitions also have the optional INPUT access mode specified for readability.)
The following table summarizes the rules for defining each .NET method parameter and return type for an ABL method that overrides a .NET method.
Table 2. Defining parameters and return types to override .NET methods1
To define this .NET element . . .
Follow this rule . . .
.NET mapped data type
Use either the default-matched ABL data type or the AS data type that maps to the corresponding .NET type, as specified in Table 11.
.NET object type that is not mapped
Use the corresponding .NET object type. For .NET arrays, you cannot use the ABL EXTENT option—you must specify the equivalent .NET array object type surrounded in quotes (for example, use "System.Byte[]" or "System.Drawing.Point[]", not UNSIGNED-BYTE EXTENT or System.Drawing.Point EXTENT). However, if the corresponding .NET array is specified as a System.Array object, you must also use System.Array.
.NET parameter mode
Use the corresponding ABL parameter mode specified in Table 1.
1 - You apply these same rules to define properties and the parameters and return types of methods that you implement in a .NET interface. For more information, see Implementing .NET interfaces in ABL.