2012-02-21 9 views
34

Perché le variabili sono dichiarate come TStrings e create come TStringList?Perché le variabili sono dichiarate come TStrings e create come TStringList?

ad esempio: la var sl è dichiarato come TStrings ma creata come 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

mia ragione superiore: TStrings comporta meno di battitura :) – mjn

+2

@mjn Perché non andare fino in fondo e aggiungere 'TSL = TStringList' ad un file di inclusione che includi in ogni unità ....... ;-) –

+1

Ottima domanda !! Credo che l'origine di questa domanda risieda nel codice sorgente VCL che comunemente usa il tipo di antenato radice per variabili, come 'TControl'. I codificatori (incluso me) tendono a radicare ogni variabile, ma non ha alcun significato. Grazie per avermi fatto riflettere. – NGLN

risposta

28

Per la mia mente che è piuttosto inutile anche se del tutto innocuo. Potresti benissimo dichiarare sl come TStringList e lo farei sempre in questo modo. Per un lettore del codice rende più facile capire la lista delle variabili locali.

In questo codice viene sempre assegnato sl un'istanza TStringList e quindi non c'è nulla da guadagnare da dichiarare sl di avere il tipo di classe di base di TStrings. Tuttavia, se si dispone di un codice che ha assegnato una varietà di diversi tipi di discendenti alla variabile, sarebbe opportuno dichiararlo come TStrings.

Le situazioni in cui è possibile dichiarare una variabile di tipo TStrings si verificano in genere quando il codice non creava esplicitamente l'istanza. Ad esempio, un metodo di utilità che ha ricevuto un elenco di stringhe come parametro sarebbe più utile se accettasse un valore TStrings da quando qualsiasi discendente potrebbe essere passato ad esso. Ecco un semplice esempio:

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

Chiaramente questo è di molto maggiore utilità quando il parametro è dichiarato TStrings piuttosto che TStringList.

Tuttavia, il codice nella domanda non è di questo tipo e credo che sarebbe migliorato così leggermente se sl è stato dichiarato di tipo TStringList.

+11

Come indicato (ma non descritto troppo bene), il motivo per cui questo è un buon design è che ti permette di usare qualsiasi discendente 'TStrings' in' PrintToStdOut', quindi 'TStringList',' Memo1.Lines', 'ListBox1 .Items', ecc. Funzionano perfettamente. Dichiarare di prendere un 'TStringList' significherebbe che le ultime due chiamate fallirebbero. –

+0

Hm, ** i ** si sbagliava. – OnTheFly

5

un TStringList è un'implementazione concreta della TStrings classe astratta

+0

È vero, ma non risponde alla domanda. – jpfollenius

+3

In genere, se si conosce il motivo per cui è opportuno avere classi di base astratte, lo stesso motivo per cui a volte è una buona idea avere un'interfaccia. In delphi, le classi di base astratte sono interfacce di ereditarietà senza conteggio dei riferimenti. –

31

TStrings è un tipo astratto che non ha tutti i metodi implementati.

TStringList è un discendente di TStrings e implementa tutte le funzioni. Nel codice, è possibile dichiarare la variabile anche come TStringList.

Tuttavia, ad es. su definizioni di funzioni ha senso accettare un parametro invece di un TStringListTStrings:

procedure doSomething(lst: TStrings); 

In questo modo la funzione di lavorare con tutte le implementazioni di TStrings, non solo TStringList.

+3

+1 Bella risposta - succinta! – Argalatyr

+0

Diretto e molto semplice: grazie! – jcfaria

7

Perché in questo modo si potrebbe mettere un altro TStrings discendente nella variabile SL (probabilmente sarei chiamare che Strings, non SL).

Nel tuo caso, questo è discutibile, poiché la logica intorno a SL contiene la creazione di uno TStringList e nessuna assegnazione esterna o analisi dei parametri.

Tuttavia, se si separa la logica dall'assegnazione, è possibile trarre vantaggio dall'utilizzo di qualsiasi discendente TStrings.

Per esempio, un TMemoy.Lines, TListBox.Items, TComboBox.Items, ecc
Dall'esterno sembra che sono TStrings, ma internamente non usano un TStringList ma loro discendente.

Alcuni esempi di classi che scendono dal 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) 
+1

+ 1, bella ricerca. – PresleyDias