Supporting Properties and Methods in Custom Variants

From RAD Studio
Jump to: navigation, search

Go Up to Defining Custom Variants Index

Some variants have properties and methods. For example, when the value of a variant is an interface, you can use the variant to read or write the values of properties on that interface and call its methods. Even if your custom variant type does not represent an interface, you may want to give it properties and methods that an application can use in the same way.

Using TInvokeableVariantType

To provide support for properties and methods, the class you create to enable the new custom variant type should descend from System.Variants.TInvokeableVariantType instead of directly from TCustomVariantType.

TInvokeableVariantType defines four methods:

that you can implement to support properties and methods on your custom variant type.

For example, the System.VarConv unit uses TInvokeableVariantType as the base class for TConvertVariantType so that the resulting custom variants can support properties. The following example shows the property getter for these properties:


 function TConvertVariantType.GetProperty(var Dest: TVarData;
 const V: TVarData; const Name: String): Boolean;
 LType: TConvType;
 // supports...
 //   'Value'
 //   'Type'
 //   'TypeName'
 //   'Family'
 //   'FamilyName'
 //   'As[Type]'
 Result := True;
 if Name = 'VALUE' then
   Variant(Dest) := TConvertVarData(V).VValue
 else if Name = 'TYPE' then
   Variant(Dest) := TConvertVarData(V).VConvType
 else if Name = 'TYPENAME' then
   Variant(Dest) := ConvTypeToDescription(TConvertVarData(V).VConvType)
 else if Name = 'FAMILY' then
   Variant(Dest) := ConvTypeToFamily(TConvertVarData(V).VConvType)
 else if Name = 'FAMILYNAME' then
   Variant(Dest) := ConvFamilyToDescription(ConvTypeToFamily(TConvertVarData(V).VConvType))
 else if System.Copy(Name, 1, 2) = 'AS' then
   if DescriptionToConvType(ConvTypeToFamily(TConvertVarData(V).VConvType), System.Copy(Name, 3, MaxInt), LType) then
     VarConvertCreateInto(Variant(Dest), Convert(TConvertVarData(V).VValue, TConvertVarData(V).VConvType, LType), LType)
     Result := False;
     Result := False;

The GetProperty method checks the Name parameter to determine what property is wanted. It then retrieves the information from the TVarData record of the Variant (V), and returns it as a Variant (Dest). Note that this method supports properties whose names are dynamically generated at run time (As[Type]), based on the current value of the custom variant.

Similarly, the SetProperty, DoFunction, and DoProcedure methods are sufficiently generic that you can dynamically generate method names, or respond to variable numbers and types of parameters.

Using TPublishableVariantType

If the custom variant type stores its data using an object instance, then there is an easier way to implement properties, as long as they are also properties of the object that represents the data of the variant. If you use System.TypInfo.TPublishableVariantType as the base class for your custom variant type, then you need only implement the GetInstance method, and all the published properties of the object that represents the data of the variant are automatically implemented for the custom variants.

For example, as was seen in Storing a custom variant type's data, TComplexVariantType stores the data of a complex-valued variant using an instance of TComplexData. TComplexData has a number of published properties (Real, Imaginary, Radius, Theta, and FixedTheta) that provide information about the complex value. TComplexVariantType descends from TPublishableVariantType, and implements the GetInstance method to return the TComplexData object (in TypInfo.pas) that is stored in a complex-valued variant's TVarData record.


 function TComplexVariantType.GetInstance(const V: TVarData): TObject;
 Result := TComplexVarData(V).VComplex;

TPublishableVariantType does the rest. It overrides the GetProperty and SetProperty methods to use the runtime type information (RTTI) of the TComplexData object for getting and setting property values.

Note: For TPublishableVariantType to work, the object that holds the custom variant's data must be compiled with RTTI. This means it must be compiled using the {$M+} compiler directive, or descend from TPersistent.

See Also