3

Arraysユーザー定義の列挙型を使用してインデックスを作成できます。例えば:

type
  TIndexValue = (ZERO = 0, ONE, TWO, THREE, FOUR);

var
  MyArray: array[Low(TIndexValue) .. High(TIndexValue)] of String;

この配列の要素は、TIndexValue値をインデックスとして使用して参照できます。

MyArray[ZERO] := 'abc';

これと同じ一般的な機能を。で取得しようとしていTStringListます。

Integer簡単な解決策の1つは、参照時にすべてのインデックス値を型にキャストすることです。

MyStringList[Integer(ZERO)] := 'abc';

別の解決策(すべてのキャストを非表示にする)は、のサブクラスを作成し、継承されたプロパティTStringListにアクセスするこのサブクラスのサブルーチンへのすべてのキャストを延期することです。Strings

type
  TIndexValue = (ZERO = 0, ONE, TWO, THREE, FOUR);

type
  TEIStringList = class(TStringList)
  private
    function GetString(ItemIndex: TIndexValue): String;
    procedure SetString(ItemIndex: TIndexValue; ItemValue: String);
  public
    property Strings[ItemIndex: TIndexValue]: String 
      read GetString write SetString; default;
  end;

function TEIStringList.GetString(ItemIndex: TIndexValue): String;
begin
  Result := inherited Strings[Integer(ItemIndex)];
end;

procedure TEIStringList.SetString(ItemIndex: TIndexValue; ItemValue: String);
begin
  inherited Strings[Integer(ItemIndex)] := ItemValue;
end;

これは、列挙型を使用する単一の実装で正常に機能しますTIndexValue

ただし、可能な列挙型ごとにサブクラスTStringListを定義することなく、この同じロジックまたはサブクラスを、異なる列挙型によってインデックス付けされたいくつかの異なるオブジェクトに再利用したいと思います。TStringList

このようなことは可能ですか?Delphiのジェネリックに依存する必要があるのではないかと思いますが、これを実現するためのより簡単な方法があることを知りたいと思います。

4

2 に答える 2

4

ジェネリックは断然最もエレガントな解決策になると思います。それらの使用は、上記のクラスを次のように書き直すのと同じくらい簡単です。

TEIStringList<T> = class(TStringList) 

次に、すべてのTIndexValue参照をTに置き換えます。次に、他のジェネリックと同じように作成できます。

var
  SL: TEIStringList<TIndexValue>;
begin
  SL:=TEIStringList<TIndexValue>.Create;
  (...)
  ShowMessage(SL[ZERO])
  (...)
end;

ジェネリックスを避けることを主張する場合は、演算子のオーバーロードが役立つかもしれません。次のようなものが機能するはずです。

type
  TIndexValueHolder = record
    Value : TIndexValue;
    class operator Implicit(A: TMyRecord): integer;
  end;

(...)

class operator TIndexValueHolder.Implicit(A: TMyRecord): integer;
begin
  Result:=Integer(A);
end;

次に、以下で使用します。

var
  Inx : TIndexValueHolder;

begin
  Inx.Value:=ZERO;
  ShowMessage(SL[Inx]);
end

更新:Next、HasNextなどのメソッドを追加することにより、forループまたはwhileループで使用するためにTIndexValueHolderを適合させることができます。ただし、これで目的が果たせなくなる可能性があります。目的が何であるか、なぜこれが役立つのかはまだわかりませんが、とにかく、それを行う方法についていくつかのアイデアがあります。

于 2012-02-20T19:57:32.283 に答える
2

おそらく、クラスヘルパーを使用して、デフォルトのプロパティインデックスをVariantとして宣言できます。

type
  TEnum1 = (Zero = 0, One, Two, Three, Four);
  TEnum2 = (Nul = 0, Een, Twee, Drie, Vier);
  TEnum3 = (Gds = 0, Psajs, Oeroifd, Vsops, Wowid);

  TStringListHelper = class helper for TStringList
  private
    function GetString(Index: Variant): String;
    procedure SetString(Index: Variant; const Value: String);
  public
    property Strings[Index: Variant]: String read GetString write SetString;
      default;
  end;

function TStringListHelper.GetString(Index: Variant): String;
begin
  Result := inherited Strings[Index];
end;

procedure TStringListHelper.SetString(Index: Variant; const Value: String);
begin
  inherited Strings[Index] := Value;
end;

テストコード:

procedure TForm1.Button1Click(Sender: TObject);
var
  Strings: TStringList;
begin
  Strings := TStringList.Create;
  try
    Strings.Add('Line 1');
    Strings.Add('Second line');
    Strings[Zero] := 'First line';
    Memo1.Lines.Assign(Strings);
    Caption := Strings[Psajs];
  finally
    Strings.Free;
  end;
end;

以前に成功しなかった試行については、編集履歴を参照してください。

于 2012-02-20T18:56:59.647 に答える