Извлечь объект из TObjectList

У меня есть TObjectList с OwnsObjects = true. Он содержит довольно много объектов. Теперь я хочу удалить объект с индексом Idx из этого списка, не освобождая его.

Является ли метод Extract единственным вариантом?

ExtractedObject := TheList.Extract(TheList[Idx]);

Все остальные методы, кажется, освобождают объект. Я ищу что-то более эффективное, которое не выполняет линейный поиск каждый раз, так как я уже знаю индекс объекта. Что-то вроде перегрузки...

ExtractedObject := TheList.Extract(Idx);

... которого не существует

6 ответов

Решение

Почему бы просто не установить для OwnsObjects значение false, выполнить удаление, а затем снова установить для него значение true?

Здесь помощники класса могут быть полезны

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;

Теперь вы можете использовать:

MyObjList.ExtractByIndex(MyIndex);

Предложенный вспомогательный класс (от Gamecat) приведет к тому же поиску, от которого Томас хотел бы избавиться.

Если вы посмотрите на источник, вы можете увидеть, что действительно делает Extract(), и затем использовать тот же подход.

Я предложу что-то вроде этого:

obj := list[idx];
list.list^[idx] := nil;  //<- changed from list[idx] := nil;
list.delete(idx);

Это даст вам объект, как это делает Extract(), а затем удалит его из списка без поиска. Теперь вы можете поместить это в какой-нибудь метод helperclass или subclass, или когда захотите.

Если вы посмотрите на код для удаления, это метод notify, который вызывает освобождение.

Это должно работать:

  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;

Что-то не так с:

ExtractedObject: = TExtractedObject.Create;
ExtractedObject.Assign (Thelist [Idx]);
TheList.Delete (IDX);

Существует время, необходимое для создания и назначения, но не для поиска в списке. Эффективность зависит от размера объекта -v- размера списка.

Некоторое время назад я не использую Delphi/C++Builder, но насколько я могу судить, это единственный способ. Я предлагаю вместо этого использовать TList и вручную удалять объекты, когда это необходимо.

Другие вопросы по тегам