delphi – 意外的隐式接口变量的神秘案例

前端之家收集整理的这篇文章主要介绍了delphi – 意外的隐式接口变量的神秘案例前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我最近遇到了一些我无法解释的行为,与Delphi接口变量有关.

从本质上讲,它归结为编译器在Broadcast方法生成的隐式接口变量.

在终止方法的结束语句中,结尾代码包含对IntfClear的两次调用.其中一个我可以解释,它对应于Listener局部变量.另一个我无法解释,它会在对象实例被销毁后将你带到TComponent._Release(Debug DCUs).它不会产生AV,但这很幸运,并且通过完整的FastMM调试,报告了破坏后实例访问.

这是代码

program UnexpectedImplicitInterfaceVariable;

{$APPTYPE CONSOLE}

uses
  SysUtils,Classes;

type
  IListener = interface
    ['{6D905909-98F6-442A-974F-9BF5D381108E}']
    procedure HandleMessage(Msg: Integer);
  end;

  TListener = class(TComponent,IListener)
  //TComponent._AddRef and TComponent_Release return -1
  private
    procedure HandleMessage(Msg: Integer);
  end;

{ TListener }

procedure TListener.HandleMessage(Msg: Integer);
begin
end;

type
  TBroadcaster = class
  private
    FListeners: IInterfaceList;
    FListener: TListener;
  public
    constructor Create;
    procedure Broadcast(Msg: Integer);
  end;

constructor TBroadcaster.Create;
begin
  inherited;
  FListeners := TInterfaceList.Create;
  FListener := TListener.Create(nil);
  FListeners.Add(FListener);
end;

procedure TBroadcaster.Broadcast(Msg: Integer);
var
  i: Integer;
  Listener: IListener;
begin
  for i := 0 to FListeners.Count-1 do
  begin
    Listener := FListeners[i] as IListener;
    Listener.HandleMessage(Msg);
  end;
  Listener := nil;

  FListeners.Clear;
  FreeAndNil(FListener);
end;//method epilogue: why is there a call to IntfClear and then TComponent._Release?

begin
  with TBroadcaster.Create do
  begin
    Broadcast(42);
    Free;
  end;
end.

以下是结语的反汇编:

在那里,明确的是对IntfClear的两次调用.

那么,谁可以看到我遗漏的明显解释?

UPDATE

好吧,Uwe马上得到它. FListeners [i]的结果变量需要一个临时隐式变量.我没有看到,因为我分配给Listener,但当然这是一个不同的变量.

以下变体是编译器为原始代码生成内容的显式表示.

procedure TBroadcaster.Broadcast(Msg: Integer);
var
  i: Integer;
  Intf: IInterface;
  Listener: IListener;
begin
  for i := 0 to FListeners.Count-1 do
  begin
    Intf := FListeners[i];
    Listener := Intf as IListener;
    Listener.HandleMessage(Msg);
  end;
  Listener := nil;

  FListeners.Clear;
  FreeAndNil(FListener);
end;

当以这种方式书写时,显然Intf无法在结尾之前被清除.

解决方法

只是一个猜测,但也许作为IListener的FListeners [i]使用FListeners [i]的临时变量.毕竟它是函数调用的结果.

猜你在找的Delphi相关文章