Add Indexer property wizard

Often when you add an indexer / array property you need to insert additional members that implement the indexer. For example a field to store the values, make sure there's a constructor and add some initialization code. The ModelMaker Code Explorer Add Indexer Wizard is used to centralize this process. The wizard is highly customizable using Indexer implementation templates.

Pascal Example: adding an Indexer / Array property

Assume you have a class TStore that stores TThings. To expose the Things we define a read-only indexer property Things[Index] like this:

type
  TStore = class(TObject)
  private
    function GetThings(Index: Integer): TThing;
  public
    property Things[Index: Integer]: TThing read GetThings; default;
  end;

Apart from the property declaration there are usually other members required to fully implement this indexer property. For example: you'll need a field of type TList or TObjectList to actually store the things. This field must be initialized in the constructor and Freed in the destructor. You additionally might want to expose a Count property to allow iteration. The TStore class interface would then look like this:

type
  TStore = class(TObject)
  private
    FThings: TList; // stores TThings
    function GetCount: Integer; // return FThings.Count
    function GetThings(Index: Integer): TThing; // return FThings[Index]
  public
    constructor Create; // create FThings
    destructor Destroy; override; // destroy FThings
    property Count: Integer read GetCount; // Number of Things
    // the actual indexer property
    property Things[Index: Integer]: TThing read GetThings; default;
  end;

The above scenario is very common and ModelMaker Code Explorer comes with a highly specialized and flexible "Add Indexer" wizard that automates (most of) the entire process.

Add Indexer Wizard dialog

Just click OK in this dialog and the above mentioned class interface is inserted including the corresponding implementation code:

constructor TStore.Create;
begin
  inherited Create;
  FThings := TList.Create;
end;

destructor TStore.Destroy;
begin
  FreeAndNil(FThings);
  inherited Destroy;
end;

function TStore.GetCount: Integer;
begin
  Result := FThings.Count;
end;

function TStore.GetThings(Index: Integer): TThing;
begin
  Result := TThing(FThings[Index]);
end;

Customizing the wizard

The indexer implementation templates are customizable and new ones can be added. Referring to the above example: More advanced implementations could include methods FindThing(..), AddThing(..), DeleteThing(..) etc. Indexer Templates are stored in directory [install-root]\Shared\Indexers. Typically "C:\Program Files\ModelMakerTools\Shared\Indexers".

The template that defines the implementation for the above mentioned TStore / Things example looks like this:

//MM#:type=indexer-implementation
//MM#:description=Simple TList implementation with Count
//MM#:getter=begin\N Result := <!PropertyType!>(F<!PropertyName!>[<!PropIndexCallParams!>]);\Nend;
//MM#:ctor=F<!PropertyName!> := TList.Create;
//MM#:dtor=FreeAndNil(F<!PropertyName!>);

unit IndexerTemplate1;

interface

type
  TCodeTemplate = class
  private
    F<!PropertyName!>: TList;
    function GetCount: Integer;
  public
    property Count: Integer read GetCount;
  end;

implementation

function TCodeTemplate.GetCount: Integer;
begin
  Result := F<!PropertyName!>.Count;
end;

end.