Почему переменные объявляются как TStrings
и создаются как TStringList
?
например: var 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;
На мой взгляд, это довольно бессмысленно, хотя и совершенно безвредно. Вы могли бы прекрасно заявить 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
.
TStrings
потомок в PrintToStdOut
, так TStringList
, Memo1.Lines
, ListBox1.Items
и т.д. работает отлично. Объявление о принятии TStringList
будет означать, что последние два вызова потерпят неудачу.
TStrings
- абстрактный тип, который не имеет всех реализованных методов.
TStringList
является потомком TStrings
и реализует все функции. В вашем коде вы также можете объявить свою переменную как TStringList
.
Однако, например, на определениях функций имеет смысл принять параметр TStrings
вместо TStringList
:
procedure doSomething(lst: TStrings);
Это позволяет функции работать со всеми реализациями TStrings
, а не только TStringList
.
Таким образом, вы можете поместить другого TStrings
потомка в переменную SL
(я бы назвал это Strings
, а не SL
).
В вашем случае, это спорный вопрос, так как логика вокруг SL
содержит создание TStringList
и нет внешнего назначения или параметр синтаксического анализа.
Но если вы когда-либо отделили логику от назначения, тогда вы могли бы использовать любой потомок TStrings
.
Например, a 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)
a TStringList - это конкретная реализация абстрактного класса TStrings
TSL = TStringList
во включаемый файл, который вы включаете в каждый модуль ....... ;-)