在Delphi中,在事件中释放发送者是正确的方法吗?

Art*_*ujo 2 delphi pascal

所以,假设我们有一个这样的类:

  TFieldsReadyEvent = procedure(Sender: TObject; Code, AuthorizatedID: string) of object;
  TCatcherServer = class(TServer)
  private
    FOnFieldsReady: TFieldsReadyEvent;
    FCode: string;
    FAuthoID: string;
    FAuthorizationType: TAuthorizationType;
    function GetAuthorizationType: string;
    function GetCode: string;
    function GetEntityID: string;
  public
    property OnFieldsReady: TFieldsReadyEvent read FOnFieldsReady write FOnFieldsReady;
    property Code: string read GetCode;
    property EntityID: string read GetEntityID;
    property AuthorizationType: string read GetAuthorizationType;
    procedure Callback(Session: TIdContext; Req: TIdHTTPRequestInfo; Res: TIdHTTPResponseInfo); override;
  end;
Run Code Online (Sandbox Code Playgroud)

程序Callback如下所示:

procedure TCatcherServer.Callback(Session: TIdContext;
  Req: TIdHTTPRequestInfo; Res: TIdHTTPResponseInfo);
begin
  inherited Callback(Session, Req, Res);
  if (Req.Params.Values['code'] <> '') and ((Req.Params.Values['shop_id'] <> '') or (Req.Params.Values['main_account_id'] <> '')) then
  begin
    Res.ResponseNo := 200;
    Res.ResponseText := '{"message":"continue on the application"}';
    FCode := Req.Params.Values['code'];
    if (Req.Params.Values['shop_id'] <> '') then
    begin
      FAuthorizationType := atShopAuthorization;
      FAuthoID := Req.Params.Values['shop_id'];
    end else
    begin
      FAuthorizationType := atMainAccountAuthorization;
      FAuthoID := Req.Params.Values['main_account_id'];
    end;

    FOnFieldsReady(Self, FCode, FAuthoID);
  end else
  begin
    Res.ResponseNo := 400;
    Res.ResponseText := '{"message":"Something went wrong."}';
  end;
end;
Run Code Online (Sandbox Code Playgroud)

在我的表单中有一个能够释放 TCatcherServer 实例的事件处理程序是正确的方法吗?示例如下:

{Form1 public declarations}
procedure FieldsReadyHandler(Sender: TObject; Code, AuthorizatedID: string);
Run Code Online (Sandbox Code Playgroud)
procedure TForm1.Button1Click(Sender: TObject);
begin
  VarServer := TCatcherServer.Create;
  VarServer.Listen(7070);
  VarServer.OnFieldsReady := FieldsReadyHandler;
end;

procedure TForm1.FieldsReadyHandler(Sender: TObject; Code,
  AuthorizatedID: string);
begin
  ServerLog.Lines.Add(Code);
  ServerLog.Lines.Add(AuthorizatedID);
  ServerLog.Lines.Add((Sender as TCatcherServer).AuthorizationType);

  Sender.Free;
end;
Run Code Online (Sandbox Code Playgroud)

TL;DR在这种情况下使用事件释放发送者是正确的方法吗(触发事件后我得到了我需要的数据并且不再需要发送者)。如果不是,那么正确的做法是什么?

Rem*_*eau 5

Sender将其从其自身事件中释放出来通常是不安全的。您不知道Sender事件处理程序退出后还可能需要访问哪些内容。

举个例子 - 如果所讨论的对象是拥有正在触发您的方法的Sender对象,那么您将尝试释放,从而释放,同时仍在等待退出。由于是一个多线程组件,在工作线程中触发其事件,因此销毁其自己的事件将导致死锁。TIdHTTPServerCallback()SenderTIdHTTPServerTIdHTTPServerCallback()TIdHTTPServerOnCommand...TIdHTTPServer

如果必须释放Sender,则应该异步执行此操作,以便为调用者/RTL 提供额外的时间来完成使用Sender。例如,通过使用TThread.Queue(nil, Sender.Free);(只需注意TThread.Queue()在主线程中运行其谓词,因此请确保Sender在此示例中您的销毁是线程安全的)。

  • “Release()”仅适用于“TForm”,本例中的“Sender”不是“TForm”,而是“TCatcherServer”。此外,“TForm.Release()”只能在主线程上下文中安全调用,而不能在工作线程中安全调用,因为它使用了线程不安全的“TForm.Handle”属性 getter。 (4认同)