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

35

Почему переменные объявляются как 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;
  • 9
    Моя главная причина: TStrings требует меньше печатания :)
  • 2
    @mjn Почему бы не пойти до конца и добавить TSL = TStringList во включаемый файл, который вы включаете в каждый модуль ....... ;-)
Показать ещё 7 комментариев
Теги:
tstringlist

4 ответа

27
Лучший ответ

На мой взгляд, это довольно бессмысленно, хотя и совершенно безвредно. Вы могли бы прекрасно заявить 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.

  • 11
    Как указано (но не слишком хорошо описывают), причиной этого является хороший дизайн , что позволяет использовать любые TStrings потомок в PrintToStdOut , так TStringList , Memo1.Lines , ListBox1.Items и т.д. работает отлично. Объявление о принятии TStringList будет означать, что последние два вызова потерпят неудачу.
  • 0
    Хм, я был неправ.
32

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

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

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

procedure doSomething(lst: TStrings);

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

  • 3
    +1 Хороший ответ - лаконично!
  • 0
    Прямо и очень просто: спасибо!
7

Таким образом, вы можете поместить другого 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)
5

a TStringList - это конкретная реализация абстрактного класса TStrings

  • 0
    Это правда, но это не отвечает на вопрос.
  • 3
    Это действительно так, если вы знаете, почему хорошо иметь базовые классы Abstract, и по той же причине иногда полезно иметь интерфейс. В delphi абстрактные базовые классы являются интерфейсами с одним наследованием без подсчета ссылок.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню