Home > Delphi, Did You Know > Overloading Default Array Properties

Overloading Default Array Properties


Secara default, setiap akses properti bertipe array -seperti TStrings- menggunakan indeks bertipe integer. Nah terkadang, kita menginginkan akses array tersebut dengan menggunakan indeks bertipe selain integer, misalnya string, enumerasi dan sebagainya seperti cuplikan kode berikut:

  Obj := MyObj.Items[1];
  Obj := MyObj.Items['Host'];
  Obj := MyObj.Items[oiHost];

Pada .NET (dan Java ?), akses array properti dengan indexer yang berbeda dapat dilakukan secara built-in. Fitur ini dinamakan ‘boxing‘.

Pada artikel sebelumnya, sudah dibahas bagaimana akses indexer bertipe string dan mengaitkan properti array dengan suatu method sebagai method default untuk properti tersebut.

Nah pada artikel ini adalah bagaimana membuat properti array default yang mampu menerima berbagai jenis indexer. Dalam kasus ini kita menggunakan contoh kode dari artikel sebelumnya. Indexer yang ingin dikembangkan adalah Integer, string dan enumerasi.

Kunci dari kasus ini tentu saja dengan menggunakan directive overload dan default. Sehingga dari kode sebelumnya, kita cukup melakukan sedikit penyesuaian saja.

Jump to the Code

Untuk lebih menyesuaikan, maka kita harus sesuaikan dulu nama properti array ObjectsByName menjadi ObjectsBoxing.

    property ObjectsBoxing[Index: string]: TObject read GetObject write PutObject; default;

Untuk indexer integer, kita tinggal berikan akses read dan write ke method GetObject dan PutObject yang sudah ada, yaitu yang dideklarasikan dalam kelas TStrings. Sehingga tambahan kode menjadi:

    property ObjectsBoxing[Index: Integer]: TObject read GetObject write PutObject; default;
    property ObjectsBoxing[Index: string]: TObject read GetObject write PutObject; default;

Langkah selanjutnya adalah bagaimana mengimplementasikan indexer enumerasi. Untuk itu perlu dibuat method GetObject dan PutObject dengan parameter indexer enumerasi. Seperti biasa, harus ditambahkan directive overload. Dalam contoh ini enumerasi nya adalah TUserDefined.

Sehingga deklarasi kelas menjadi:

  TUserDefined = (udOdd, udEven);

  TStringsHelper = class helper for TStrings
  protected
    function GetObject(Index: string): TObject; overload;
    function GetObject(Index: TUserDefined): TObject; overload;
    procedure PutObject(Index: string; AObject: TObject); overload;
    procedure PutObject(Index: TUserDefined; AObject: TObject); overload;
  public
    property ObjectsBoxing[Index: Integer]: TObject read GetObject write PutObject; default;
    property ObjectsBoxing[Index: string]: TObject read GetObject write PutObject; default;
    property ObjectsBoxing[Index: TUserDefined]: TObject read GetObject write PutObject; default;
  end;

Dalam kasus ini, method GetObject indexer enumerasi akan mengembalikan TObject item ke 1 jika indeks nya bernilai udOdd dan item ke 6 jika indeks nya bernilai udEven. Demikian pula dengan method PutObject. Jika bernilai udOdd maka akan menyimpan ke item 1 dan udEven ke item 6.

Implementasi method GetObject dan PutObject:

function TStringsHelper.GetObject(Index: TUserDefined): TObject;
begin
  case Index of
    udOdd: Result := Self.Objects[1];
    udEven: Result := Self.Objects[6];
  end;
end;

procedure TStringsHelper.PutObject(Index: TUserDefined; AObject: TObject);
begin
  case Index of
    udOdd: Self.Objects[1] := AObject;
    udEven: Self.Objects[6] := AObject;
  end;
end;

Dan ketika properti Items di akses, maka method GetObject sudah tampak di CodeInsight dan tentu saja sudah siap digunakan.

CodeInsight

Skrinsyut indexer integer:
Indexer Integer

Skrinsyut indexer string:
Indexer String

Skrinsyut indexer enumerasi:
Indexer Enumerasi

Secara lengkap, kodenya adalah sebagai berikut:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls;

type
  TIntType = class
  private
    FValue: Integer;
    procedure SetValue(const Value: Integer);
  public
    constructor Create(Value: Integer);
    property Value: Integer read FValue write SetValue;
  end;

  TUserDefined = (udOdd, udEven);

  TStringsHelper = class helper for TStrings
  protected
    function GetObject(Index: string): TObject; overload;
    function GetObject(Index: TUserDefined): TObject; overload;
    procedure PutObject(Index: string; AObject: TObject); overload;
    procedure PutObject(Index: TUserDefined; AObject: TObject); overload;
  public
    property ObjectsBoxing[Index: Integer]: TObject read GetObject write PutObject; default;
    property ObjectsBoxing[Index: string]: TObject read GetObject write PutObject; default;
    property ObjectsBoxing[Index: TUserDefined]: TObject read GetObject write PutObject; default;
  end;

  TfrmOverloadingPropDemo = class(TForm)
    ListBox: TListBox;
    leInteger: TLabeledEdit;
    btnInteger: TButton;
    lblInfo: TLabel;
    lblAbout: TLabel;
    leString: TLabeledEdit;
    btnString: TButton;
    leEnumerasi: TLabeledEdit;
    btnEnum: TButton;
    procedure btnIntegerClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormShow(Sender: TObject);
    procedure btnStringClick(Sender: TObject);
    procedure btnEnumClick(Sender: TObject);
  private
    { Private declarations }
    procedure FreeObjects;
    procedure AssignObject(Index: Integer);
  public
    { Public declarations }
  end;

var
  frmOverloadingPropDemo: TfrmOverloadingPropDemo;

implementation

{$R *.dfm}

{ TIntType }

constructor TIntType.Create(Value: Integer);
begin
  FValue := Value;
end;

procedure TIntType.SetValue(const Value: Integer);
begin
  FValue := Value;
end;

{ TStringsHelper }

function TStringsHelper.GetObject(Index: string): TObject;
begin
  Result := Self.Objects[Self.IndexOf(Index)];
end;

procedure TStringsHelper.PutObject(Index: string; AObject: TObject);
begin
  Self.Objects[Self.IndexOf(Index)] := AObject;
end;

function TStringsHelper.GetObject(Index: TUserDefined): TObject;
begin
  case Index of
    udOdd: Result := Self.Objects[1];
    udEven: Result := Self.Objects[6];
  end;
end;

procedure TStringsHelper.PutObject(Index: TUserDefined; AObject: TObject);
begin
  case Index of
    udOdd: Self.Objects[1] := AObject;
    udEven: Self.Objects[6] := AObject;
  end;
end;

{ TfrmOverloadingPropDemo }

procedure TfrmOverloadingPropDemo.btnEnumClick(Sender: TObject);
var
  strTemp: string;
  UserDefEnum: TUserDefined;
begin
  strTemp := LowerCase(leEnumerasi.Text);
  if strTemp = 'udodd' then UserDefEnum := udOdd
  else if strTemp = 'udeven' then UserDefEnum := udEven
  else Exit;
  ShowMessage('Items[Index: TUserDefined]' + #13#10 + 'Value of Index ' + QuotedStr(strTemp) + ' is ' +
              IntToStr(TIntType(ListBox.Items[UserDefEnum]).Value));
end;

procedure TfrmOverloadingPropDemo.btnIntegerClick(Sender: TObject);
var
  IntIndex: Integer;
begin
  IntIndex := StrToInt(leInteger.Text);
  ShowMessage('Items[Index: Integer]' + #13#10 + 'Value of Index ' + QuotedStr(leInteger.Text) + ' is ' +
              IntToStr(TIntType(ListBox.Items[IntIndex]).Value));
end;

procedure TfrmOverloadingPropDemo.btnStringClick(Sender: TObject);
var
  strIndex: string;
begin
  strIndex := leString.Text;
  ShowMessage('Items[Index: string]' + #13#10 + 'Value of Index ' + QuotedStr(strIndex) + ' is ' +
              IntToStr(TIntType(ListBox.Items[strIndex]).Value));
end;

procedure TfrmOverloadingPropDemo.AssignObject(Index: Integer);
var
  IntObj : TIntType;
begin
  IntObj := TIntType.Create(Random(10000));
  ListBox.Items.Objects[Index] := TObject(IntObj);
end;

procedure TfrmOverloadingPropDemo.FreeObjects;
var
  I: Integer;
  IntObj : TIntType;
begin
  for I := 0 to ListBox.Items.Count - 1 do
  begin
    if Assigned(ListBox.Items.Objects[I]) then
    begin
      if (ListBox.Items.Objects[I] is TIntType) then
      begin
        IntObj := TIntType(ListBox.Items.Objects[I]);
        IntObj.Free;
        ListBox.Items.Objects[I] := nil;
      end;
    end;
  end;
end;

procedure TfrmOverloadingPropDemo.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  FreeObjects;
end;

procedure TfrmOverloadingPropDemo.FormShow(Sender: TObject);
var
  I: Integer;
begin
  Randomize;
  for I := 0 to ListBox.Items.Count - 1 do
    AssignObject(I);
end;

end.

Semoga bermanfaat.

Advertisements
Categories: Delphi, Did You Know
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: