A class reference is a special meta type that can be used to refer to classes (not instances of them) within a certain subtree of the class hierarchy. This allows to write code that can work polymorphically with classes – for example dynamically instantiate different subclasses or call virtual static methods.
A class reference can be expressed by using the
class of keywords, followed by the name of a Class.
var lControlClass: class of Control; lControlClass := Button;
A class reference variable can hold a reference to the base type it was defined for (in this example,
Control, as well as any subclass of it (e.g.
Button)). Assignment can be made by simply specifying the type name, or by using the result of the
classOf() System Function.
A valid class reference (i.e. one that is not
nil, but references an actual type) can be used in many of the same scenarios that the type name itself can be used. Most interestingly, it can be used in
new Expressions, to instantiate instances of the referenced type dynamically.
This is very powerful, as it allows for code that can instantiate new types, without knowing the exact subclass that is being instantiated, at compile time.
A class reference can also be used to call any Static Members of the type.
Of course, since a class reference is strongly-typed to reference a specific base type, it can only provide access to constructors and static members defined on the base type. For example, the above reference would allow calls to constructors and static members declared on
Control, but not any new members introduced by
Virtual Constructors and Status Members
When working with class references, Oxygene provides the ability to have Constructors, as well as any static Methods, Properties or Events be by being marked
abstract) in a base class, and
overridden in descendant classes.
Polymorphism will work just as it does normally for class instances: at runtime, calls will be directed to the implementation most appropriate for the current class reference. For example:
type Control = public abstract class public property DescriptionForToolBox: String; static; abstract; constructor(aWindow: Window); virtual; end; Button = public class(Control) property DescriptionForToolBox: String read 'A Button Control'; static; abstract; constructor(aWindow: Window); override; end; var ControlType: class of Control := Button; writeLn(ControlType.DescriptionForToolBox); // prints `A Button Control` var c := new ControlType(SomeWindow); // creates a new button
Class references in Oxygene are implemented via a meta class type.
Since emitting a meta class for every type would be a big overhead, the compiler automatically decides whether a meta class is required for a given class.
A meta class will be generated if
- the class (or one of its base classes) is used in a class reference type anywhere in the project
- the class (or one of its base classes) declares a virtual constructor or a virtual static member.
For this reason, class references can not be used for classes from external references (unless the external reference already provided the meta class). In other words,
class of cannot be used with, say, classes provided by the platform.
For custom solutions spread across multiple projects, if project A references project B, then project B can only use
class of with types from project A if a class reference for them was declared or used in project A (or if the type has a virtual constructor or a virtual static member).
An easy way to do this is to simply declare a Type Alias in the base project, for the root of the type hierarchy that should be enabled for class references, eg:
type Control = public abstract class end; ControlClass = public class of Control;
The type alias ensures that
Control, and all its subclasses, will be ready for use with class references (even if the rest of the project that declares
Control does not use class references.
Special Members on Meta Classes
Classes references implement a couple of helper methods
Instance: class of
ClassName— Holds the instance of this meta class.
ActualType: &Type— returns the platform type for the class this meta class refers to (
Typeon .NET, Java and Island, and
Additionally, any class that a meta class was generated for will expose a
GetMetaClass instance method that returns the meta class for a live instance.