2005. június 5., vasárnap

Implement an Array Property

Problem/Question/Abstract:

In an interface we can't use fields so when you declare a class that implements one or more interfaces, you must provide an implementation of all the methods declared in the interface and the fields too. Therefore Array Properties are welcome.

Answer:

Properties come in two mode behaviour, scalar and array. An array property can't be published in component design, but they have many other uses to struct your class. One of the best features is the array index can be ANY type, and multidimensional arrays are possible, too. For array-type properties, we must use getter and setter, means read and write methods; no possibilitie to map an array-type property directly to an array-type field. Thats real design. First we need a class or interface:

IChaosBase = interface(IUnknown)
['{C6661345-26D1-D611-9FAD-C52B9EAAF7C0}']
function getScales(index: integer): Tdouble; stdcall;
procedure setScales(index: integer; scale: Tdouble); stdcall;
property scales[index: integer]: TDouble
read getScales write setScales;
end;

The aim is to store those 4 fields with the property scales[]:

scaleX1: double;
scaleX2: double;
scaleY1: double;
scaleY2: double;

Second we need the implementing class. The simplest way to implement the _AddRef, _Release, and QueryInterface methods is to inherit them from TInterfacedObject, thats the meaning of TInterfacedObject:

type
TDouble = double;
TDoubleArray = array[1..4] of TDouble;

TChaosBase = class(TInterfacedObject, IChaosBase)
protected
myscales: TDoubleArray;
function getScales(index: integer): TDouble; stdcall;
procedure setScales(index: integer; scale: TDouble); stdcall;
property scales[index: integer]: TDouble
read getScales write setScales;
end;

Now comes the setter and getter, especially the setter setScalses() needs a second parameter to define the type (you remember the array index can be ANY type) in our case a simple double. Also the datastructure can be choosen (list, map, collection), in our case the structure is a simple array.

function TChaosBase.getScales(index: integer): Tdouble;
begin
result := myscales[index];
end;

procedure TChaosBase.setScales(index: integer; scale: Tdouble);
begin
myScales[index] := scale;
end;

At least the write-access goes like this from any class or method:

scales[1] := 0.89;
scales[2] := 1.23;
scales[3] := 0.23;
scales[4] := 1.34;

or the read-access is a simple call to the propertie:

scaledX := (X - scales[1]) / (scales[2] - scales[1]);
scaledY := (Y - scales[4]) / (scales[3] - scales[4]);

Default access: There can be only one default array property for each class, means instead of myChaosBase.scales[i] we can use myChaosBase[i] with the directive default:

property scales[index: integer]: TDouble read getScales write setScales; default;


Nincsenek megjegyzések:

Megjegyzés küldése