所以,假设我们有一堂这样的课程:
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;
其中
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;
在我的表单中包含一个能够释放 TCatcherServer 实例的事件处理程序是正确的方法吗?示例如下:
{Form1 public declarations}
procedure FieldsReadyHandler(Sender: TObject; Code, AuthorizatedID: string);
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;
TL;DR 在这种情况下使用事件释放发送者是否是正确的方法(在事件触发后,我获得了所需的数据并且不再需要发送者)。如果不是,正确的做法是什么?
将
Sender
从其自己的事件中释放通常是不安全的。您不知道事件处理程序退出后还可能需要什么来访问 Sender
。
举个例子 - 如果所讨论的
Sender
是拥有 TIdHTTPServer
的对象,而该对象正在触发您的 Callback()
方法,那么您将尝试释放 Sender
,从而释放 TIdHTTPServer
,而 TIdHTTPServer
仍在等待 Callback()
退出。这会导致僵局。
如果必须释放
Sender
,则应异步执行此操作,以便为调用者/RTL 提供额外的时间来完成对 Sender
的使用。例如,通过使用 TThread.Queue(nil, Sender.Free);
请注意,TIdHTTPServer
在工作线程中触发其 OnCommand...
事件,但 TThread.Queue()
在主线程中运行其谓词,因此请确保 Sender
的销毁是线程-安全。