2014-06-17 9 views
5

Ho la migrazione di un progetto sviluppato in Delphi 7 e guardando il codice ogni volta che gli sviluppatori precedenti volevano utilizzare un insieme hanno creato qualcosa di simile:Devo usare "TList <String>" invece di "Array of String" sempre?

ArrayOfString : array of string; 
ArrayOfInteger: array of integer; 
ArrayOfStringArrays : array of ArrayOfString; 

Questo tipo di codice viene ripetuto in molti luoghi, e anche il "SetLength" per ognuna di esse più volte, mi chiedo se si modifica tutto questo Array of Something in un TList<Something> ora che siamo in Delphi XE4.

C'è qualche vantaggio nel fare questo, risorse, velocità o qualcosa del genere per sostenermi in questa decisione?

PS: Io vengo da Java e Delphi per me si sente buio e pieno di terrori

+3

Allora benvenuto nell'oscurità e nel terrore! :) – TLama

risposta

8

pensare a un array dinamico come un costrutto livello inferiore rispetto TStringList o TList<T>.

L'array dinamico offre l'accesso diretto agli elementi tramite un puntatore. Il linguaggio nasconde il puntatore da te, ma è essenzialmente tutto ciò che è un array dinamico. Ma sei responsabile di eventuali riallocazioni e se desideri inserire o rimuovere elementi, devi scrivere il codice e gestire i dettagli.

Le classi di raccolta di livello superiore, TStringList e TList<T> vengono create sopra gli array dinamici. Questo è internamente come i contenuti sono memorizzati. Ma le classi di raccolta lo completano per te. Le operazioni di livello più elevato come l'inserimento e l'eliminazione e molte altre sono fornite come metodi. In sostanza, queste classi di raccolta offrono molto più comodità rispetto agli array dinamici non elaborati.

Per illustrare, prendere in considerazione l'atto di inserire un articolo. Per un array dinamico, procedere come segue:

  1. Ridimensionare l'array.
  2. Sposta gli elementi che si trovano dopo il punto di inserimento dalla posizione i a i + 1.
  3. Assegnare l'elemento inserito.

Se è necessario scrivere questo codice più di una volta, beh, si sta sbagliando.

Per la collezione di alto livello si scrive:

List.Insert(Index, Value); 

e lasciare che la classe prendersi cura dei dettagli.

Si noti che per motivi storici e perché le stringhe sono particolarmente importanti, gli sviluppatori tendono a utilizzare la classe TStringList dedicata, anziché TList<string>. Anche in questo caso la classe dedicata offre funzionalità al di sopra e al di sotto di TList<string> perché è specializzata in stringhe e può offrire funzionalità su misura per le stringhe. Ancora una volta, la classe dedicata offre convenienza.

Un luogo in cui gli array dinamici sono utili quando non si vuole incorrere nello schema di gestione della durata. Quindi per i compilatori desktop che non hanno ARC per le classi, è necessario distruggere esplicitamente le istanze TList<T>. Ma gli array dinamici sono gestiti a vita da ARC. Se si sintetizzano array in un colpo e quindi non si ridimensionano, il problema della gestione a vita può rendere gli array più comodi da utilizzare.

Come regola generale, preferire le classi di raccolta di alto livello. Dovrebbero essere la tua scelta predefinita. A volte gli array dinamici sono la scelta giusta, ma tende ad essere per scenari più specializzati.

+0

Preferisco non fare una nuova domanda per questo ma, c'è un progetto in cui tutto è fatto con array dinamici, mi chiedo se sia una buona idea sostituire quelli per TList o lasciarlo così ... puoi consigliare me? – sandiego206

+0

Impossibile dire da qui –

5

Innanzitutto, nelle versioni più recenti di Delphi, c'è un tipo TArray<T> che può essere utilizzato per sostituire tutte quelle vecchie dichiarazioni array of whatever. Usarlo può aggirare alcuni trucchi di vecchia data nella lingua, lasciati dal classico Pascal, e aiutarti a non imbattersi in bug confusi lungo la strada.

Detto questo, TStringList non è un array di stringhe; è un oggetto contenitore che contiene un elenco di stringhe. Ha diversi metodi specializzati per la gestione delle stringhe che lo rendono estremamente versatile: può essere usato essenzialmente come un elenco di stringhe, un set di stringhe (tramite la proprietà .Sorted), una stringa/mappa oggetto (tramite la proprietà .Objects) e una mappa della stringa/stringa (tramite le proprietà .Names e .Values.)

Se trovate che stai chiamando SetLength su un array molto, soprattutto se si tratta di qualcosa di simile al seguente, si dovrebbe assolutamente convertirlo in una classe lista:

for i := 0 to Count - 1 do 
begin 
    SetLength(myArray, length(myArray) + 1); 
    myArray[high(myArray)] := values[i]; 
end; 

Con un generico TList<T> o un TStringList, questo diventa:

for i := 0 to Count - 1 do 
begin 
    myList.Add(values[i]); 
end; 

Questo è sia più semplice da leggere e decisamente più performante (soprattutto con un grande valore di conteggio) perché le classi della lista sono in grado di monitorare il loro formato internamente e tenere le riassegnazioni di memoria verso il basso. Quindi le classi di lista sono una situazione vantaggiosa per la maggior parte del tempo. Ci sono alcuni scenari in cui preferiresti gli array dinamici, ma sono piuttosto rari.

Una cosa di cui essere a conoscenza, però: se si proviene da uno sfondo Java, tenere presente che gli array dinamici sono tipi gestiti dal compilatore, ma le classi di elenco sono oggetti che devono essere liberati nel codice.

+0

"... e significativamente più performante", quindi è vero che gli elenchi vengono elaborati più velocemente degli array? – sandiego206

+0

@ sandiego206: Intendevo specificamente * aggiungere tutti quegli elementi all'elenco * sarà significativamente più performante che dover chiamare 'SetLength' più e più volte. Per elaborare le cose, dipende davvero da cosa intendi esattamente con "elaborazione". –

+0

per il primo esempio che sposta 'SetLength (myArray, length (myArray) + Count);' outside the loop sarebbe più performante, poiché l'allocazione dell'heap verrà eseguita solo una volta. Per 'TStrings' e discendenti, usa' myList.Capacity: = myList.Capacity + Count' per fare lo stesso (nelle versioni successive di Delphi SetCapacity chiama SetLength su un array interno) –

0

A meno che non si abbia una necessità specifica per Array of String, quindi suggerirei fortemente una TStringList. Non userei affatto TList, personalmente. TStringList fornisce tutto ciò di cui ho bisogno e solo alcuni casi ho avuto bisogno di ricorrere a un array di stringhe.

È possibile accedere a TStringList come un array tramite myStringList.Items [i] o anche solo myStringList [i].

Non è necessario mantenere la modifica della lunghezza o mantenere il conteggio, solo myStringList.Add (aString) e myStringList.Count (non dimenticare il ciclo -1 per il ciclo).

Inoltre ha le routine necessari per tutte le manipolazioni della lista per l'aggiunta, la rimozione, il riordino, l'ordinamento, ecc

Può anche essere passato come parametro, senza bisogno di altre dichiarazioni, come è necessario per i tipi di array.

Spero che questo aiuti.

+0

E se vuoi una raccolta di cose che non sono stringhe? –

+0

Se si desidera disporre di una raccolta di oggetti, allora TObjectList è lo strumento per il lavoro. Ha tutti i pro che una TStringList ha ma per gli oggetti. Se davvero, davvero devi usare un array, allora va bene, ma se hai bisogno di una collezione, allora TObjectList per gli oggetti e TStringList per le stringhe. – EchelonKnight

+2

Si utilizza 'TObjectList ' quando è necessario l'elenco per possedere gli oggetti. Altrimenti 'TList ' è migliore. Ma che dire di una raccolta di numeri interi, come da domanda? –