Pergunta

Recentemente, tropeçou em um problema causado por algum código muito antigo que eu escrevi que foi, obviamente, assumindo que as referências interface utilizados em um comunicado with seria liberado tão logo o with-block é deixado - como uma espécie de try-finally-block implícita (semelhante ao using-statement 's C # se eu entendi corretamente).

Aparentemente (em Delphi 2009), este não é (não?) O caso. Alguém sabe quando isso aconteceu? Ou era o meu código apenas errado liso para começar?

Para esclarecer, aqui está um exemplo simplificado:

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

Sempre que alguém começou o velho "with é mal" argumento este era sempre o exemplo que eu tinha em mente o que me manteve "Sim, mas ...". Parece que eu estava errado ... Alguém pode confirmar?

Foi útil?

Solução

A palavra preservada with em Pascal / Delphi só é usado para acessar facilmente os membros de registros ou objetos / classes (ou seja, a fim de não mencionar o nome de do registro / objeto da classe /). É muito diferente do # with C que se relaciona com a coleta de lixo. Tem existido na linguagem Pascal desde o records dia nasceram, para simplificar o código chamando a muitos membros de dados (na época chamado simplesmente de "campos").

Para resumir, with não tem nada a ver com a coleta de lixo, liberação de memória ou destruição de objeto instâncias. Objetos que são construídos no cabeçalho with apenas poderia ter sido inicializado em uma linha de código separado antes, é o mesmo.

Outras dicas

Este COM-comportamento nunca mudou. Para chegar ao seu comportamento esperado pode alterar o código da seguinte maneira:

    procedure TestIt;
    var
       myIntf: IMyIntf; 
    begin
      DoSomething;

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

      DoSomethingElse;
    end; 

ou você pode fazê-lo no procedimento:

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; 
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top