Delphi 以这种方式删除和重新分配事件是否安全?若否,原因为何?

Delphi 以这种方式删除和重新分配事件是否安全?若否,原因为何?,delphi,Delphi,它会出毛病吗 编辑: 我接受了Barry的答案,因为它完全回答了我的问题,但Vegar的答案也正确,这取决于具体情况,遗憾的是,我不能同时接受这两个答案。这完全取决于标记为“…”的代码位中发生了什么。例如,如果它启动后台线程,并在继续执行到finally块后尝试调用Event1或Event2,则可能会得到意外的结果 如果代码完全是单线程的,那么是的,当代码处于try和finally之间时,不应触发Event1和Event2 但是,这确实假设Event1和Event2属性(所有Delphi事件都是

它会出毛病吗

编辑:


我接受了Barry的答案,因为它完全回答了我的问题,但Vegar的答案也正确,这取决于具体情况,遗憾的是,我不能同时接受这两个答案。

这完全取决于标记为“…”的代码位中发生了什么。例如,如果它启动后台线程,并在继续执行到finally块后尝试调用Event1或Event2,则可能会得到意外的结果

如果代码完全是单线程的,那么是的,当代码处于try和finally之间时,不应触发Event1和Event2

但是,这确实假设Event1和Event2属性(所有Delphi事件都是方法指针类型的属性)在其setter中不会执行异常操作。具有病态恶意的事件设置程序可能会隐藏一个方法指针,并且仍然能够调用它,即使稍后您使用“nil”作为值调用该设置程序


但那将是非常不寻常的行为。

这听起来像是我以前见过的一场噩梦:-)

我通常设置一个标记,以便在事件中进行检查,而不是删除事件。我经常使用整数而不是布尔值,以便在一次处理中多次设置同一标志

大概是这样的:

A.Event1 := nil;
A.Event2 := nil;
try
  ...
finally
  A.Event1 := MyEvent1;
  A.Event2 := MyEvent2;
end;

我想这可以很容易地使线程安全,以解决Barry的问题。

正如Barry所说,唯一真正的问题是多线程问题——而不是完全正常的问题。由于VCL事件设置程序只分配事件,因此无需担心。

如果是多线程的,则需要使操作原子化。禁用多个事件处理程序可能会导致它们正在运行,然后被禁用。或当Event1设置为nil时,Event2启动。如果经常调用这些事件,可能会发生各种故障。可能的解决方案是使用信号量。但是,您可能还需要向事件处理程序添加额外的代码


任何将事件处理程序临时设置为nil的方法看起来都是糟糕的设计。这很快就会让人难以理解,也很难让人以任何方式去做它必须做的事情。因此,您最好花些时间开发更复杂的东西。

实际上,我只是删除ClientDataSet的OnBeforePost和OnAfterPost事件,因为我需要遍历它,下一个方法调用Post,这会导致堆栈溢出。我在这种情况下也使用了这种方法,因为我喜欢在设计时分配事件,并希望它们保持这种状态;-)
procedure TMyObject.Traverse;
begin
  inc(FTraverseFlag);
  try
    ...
  finally
    dec(FTracerseFlag);
  end;
end;

procedure TMyObject.OnBefore( ... );
begin
  if FTraverseFlag > 0 then 
    exit;
  ...
end;