2012-01-20 21 views
11

Quiero saber lo que hace esta llamada al método:método addObject de TStringList

stringList.addObject(String,Object); 

que también quieren saber lo que hace esta propiedad:

stringList.Objects[i] 

Parece clave, valor par al tiempo que añade. Pero al recuperar en un bucle, ¿qué se recupera?

También veo elementos [i] llamada.

Estoy confundido con las operaciones TStringList y las operaciones TList.

+1

Esto es realmente una reliquia de los antiguos Delphi pre-genéricos. Hoy en día no tiene sentido usar esos mecanismos crudos sin tipo. El 'TList genérico' reemplaza esta técnica. –

+0

@DavidHeffernan es antiguo, pero útil para usuarios sin acceso a las versiones más nuevas de delphi (> = 2009). Además, el OP no especifica la versión de Delphi que está utilizando. – RRUZ

+1

@RRUZ Exactamente.Úselo pregenéricos, pero por favor deténgalo una vez que haya ido más allá. –

Respuesta

5

El método AddObject le permite almacenar una dirección TObject (puntero) asociada a la cadena almacenada en la propiedad Item. la propiedad Objects es para acceder a los objetos almacenados.

Compruebe este ejemplo simple que utiliza AddObject para almacenar un valor entero asociado a cada cadena.

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

Sí, TStringList.Objects [] se puede usar para almacenar valores. ¡Pero recuerde que con XE2 el tamaño del puntero no siempre es igual al tamaño entero! –

+1

De hecho, pero si usa x64, el puntero tiene un tamaño de 8 bytes y perfectamente puede contener un entero que siempre tiene un tamaño de 4 bytes. – RRUZ

+1

Si está utilizando un delphi antes de que TStringList tuviera una propiedad 'OwnsObjects' (y un parámetro constructor) y no está almacenando simplemente valores sino referencias de instancia, entonces debería liberar cualquier instancia que coloque en esas referencias de objeto antes de liberar el StringList (a menos que esas instancias fueran propiedad de otra cosa). –

2

TStringList es más que una lista de cadenas.

Puede ser utilizado para pares de nombre y valor:

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

Pero también se puede utilizar para asociar las cadenas con cualquier objeto (o cualquier puntero).

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 es una lista que almacena punteros. No están asociados con cadenas.

+3

-1 Usted * deberá * mencionar en su respuesta que cualquier objeto asignado ('TFuit.Create') debe ser liberado (' para i: = 0 a stringlist.Count-1 do stringList.Objects [i] .Free; 'o Propiedad 'OwnsObjects') - no es una buena idea usar' TStringList' para almacenar solo objetos creados. Puede usarlo con objetos que tienen propiedad administrada por VCL o tienen su propia vida útil. OP parece ser inexperimentado, por lo que su respuesta debería mencionar al menos eso (como Ken White's). –

16

Agrega un par de elementos: una entrada en la lista TStringList.Strings, y un TObject correspondiente en la lista TStringList.Objects.

Esto le permite, por ejemplo, almacenar una lista de cadenas que proporcionan un nombre para el elemento y un objeto que es la clase que contiene el elemento correspondiente.

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; 

Esto es claramente un ejemplo artificial, ya que no es algo que realmente encuentre útil. Sin embargo, demuestra el concepto.

Otro uso práctico es para almacenar un valor entero junto con una cadena (por ejemplo, mostrando una lista de artículos en un TComboBox o TListBox y una correspondiente ID para su uso en una consulta de base de datos). En este caso, solo tiene que escribir el entero (o cualquier otra cosa que sea SizeOf (Pointer)) en la matriz 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; 

En el caso de almacenar las cosas que no sean un verdadero TObject, que no es necesario para liberar el contenido. Como no son objetos reales, no hay nada que liberar, excepto el TStringList.

+2

Las versiones más nuevas de Delphi tienen una TStringList con una propiedad 'OwnsObjects' (y un parámetro constructor) muy similar a TObjectList. Si se establece en verdadero, no es necesario, de hecho no debe, liberar las instancias antes de liberar la lista. –

+1

Buen punto, Marjan. Gracias por mencionarlo. :) –

+0

Sería útil describir qué sucede con los objetos cuando, por ejemplo, 'stringListB: = stringListA'. ¿StringListB.Objects toma una copia del puntero a los objetos originales? ¿Esto significa que cuando queremos que 'stringListA' se libere, no deberíamos liberar uno por uno sus Objetos asignados? – Vassilis

Cuestiones relacionadas