extraer un objeto de una TObjectList
-
08-07-2019 - |
Pregunta
Tengo una TObjectList con OwnsObjects = true. Contiene bastantes objetos. Ahora quiero eliminar el objeto en el índice Idx de esa lista, sin liberarlo.
¿Es el método de extracción la única opción?
ExtractedObject: = TheList.Extract (TheList [Idx]);
Todos los demás métodos parecen liberar el objeto. Estoy buscando algo un poco más eficiente, que no haga una búsqueda lineal cada vez, ya que ya conozco el índice del objeto. Algo así como un sobrecargado ...
ExtractedObject: = TheList.Extract (Idx);
... que no existe.
Solución
¿Por qué no solo establece OwnsObjects en falso, realiza su eliminación y luego lo establece en verdadero nuevamente?
Otros consejos
Si observa el código para eliminar, es el método de notificación el que causa la liberación.
Esto debería funcionar:
TMyObjectList = Class(TObjectList)
private
fNotify: Boolean;
{ Private declarations }
procedure EnableNotification;
procedure DisableNotification;
protected
procedure Notify(Ptr: Pointer; Action: TListNotification); override;
public
constructor Create(AOwnsObjects: Boolean);overload;
constructor Create; overload;
function Extract(const idx : Integer) : TObject;
end;
constructor TMyObjectList.Create(AOwnsObjects: Boolean);
begin
inherited Create(AOwnsObjects);
fNotify := True;
end;
constructor TMyObjectList.Create;
begin
inherited Create;
fNotify := True;
end;
procedure TMyObjectList.DisableNotification;
begin
fnotify := False;
end;
procedure TMyObjectList.EnableNotification;
begin
fNotify := True;
end;
function TMyObjectList.Extract(const idx: Integer) : TObject;
begin
Result := Items[idx];
DisableNotification;
try
Delete(idx);
finally
EnableNotification;
end;
end;
procedure TMyObjectList.Notify(Ptr: Pointer; Action: TListNotification);
begin
if fNotify then
inherited;
end;
Aquí es donde los ayudantes de clase pueden ser útiles
TObjectListHelper = class helper for TObjectList
function ExtractByIndex(const AIndex: Integer): TObject;
end;
function TObjectListHelper.ExtractByIndex(const AIndex: Integer): TObject;
begin
Result := Items[AIndex];
if Result<>nil then
Extract(Result);
end;
Ahora puede usar:
MyObjList.ExtractByIndex(MyIndex);
La clase de ayuda propuesta (por Gamecat) dará como resultado la misma búsqueda de la que Thomas quisiera deshacerse.
Si echas un vistazo a la fuente, puedes ver qué hace realmente Extract () y luego usar el mismo enfoque.
Sugeriré algo como esto:
obj := list[idx];
list.list^[idx] := nil; //<- changed from list[idx] := nil;
list.delete(idx);
Esto le dará el objeto, como lo hace Extract (), y luego lo eliminará de la lista, sin ninguna búsqueda. Ahora puede poner esto en un método en algún lugar, una clase auxiliar o subclase o donde quiera.
No uso Delphi / C ++ Builder hace algún tiempo, pero hasta donde puedo recordar esa es la única forma. Mi sugerencia es utilizar un TList en su lugar y eliminar manualmente los objetos cuando sea necesario.
Algo malo con:
ExtractedObject: = TExtractedObject.Create;
ExtractedObject.Assign (Thelist [Idx]);
TheList.Delete (idx);
Se necesita tiempo para crear y asignar, pero no para buscar en la lista. La eficiencia depende del tamaño del objeto -v- el tamaño de la lista.