2012-01-20 14 views
11

Chcę wiedzieć, co robi ta metoda połączenia:metoda TStringList za addObject

stringList.addObject(String,Object); 

Chcę też wiedzieć, co robi ta właściwość:

stringList.Objects[i] 

Wygląda kluczem, para wartości podczas dodawania. Ale podczas pobierania w pętli, co zostanie odzyskane?

Widzę również pozycje [i] zadzwoń.

Jestem zdezorientowany z operacji TStringList i operacji TList.

+1

To jest naprawdę relikt starożytnych pre-generics Delphi. W dzisiejszych czasach nie ma sensu używać tak prymitywnych mechanizmów bezdusznych. Typowa 'TList ' zastępuje tę technikę. –

+0

@DavidHeffernan jest starożytny, ale przydatny dla użytkowników bez dostępu do nowszych wersji delphi (> = 2009). Również OP nie określa wersji Delphi, która jest używana. – RRUZ

+1

@RRUZ Dokładnie.Używaj pre-generics, ale zatrzymaj go, kiedy już się wyniesiesz. –

Odpowiedz

5

Metoda AddObject pozwala zapisać adres TObject (wskaźnik) powiązany z ciągiem przechowywanym we właściwości Item. Właściwość Objects służy do uzyskiwania dostępu do przechowywanych obiektów.

Sprawdź ten prosty samplem, który używa AddObject, aby zapisać wartość całkowitą powiązaną z każdym ciągiem.

var 
List : TStringList; 
I : integer; 
begin 
    try 
    List:=TStringList.Create; 
    try 
     List.AddObject('Item 1', TObject(332)); 
     List.AddObject('Item 2', TObject(345)); 
     List.AddObject('Item 3', TObject(644)); 
     List.AddObject('Item 4', TObject(894)); 

     for I := 0 to List.Count-1 do 
     Writeln(Format('The item %d contains the string "%s" and the integer value %d',[I, List[I], Integer(List.Objects[i])])); 
    finally 
     List.Free; 
    end; 
    except 
    on E: Exception do 
     Writeln(E.ClassName, ': ', E.Message); 
    end; 
    Readln; 
end. 
+1

Tak, TStringList.Objects [] może służyć do przechowywania wartości. Ale pamiętaj, że przy XE2 rozmiar wskaźnika nie zawsze jest równy wielkości całkowitej! –

+1

Rzeczywiście, ale jeśli używasz x64 wskaźnik ma rozmiar 8 bajtów i idealnie może pomieścić liczbę całkowitą, która zawsze ma rozmiar 4 bajtów. – RRUZ

+1

Jeśli używasz delphi zanim TStringList miał właściwość 'OwnsObjects' (i parametr konstruktora) i nie przechowujesz tylko wartości, ale referencje instancji, musisz zwolnić wszystkie instancje, które umieścisz w tych odwołaniach do obiektów, zanim zwolnisz samą StringList (chyba że te instancje były własnością czegoś innego). –

2

TStringList to więcej niż lista ciągów.

Może być stosowany dla par wartości nazwa:

stringlist.Values['apple'] := 'one'; 
stringlist.Values['banana'] := 'two'; 

Ale to może być również używany do kojarzenia sznurki z każdego przedmiotu (lub dowolnym wskaźnikiem).

stringlist.AddObject('apple', TFruit.Create); 
stringlist.AddObject('banana', TFruit.Create); 


i := stringlist.IndexOf('apple'); 
if i >= 0 then 
    myfruit := stringlist.Objects[i] as TFruit; 

TList to lista, która przechowuje wskaźniki. Nie są powiązane z ciągami.

+3

-1 Ty * powinieneś wspomnieć w swojej odpowiedzi, że każdy przydzielony obiekt ('TFuit.Create') musi zostać zwolniony (' for i: = 0 to stringlist.Count-1 do stringList.Objects [i] .Free; 'lub Właściwość OwnsObjects) - nie jest dobrym pomysłem użycie 'TStringList' do przechowywania właśnie utworzonych obiektów. Można go używać z obiektami, które mają własność zarządzaną przez VCL lub mają własny okres istnienia. OP wydaje się być niedoświadczony, więc twoja odpowiedź powinna przynajmniej wspomnieć o tym (jak Ken White). –

16

Dodaje parę elementów: wpis na liście TStringList.Strings i odpowiadający TObject na liście TStringList.Objects.

Pozwala to na przykład na przechowywanie listy łańcuchów, które zawierają nazwę elementu, oraz obiektu będącego klasą zawierającą pasujący element.

type 
    TPerson=class 
    FFirstName, FLastName: string; 
    FDOB: TDateTime; 
    FID: Integer; 
    private 
    function GetDOBAsString: string; 
    function GetFullName: string; 
    published 
    property FirstName: string read FFirstName write FFirstName; 
    property LastName: string read FLastName write FLastName; 
    property DOB: TDateTime read FDOB write FDOB; 
    property DOBString: string read GetDOBAsString; 
    property FullName: string read GetFullName; 
    property ID: Integer read FID write FID; 
    end; 

implementation 

{TPerson} 
function TPerson.GetDOBAsString: string; 
begin 
    Result := 'Unknown'; 
    if FDOB <> 0 then 
    Result := DateToStr(FDOB); 
end; 

function TPerson.GetFullName: string; 
begin 
    Result := FFirstName + ' ' + FLastName; // Or FLastName + ', ' + FFirstName 
end; 

var 
    PersonList: TStringList; 
    Person: TPerson; 
    i: Integer; 
begin 
    PersonList := TStringList.Create; 
    try 
    for i := 0 to 9 do 
    begin 
     Person := TPerson.Create; 
     Person.FirstName := 'John'; 
     Person.LastName := Format('Smith-%d', [i]); // Obviously, 'Smith-1' isn't a common last name. 
     Person.DOB := Date() - RandRange(1500, 3000); // Make up a date of birth 
     Person.ID := i; 
     PersonList.AddObject(Person.LastName, Person); 
    end; 

    // Find 'Smith-06' 
    i := PersonList.IndexOf('Smith-06'); 
    if i > -1 then 
    begin 
     Person := TPerson(PersonList[i]); 
     ShowMessage(Format('Full Name: %s, ID: %d, DOB: %s', 
         [Person.FullName, Person.ID, Person.DOBString])); 
    end; 
    finally 
    for i := 0 to PersonList.Count - 1 do 
     PersonList.Objects[i].Free; 
    PersonList.Free; 
    end; 

Jest to wyraźnie wymyślny przykład, ponieważ nie jest to coś, co naprawdę mogłoby się okazać przydatne. Pokazuje jednak koncepcję.

Innym przydatnym zastosowaniem jest przechowywanie wartości całkowitych wraz z ciągiem znaków (na przykład pokazanie listy pozycji w pliku TComboBox lub TListBox i odpowiedniego identyfikatora do użycia w zapytaniu do bazy danych). W tym przypadku musisz tylko wpisać liczbę całkowitą (lub cokolwiek innego, co jest SizeOf (Wskaźnik)) w tablicy Objects.

// Assuming LBox is a TListBox on a form: 
while not QryItems.Eof do 
begin 
    LBox.Items.AddObject(QryItem.Fields[0].AsString, TObject(QryItem.Fields[1[.AsInteger)); 
    QryItems.Next; 
end; 

// User makes selection from LBox 
i := LBox.ItemIndex; 
if i > -1 then 
begin 
    ID := Integer(LBox.Items.Objects[i]); 
    QryDetails.ParamByName('ItemID').AsInteger := ID; 
    // Open query and get info. 
end; 

W przypadku przechowywania rzeczy inne niż rzeczywiste TObject, nie trzeba uwolnić zawartość. Ponieważ nie są prawdziwymi obiektami, nie ma nic do stracenia poza samym sobą.

+2

Nowsze wersje Delphi mają TStringList z właściwością 'OwnsObjects' (i parametrem konstruktora) podobnie jak TObjectList. Jeśli jest to ustawione na true, nie musisz, w rzeczywistości nie powinieneś, zwolnić instancji przed zwolnieniem listy. –

+1

Dobra uwaga, Marjan. Dzięki za wzmiankę o tym. :) –

+0

Przydałoby się opisać, co dzieje się z obiektami, gdy na przykład 'stringListB: = stringListA'. Czy stringListB.Objects pobiera kopię wskaźnika do oryginalnych obiektów? Czy to oznacza, że ​​kiedy chcemy zwolnić 'stringListA', nie powinniśmy uwolnić jeden po drugim przypisanych mu obiektów? – Vassilis

Powiązane problemy