Почему переменные объявлены как TStrings и созданы как TStringList? - PullRequest
36 голосов
/ 21 февраля 2012

Почему переменные объявлены как TStrings и созданы как TStringList?

Например: переменная sl объявлена ​​как TStrings, но создана как TStringList

var
  sl : TStrings;
begin
  sl := TStringList.Create;

  // add string values...
  sl.Add( 'Delphi' );
  sl.Add( '2.01' );

  // get string value using its index
  // sl.Strings( 0 ) will return
  //   'Delphi'
  MessageDlg(
    sl.Strings[ 0 ],
    mtInformation, [mbOk], 0 );

  sl.Free;
end;

Ответы [ 4 ]

34 голосов
/ 21 февраля 2012

TStrings - абстрактный тип, в котором реализованы не все методы.

TStringList является потомком TStrings и реализует все функции.В вашем коде вы можете объявить переменную также как TStringList.

Однако, например, в определениях функций имеет смысл принять параметр TStrings вместо TStringList:

procedure doSomething(lst: TStrings);

Это позволяет функции работать со всеми реализациями TStrings, а не только TStringList.

29 голосов
/ 21 февраля 2012

На мой взгляд, это довольно бессмысленно, хотя и совершенно безвредно.Вы могли бы прекрасно заявить, что sl будет TStringList, и я бы всегда так делал.Для читателя кода это облегчает понимание списка локальных переменных.

В этом коде sl всегда присваивается экземпляр TStringList, и поэтому от объявления sl ничего не получитсяиметь тип базового класса TStrings.Однако, если у вас есть код, который присваивает переменной различные типы TStrings потомков, то имеет смысл объявить ее как TStrings.

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

procedure PrintToStdOut(Strings: TStrings);
var
  Item: string;
begin
  for Item in Strings do
    Writeln(Item);
end;

Очевидно, что это гораздо полезнее, когда параметр объявлен как TStrings, а не TStringList.

Однако код в вопросене имеет такого характера, и я считаю, что было бы немного лучше, если бы sl было объявлено типа TStringList.

7 голосов
/ 22 февраля 2012

Потому что таким образом вы можете поместить другого TStrings потомка в переменную SL (я бы назвал это Strings, а не SL).

В вашем случае это спорный вопрос, поскольку логика вокруг SL содержит создание TStringList и никакого внешнего присваивания или синтаксического анализа параметров.

Но если вы когда-нибудь отделите логику от присваивания, то вы могли бы получить выгоду от использования любого TStrings потомок.

Например, TMemoy.Lines, TListBox.Items, TComboBox.Items и т. Д.
Со стороны это выглядит как TStrings, но внутри они не используютTStringList но их собственный потомок.

Несколько примеров классов, которые происходят от TStrings:

source\DUnit\Contrib\DUnitWizard\Source\DelphiExperts\Common\XP_OTAEditorUtils.pas:
     TXPEditorStrings = class(TStrings)
source\fmx\FMX.ListBox.pas:
       TListBoxStrings = class(TStrings)
source\fmx\FMX.Memo.pas:
     TMemoLines = class(TStrings)
source\rtl\common\System.Classes.pas:
     TStringList = class(TStrings)
source\vcl\Vcl.ComCtrls.pas:
     TTabStrings = class(TStrings)
     TTreeStrings = class(TStrings)
     TRichEditStrings = class(TStrings)
source\vcl\Vcl.ExtCtrls.pas:
     TPageAccess = class(TStrings)
     THeaderStrings = class(TStrings)
source\vcl\Vcl.Grids.pas:
     TStringGridStrings = class(TStrings)
     TStringSparseList = class(TStrings)
source\vcl\Vcl.Outline.pas:
     TOutlineStrings = class(TStrings)
source\vcl\Vcl.StdCtrls.pas:
     TCustomComboBoxStrings = class(TStrings)
     TMemoStrings = class(TStrings)
     TListBoxStrings = class(TStrings)
source\vcl\Vcl.TabNotBk.pas:
     TTabPageAccess = class(TStrings)
5 голосов
/ 21 февраля 2012

TStringList является конкретной реализацией абстрактного класса TStrings

...