Identify constraints on generic type parameters
- Last Updated: January 17, 2024
- 2 minute read
- OpenEdge
- Version 12.8
- Documentation
The complete formal declaration for a generic type can also include constraints on the .NET data types that are allowed for each of its type parameters. These constraints place limits on the choice of data types that you can substitute for a given type parameter.
If there are no constraints on a type
parameter, when a generic class is compiled, the .NET compiler
treats the type parameter as a System.Object. Therefore,
the methods and properties defined in the generic class can operate
on the type parameter only in ways that are allowed for a System.Object,
which is a very limited set of operations. By constraining the type
parameter, it increases the number of allowable operations to what
are supported by the constraining types and all types in their inheritance
hierarchy.
Therefore, generic classes and interfaces often have constraints on their type parameters. It gives the coder of the generic type more flexibility and some type checking even before the actual type is supplied in a constructed type name.
A given constraint might allow you to
substitute only .NET value types for a given type parameter, which would allow you to
substitute the ABL INTEGER or .NET System.Drawing.Size type. A type with this constraint is the
SettablePropertyValue<T> generic class in the
Microsoft.EnterpriseManagement.Administration namespace.
Note that constraints on a generic type parameter are introduced in C# by the where keyword (shown in bold):
|
For another example, this is a C# generic class
type that constrains the TEmployee type parameter
to be replaced by an Employee object or any object
that inherits from Employee:
|
A .NET generic type parameter can also
be defined with multiple constraints to identify a particular subset
of .NET types that you can substitute for a given type parameter
in a constructed type name. This example shows the C# definition
for the System.Nullable<T> generic structure
type:
|
Thus, System.Nullable<T> defines
two constraints on the type parameter T, where
the .NET type you substitute for T must be
a value type with a default constructor (a constructor with no parameters).
The following table lists every possible
type parameter constraint using C# syntax, where the where keyword identifies
one or more constraints on some type parameter, Tparm,
and the description shows one or more ABL constructed type examples
that satisfy each constraint.
| Constraint | Description |
|---|---|
where Tparm : struct
|
Tparm must be a value type, and can be any value
type except a nullable type (System.Nullable).For example, valid ABL references to a generic type, |
where Tparm : class
|
Tparm must be a reference type, which can be any
class, interface, delegate, or array type. For example, a valid
ABL reference to a generic type, |
where Tparm : new()
|
Tparm must have a default public constructor
(without parameters) For example, a valid ABL reference to a
generic type, |
where Tparm : BaseClassName
|
Tparm must be, or derive from, the class
specified by BaseClassName. For
example, a valid ABL reference to a generic type defined as |
where Tparm : InterfaceName
|
Tparm must be, or must implement, the interface
specified by InterfaceName. The constraining
interface can also be generic. For example, a valid ABL reference
to a generic type defined as |
where Tparm : Uparm
|
The type argument that you substitute for Tparm must be, or must derive from, the type argument
that you substitute for another type parameter, Uparm. This is called a naked type constraint. For
example, a valid ABL reference to a generic type defined as |
|
Tparm can by constrained by one or more of the
previously listed constraints (constraint), as
long as the new() constraint is listed last.For example, a valid ABL reference to a generic type defined as
|