Domanda

Arrays Può essere indicizzato utilizzando tipi enumerati definiti dall'utente. Per esempio:

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

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

Gli elementi di questo array possono quindi essere referenziati utilizzando TIndexValue valori come indice:

MyArray[ZERO] := 'abc';

Sto cercando di ottenere questo stesso generale funzionalità con a TStringList.

Una soluzione semplice è lanciare ogni valore dell'indice a un Integer Digita al momento del riferimento:

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

Un'altra soluzione (per nascondere tutto il casting) è creare una sottoclasse di TStringList e differire tutto il casting alle subroutine di questa sottoclasse che accedono alle eredità Strings proprietà:

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;

Funziona bene per un'unica implementazione che utilizza il tipo enumerato TIndexValue.

Tuttavia, vorrei riutilizzare questa stessa logica o sottoclasse per diversi diversi TStringList oggetti indicizzati da diversi tipi elencati, senza dover definire TStringList sottoclassi per ciascun possibile tipo enumerato.

È possibile qualcosa di simile? Sospetto che potrei dover dipendere dai generici di Delphi, ma sarei molto interessato ad apprendere che ci sono modi più semplici per raggiungere questo obiettivo.

È stato utile?

Soluzione

Penso che i generici sarebbero di gran lunga la soluzione più elegante. Usarli sarebbe semplice come riscrivere la tua classe sopra come:

TEIStringList<T> = class(TStringList) 

e quindi sostituendo tutti i riferimenti di Tindexvalue con T. Quindi potresti crearlo come qualsiasi altro generico:

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

Se insisti per evitare i generici, forse il sovraccarico dell'operatore sarebbe utile. Qualcosa come il seguente dovrebbe funzionare:

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

(...)

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

Quindi usa con:

var
  Inx : TIndexValueHolder;

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

AGGIORNAMENTO: è possibile adattare i metodi TindexValueholder per l'uso in un loop aggiungendo i metodi successivi, Hasnext, ecc.. Questo potrebbe finire per sconfiggere lo scopo, però. Non sono ancora sicuro di quale sia lo scopo, o perché questo sarebbe utile, ma ecco alcune idee su come farlo, comunque.

Altri suggerimenti

Probabilmente è possibile utilizzare un aiutante di classe e dichiarare l'indice di proprietà predefinito come variante:

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;

Codice di test:

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;

Vedi la cronologia di modifica per un precedente tentativo meno riuscito.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top