我想在构造函数中分配一个事件处理程序,如果它没有分配一个。因此,我想在析构函数中删除最终分配的事件处理程序。我写的代码如下,但无法编译
constructor TSomeControl.Create(Panel: TPanel);
begin
inherited Create;
FPanel := Panel;
if not Assigned(FPanel.OnResize) then
FPanel.OnResize := HandlePanelResize;
end;
destructor TSomeControl.Destroy;
begin
if @FPanel.OnResize = @HandlePanelResize then // [dcc32 Error] E2036 Variable required
FPanel.OnResize := nil;
FPanel := nil;
inherited;
end;
如何正确测试?我知道一个解决方案是使用一个变量来记录,我是否已经分配了OnResize
。
这里不需要编写任何自定义代码,因为您可以使用Generics.Defaults
中已经存在的比较器:
destructor TSomeControl.Destroy;
begin
if Assigned(FPanel) and TEqualityComparer<TNotifyEvent>.Default.Equals(
FPanel.OnResize, HandlePanelResize) then
FPanel.OnResize := nil;
FPanel := nil;
inherited;
end;
OnResize
是一个属性而不是一个变量,这使得情况更加复杂。直接引用一个方法而不让编译器认为你想调用这个方法是很困难的。这是Pascal的一大缺点,它允许您在不使用父类的情况下调用过程。
所有这些使得在一行代码中完成它相当困难。在我看来,您需要做这样的事情:
destructor TSomeControl.Destroy;
var
Method1, Method2: TNotifyEvent;
begin
if Assigned(FPanel) then
begin
Method1 := FPanel.OnResize;
Method2 := HandlePanelResize;
if TMethod(Method1) = TMethod(Method2) then
FPanel.OnResize := nil;
end;
FPanel := nil;
inherited;
end;
这依赖于现代Delphi的TMethod
记录,该记录包含一个重载相等运算符以使=
测试工作。
如果我不止一次这样做,我会把这些都包装在一个泛型方法中。它可能看起来像这样:
type
TEventComparer = class
class function Equal<T>(const lhs, rhs: T): Boolean; static;
end;
class function TEventComparer.Equal<T>(const lhs, rhs: T): Boolean;
begin
Assert(SizeOf(T)=SizeOf(TMethod));
Result := TMethod((@lhs)^)=TMethod((@rhs)^);
end;
你可以这样称呼它:
destructor TSomeControl.Destroy;
begin
if Assigned(FPanel) and TEventComparer.Equal<TNotifyEvent>(FPanel.OnResize,
HandlePanelResize) then
FPanel.OnResize := nil;
FPanel := nil;
inherited;
end;
这里强调的一件事是,可用的泛型约束不允许将类型约束为方法指针。因此,基本的完整性检查是T
的大小与方法的大小相同。但这并不能提供多少安全保障。你可以通过传递Int64
或Double
来调用这个方法。我很想看看是否有人能想出一个更简洁的版本
根本不需要使用Generics.Defaults
或任何泛型。在System
单元中声明了TMethod
记录,所以这可能是最简单的一个:
destructor TSomeControl.Destroy;
var
Event: TNotifyEvent;
begin
Event := HandlePanelResize;
if TMethod(FPanel.OnResize).Code = Addr(Event) then
FPanel.OnResize := nil;
FPanel := nil;
inherited;
end;