3 Stimmen

Delphi: Andere Typen als Integer für die Indizierung von TStringList-Elementen

Arrays können mit benutzerdefinierten Aufzählungstypen indiziert werden. Zum Beispiel:

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

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

Auf die Elemente dieses Arrays kann dann mit TIndexValue Werte als Index:

MyArray[ZERO] := 'abc';

Ich versuche, dasselbe zu erreichen allgemein Funktionalität mit einer TStringList .

Eine einfache Lösung besteht darin, jeden Indexwert in eine Integer Typ zum Zeitpunkt der Bezugnahme:

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

Eine andere Lösung (um das ganze Casting auszublenden) ist die Erstellung einer Unterklasse von TStringList und verschieben das Casting auf die Unterprogramme dieser Unterklasse, die auf die geerbten Strings Eigentum:

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;

Dies funktioniert gut bei einer einzigen Implementierung, die den Aufzählungstyp TIndexValue .

Ich möchte jedoch dieselbe Logik oder Unterklasse für mehrere verschiedene Anwendungen wiederverwenden. TStringList Objekte, die durch verschiedene Aufzählungstypen indiziert sind, ohne dass sie TStringList Unterklassen für jeden möglichen Aufzählungstyp.

Ist so etwas möglich? Ich vermute, ich kann auf Delphi's Generics abhängen, aber ich würde sehr daran interessiert sein, zu erfahren, dass es einfachere Möglichkeiten, dies zu erreichen.

4voto

boileau Punkte 807

Ich denke, dass Generika bei weitem die eleganteste Lösung wären. Sie zu verwenden wäre so einfach wie das Umschreiben Ihrer Klasse oben als:

TEIStringList<T> = class(TStringList) 

und ersetzen dann alle TIndexValue-Referenzen durch T. Dann können Sie es genauso wie jedes andere generische Element erstellen:

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

Wenn Sie darauf bestehen, Generika zu vermeiden, wäre vielleicht die Überladung von Operatoren von Nutzen. Etwas wie das Folgende sollte funktionieren:

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

(...)

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

Dann verwenden Sie mit:

var
  Inx : TIndexValueHolder;

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

UPDATE: Sie könnten TIndexValueHolder für die Verwendung in einer for- oder while-Schleife anpassen, indem Sie die Methoden Next, HasNext, etc. hinzufügen. Dies könnte jedoch den Zweck vereiteln. Ich bin immer noch nicht sicher, was der Zweck ist, oder warum dies nützlich sein würde, aber hier sind einige Ideen, wie es zu tun, auf jeden Fall.

2voto

NGLN Punkte 41853

Sie können wahrscheinlich eine Klassenhilfe verwenden und die Standardeigenschaft index als Variant deklarieren:

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;

Test-Code:

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;

Siehe Bearbeitungshistorie für einen früheren, weniger erfolgreichen Versuch.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X