delphi 如何访问Tag属性

gtlvzcf8  于 2022-12-18  发布在  其他
关注(0)|答案(3)|浏览(193)

我怎样才能访问先前从HTTPRIO.OnBeforeExecute事件中分配的HTTPRIO.Tag?可以吗?
假设我有这样的东西:

procedure TForm1.HTTPRIO1BeforeExecute(const MethodName: string; SOAPRequest: TStream);
begin
  if THHPRIO(Sender).Tag = 99 then
    ...some code...
end;

但是我在任何THTTPRIO事件上都没有Sender

wfypjpf4

wfypjpf41#

由于您要将事件分配给多个THTTPRIO对象,但无法访问事件中的Sender参数(THTTPRIO作者的设计不佳),因此一种解决方法是使用TMethod record操作事件处理程序的Self指针,使其指向THTTPRIO对象而不是TForm1对象,例如:

procedure TForm1.FormCreate(Sender: TObject);
var
  M: TBeforeExecuteEvent;
begin
  M := HTTPRIOBeforeExecute;
  TMethod(M).Data := HTTPRIO1;
  HTTPRIO1.OnBeforeExecute := M;

  M := HTTPRIOBeforeExecute;
  TMethod(M).Data := HTTPRIO2;
  HTTPRIO2.OnBeforeExecute := M;

  // and so on ...
end;

然后,您可以在事件内部对Self进行类型转换,例如:

procedure TForm1.HTTPRIOBeforeExecute(const MethodName: string; SOAPRequest: TStream);
begin
  if THTTPRIO(Self).Tag = 99 then
    ...some code...
end;

或者,您可以使用独立过程(或class static方法),并为Self指针指定显式参数,例如:

procedure HTTPRIOBeforeExecute(Sender: THTTPRIO; const MethodName: string; SOAPRequest: TStream);
begin
  if Sender.Tag = 99 then
    ...some code...
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  M: TBeforeExecuteEvent;
begin
  TMethod(M).Data := HTTPRIO1;
  TMethod(M).Code := @HTTPRIOBeforeExecute;
  HTTPRIO1.OnBeforeExecute := M;

  TMethod(M).Data := HTTPRIO2;
  TMethod(M).Code := @HTTPRIOBeforeExecute;
  HTTPRIO2.OnBeforeExecute := M;

  // and so on ...
end;

qyzbxkaa

qyzbxkaa2#

虽然雷米的解决方案有效,但将代码留在TForm1中会使您面临在TForm1.HTTPRIOBeforeExecute中意外引用TForm1中的字段的风险,而且由于“Self”不再是TForm 1,这将导致内存崩溃/损坏。
我个人会使用以下方法:

THTTPRIOMethodHolder = class(THTTPRIO)
public
  procedure HTTPRIOBeforeExecute(const MethodName: string; SOAPRequest: TStream);
end;

procedure THTTPRIOMethodHolder.HTTPRIOBeforeExecute(const MethodName: string; SOAPRequest: TStream);
begin
  if {self.}Tag = 99 then
    ...some code...
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  HTTPRIO1.OnBeforeExecute := THTTPRIOMethodHolder(HTTPRIO1).HTTPRIOBeforeExecute;
  HTTPRIO2.OnBeforeExecute := THTTPRIOMethodHolder(HTTPRIO2).HTTPRIOBeforeExecute;
end;

只要您不在THTTPRIOMethodHolder中添加字段,并且HTTPRIOBeforeExecute不是虚拟的,这就可以工作。

hrirmatl

hrirmatl3#

实际上,我并没有将代码留在TForm1中。我做了如下操作:

type
  THTTPRIO_EventHandlers_v2 = Class
    procedure HTTPRIOBeforeExecute(const MethodName: String; SOAPRequest: TStream);
    procedure HTTPRIOAfterExecute(const MethodName: string; SOAPResponse: TStream);
  end;
    
  type
    THTTPRIOBeforeExecute = procedure(const MethodName: String; SPRequest: TStream) of Object;
      THTTPRIOAfterExecute = procedure(const MethodName: string; SOAPResponse: TStream) of Object;
    
  var
    HTTPRIO: THTTPRIO;
    
  procedure TForm1.Button1Click(Sender: TObject)
  var
    RIO_Events: THTTPRIO_EventHandlers_v2;
    EvtHTTPRIOBeforeExecute: THTTPRIOBeforeExecute;
    EvtHTTPRIOAfterExecute: THTTPRIOAfterExecute;
  begin
    HTTPRIO := THTTPRIO.Create(Application);
    HTTPRIO.Tag := 99;
    HTTPRIO.Converter.Encoding := 'utf-8';
    
    RIO_Events := THTTPRIO_EventHandlers_v2.Create;
    
    EvtHTTPRIOBeforeExecute := RIO_Events.HTTPRIOBeforeExecute;
    TMethod(EvtHTTPRIOBeforeExecute).Data := HTTPRIO;
    HTTPRIO.OnBeforeExecute := EvtHTTPRIOBeforeExecute;
    
    EvtHTTPRIOAfterExecute := RIO_Events.HTTPRIOAfterExecute;
    TMethod(EvtHTTPRIOAfterExecute).Data := HTTPRIO;
    HTTPRIO.OnAfterExecute := EvtHTTPRIOAfterExecute;
    
    RIO_Events.Free;
  end;

例如,在HTTPRIOBeforeExecute过程中,我这样做:

procedure THTTPRIO_EventHandlers_v2.HTTPRIOBeforeExecute(const MethodName: String; SOAPRequest: TStream);
var
  HttpRioTag: Integer;
begin
  HttpRioTag := THTTPRIO(Self).Tag;
  if HttpRioTag = 99 then
    ...some code...
end;

这正如预期的那样工作。我这样做对吗?谢谢

相关问题