Delphi: типы, отличные от Integer, для индексации элементов TStringList - PullRequest
3 голосов
/ 20 февраля 2012

Arrays может быть проиндексировано с использованием пользовательских перечислимых типов.Например:

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

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

На элементы этого массива можно ссылаться, используя в качестве индекса значения TIndexValue:

MyArray[ZERO] := 'abc';

Я пытаюсь получить то же самое general функциональность с TStringList.

Одно простое решение - привести каждое значение индекса к типу Integer во время ссылки:

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 подклассы для каждого возможного перечисляемого типа.

Возможно ли что-то подобное?Я подозреваю, что мне, возможно, придется зависеть от Generics Delphi, но мне было бы очень интересно узнать, что есть более простые способы достичь этого.

Ответы [ 2 ]

4 голосов
/ 20 февраля 2012

Я думаю, что дженерики были бы безусловно самым элегантным решением. Использовать их так же просто, как переписать ваш класс выше:

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

UPDATE: Вы можете адаптировать TIndexValueHolder для использования в цикле for или while, добавив методы Next, HasNext и т. Д. Это может закончить поражение цели, хотя. Я все еще не уверен, какова цель или почему это было бы полезно, но вот некоторые идеи о том, как это сделать, в любом случае.

2 голосов
/ 20 февраля 2012

Вы, вероятно, можете использовать вспомогательный класс и объявить индекс свойства по умолчанию как вариант:

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;

См. Историю изменений для предыдущей менее успешной попытки.

...