Delphi: С каких это пор ссылки на интерфейсы больше не выпускаются в конце блока with? - PullRequest
4 голосов
/ 05 августа 2009

Недавно я наткнулся на проблему, вызванную каким-то очень старым кодом, который я написал, который явно предполагал, что ссылки на интерфейсы, используемые в операторе with, будут освобождены, как только останется with -блок - вроде как неявный try-finally -блок (аналогично using -состоянию C #, если я правильно понял).

По-видимому (в Delphi 2009) это не так (уже не так). Кто-нибудь знает, когда это произошло? Или мой код был просто неправильным для начала?

Чтобы пояснить, вот упрощенный пример:

type
  IMyIntf = interface;
  TSomeObject = class(TInterfacedObject, IMyIntf)
  protected
    constructor Create; override; // creates some sort of context
    destructor Destroy; override; // cleans up the context created in Create
  public
    class function GetMyIntf: IMyIntf; //a factory method, calling the constructor
  end;

procedure TestIt;
begin
  DoSomething;
  with (TSomeObject.GetMyIntf) do
    begin
      DoStuff;
      DoMoreStuff;
    end; // <- expected: TSomeObject gets destroyed because its ref.count is decreased to 0
  DoSomethingElse;
end; // <- this is where TSomeObject.Destroy actually gets called

Всякий раз, когда кто-то начинал старый аргумент "with является злом", это всегда был единственный пример, который я имел в виду, который заставлял меня говорить "Да, но ...". Похоже, я был неправ ... Кто-нибудь может подтвердить?

Ответы [ 2 ]

17 голосов
/ 05 августа 2009

Сохраненное слово with в Pascal / Delphi используется только для легкого доступа к членам записей или объектов / классов (то есть, чтобы не упоминать имя записи / объекта / класса). Это очень отличается от C # with, что касается сборки мусора. Он существует на языке Pascal со дня рождения records, чтобы упростить вызов кода для многих членов данных (тогда их просто называли «полями»).

Подводя итог, with не имеет ничего общего с сборкой мусора, освобождением памяти или уничтожением экземпляров объектов. Объекты, которые сконструированы в заголовке with, могли бы просто быть инициализированы в отдельной строке кода раньше, это то же самое.

3 голосов
/ 05 августа 2009

Это WITH-поведение никогда не менялось. Чтобы достичь ожидаемого поведения, вы можете изменить свой код следующим образом:

    procedure TestIt;
    var
       myIntf: IMyIntf; 
    begin
      DoSomething;

      myIntf := TSomeObject.GetMyIntf
      DoStuff;
      DoMoreStuff;
      myIntf := nil; // <- here is where TSomeObject.Destroy called

      DoSomethingElse;
    end; 

или вы можете сделать это в процедуре:

procedure TestIt;

   procedure DoAllStuff;
   var
      myIntf: IMyIntf; 
   begin
      myIntf := TSomeObject.GetMyIntf
      DoStuff;
      DoMoreStuff;
   end;  // <- here is where TSomeObject.Destroy called

begin    
  DoSomething;
  DoAllStuff;
  DoSomethingElse;
end; 
...