在 Delphi 中,如何在基础 class 及其后代 classes 中启用方法指针 属性
In Delphi, how do I enable a method pointer property in both a base class and its descendant classes
我想创建一个 TService
后代 class 作为我的 Windows 服务实现的基础。在我的基础 class 中,我正在引入一个已发布的 ServiceDescription
属性,并且我正在使用 AfterInstall
事件处理程序将此描述写入 [=56= 中的适当位置] 注册表。
请注意,由于 TServer
class(在 Vcl.SvcMgr
中声明)是 TDataModule
后代,为了允许 ServiceDescription
属性 要在对象检查器中可见,必须在设计时包中声明此基 class,并使用对 RegisterCustomModule
的调用将其注册到 Delphi。此外,此基础 class 的后代必须由 OTA(打开工具 api)向导或某种代码生成器(.pas 和 .dfm 文件)生成。没问题,我已经整理好了,如果您有兴趣,可以从 Marco Cantu 的书中阅读更多相关信息 (http://www.marcocantu.com/ddh/ddh15/ddh15e.htm)。
我被卡住的地方是我想使用我的基础 class 中的 AfterInstall
事件处理程序写入注册表,并使用 AfterUninstall
删除它,但是我想确保我的后代 classes 也将支持 AfterInstall
和 AfterUninstall
事件。
我之前从 Ray Konopka 那里了解到,如果你想重新引入一个 属性,你必须在后代 class 中使用访问器方法。因此,这是一个代码段,代表我对 AfterInstall
事件所做的尝试:
private
// field to store method pointer for the descendant AfterInstall event handler
FFAfterInstall: TServiceEvent;
…
protected
function GetAfterInstall: TServiceEvent;
procedure SetAfterInstall( value: TServiceEvent );
…
published
property AfterInstall: TServiceEvent read GetAfterInstall write SetAfterInstall;
我重写的构造函数为继承的 AfterInstall
属性:
分配了一个方法
constructor TTPMBaseService.Create(AOwner: TComponent);
begin
inherited;
// Hook-up the AfterInstall event handlers
Self.AfterInstall := CallAfterInstall;
…
end;
在我 CallAfterInstall
的实现中,在我 运行 我的代码写入 Windows 注册表后,我测试是否已将方法指针分配给我的本地方法指针字段,如果是这样,我就调用它。它看起来像这样:
procedure TTPMBaseService.CallAfterInstall(Service: TService);
var
Reg: TRegistry;
begin
// Code here to write to the Windows Registry is omitted
// Test if our method pointer field has been written to
if Assigned( FFAfterInstall ) then
FFAfterInstall( Service ); // call the method,
…
end;
我认为这一切都很有道理,而且我认为它应该可行。但是,我坚持访问器方法。 Get 访问器方法编译得很好,这里是:
function TTPMBaseService.GetAfterInstall: TServiceEvent;
begin
Result := FFAfterInstall;
end;
但是我的 SetAfterInstall
方法引发了编译时异常,报告没有足够的参数:
procedure TTPMBaseService.SetAfterInstall( value: TServiceEvent );
begin
if value <> FFAfterInstall then
FFAfterInstall := value;
end;
我不知道该做什么。我做了以下更改,它编译了,但它似乎没有完成这项工作:
procedure TTPMBaseService.SetAfterInstall( value: TServiceEvent);
begin
if @value <> @FFAfterInstall then
@FFAfterInstall := @value;
end;
我有两个问题。首先是,我是否采用了正确的方法来重新引入事件处理程序,同时确保我的基础 class 及其后代都支持此事件?如果我的逻辑是正确的,那么 Setter 访问器方法我做错了什么?
Am I taking the correct approach to reintroducing an event handler?
可能是的。由于 TService
class 的笨拙设计,您无法覆盖引发事件的方法。
What am I doing wrong with the Setter accessor method?
问题实际上出在您的构造函数中:
constructor TTPMBaseService.Create(AOwner: TComponent);
begin
inherited;
// Hook-up the AfterInstall event handlers
Self.AfterInstall := CallAfterInstall;
…
end;
其中的注释表明您正在设置继承的事件处理程序,但这不是注释下面的代码所做的。尽管分配给 Self.AfterInstall
,但您正在设置重新引入的值 属性。这就是您设置继承 属性:
的方式
constructor TTPMBaseService.Create(AOwner: TComponent);
begin
inherited;
// Hook-up the AfterInstall event handlers
inherited AfterInstall := CallAfterInstall;
…
end;
But my SetAfterInstall method raises a compile-time exception, reporting that there are not enough parameters.
准确地说,setter 方法中的 if
语句出现语法错误。这只是因为这不是您在 Delphi 中比较方法引用的方式。参见 How to check if two events are pointing to the same procedure in Delphi。为什么你甚至需要进行这样的比较?您可以放心地省略它。
我想创建一个 TService
后代 class 作为我的 Windows 服务实现的基础。在我的基础 class 中,我正在引入一个已发布的 ServiceDescription
属性,并且我正在使用 AfterInstall
事件处理程序将此描述写入 [=56= 中的适当位置] 注册表。
请注意,由于 TServer
class(在 Vcl.SvcMgr
中声明)是 TDataModule
后代,为了允许 ServiceDescription
属性 要在对象检查器中可见,必须在设计时包中声明此基 class,并使用对 RegisterCustomModule
的调用将其注册到 Delphi。此外,此基础 class 的后代必须由 OTA(打开工具 api)向导或某种代码生成器(.pas 和 .dfm 文件)生成。没问题,我已经整理好了,如果您有兴趣,可以从 Marco Cantu 的书中阅读更多相关信息 (http://www.marcocantu.com/ddh/ddh15/ddh15e.htm)。
我被卡住的地方是我想使用我的基础 class 中的 AfterInstall
事件处理程序写入注册表,并使用 AfterUninstall
删除它,但是我想确保我的后代 classes 也将支持 AfterInstall
和 AfterUninstall
事件。
我之前从 Ray Konopka 那里了解到,如果你想重新引入一个 属性,你必须在后代 class 中使用访问器方法。因此,这是一个代码段,代表我对 AfterInstall
事件所做的尝试:
private
// field to store method pointer for the descendant AfterInstall event handler
FFAfterInstall: TServiceEvent;
…
protected
function GetAfterInstall: TServiceEvent;
procedure SetAfterInstall( value: TServiceEvent );
…
published
property AfterInstall: TServiceEvent read GetAfterInstall write SetAfterInstall;
我重写的构造函数为继承的 AfterInstall
属性:
constructor TTPMBaseService.Create(AOwner: TComponent);
begin
inherited;
// Hook-up the AfterInstall event handlers
Self.AfterInstall := CallAfterInstall;
…
end;
在我 CallAfterInstall
的实现中,在我 运行 我的代码写入 Windows 注册表后,我测试是否已将方法指针分配给我的本地方法指针字段,如果是这样,我就调用它。它看起来像这样:
procedure TTPMBaseService.CallAfterInstall(Service: TService);
var
Reg: TRegistry;
begin
// Code here to write to the Windows Registry is omitted
// Test if our method pointer field has been written to
if Assigned( FFAfterInstall ) then
FFAfterInstall( Service ); // call the method,
…
end;
我认为这一切都很有道理,而且我认为它应该可行。但是,我坚持访问器方法。 Get 访问器方法编译得很好,这里是:
function TTPMBaseService.GetAfterInstall: TServiceEvent;
begin
Result := FFAfterInstall;
end;
但是我的 SetAfterInstall
方法引发了编译时异常,报告没有足够的参数:
procedure TTPMBaseService.SetAfterInstall( value: TServiceEvent );
begin
if value <> FFAfterInstall then
FFAfterInstall := value;
end;
我不知道该做什么。我做了以下更改,它编译了,但它似乎没有完成这项工作:
procedure TTPMBaseService.SetAfterInstall( value: TServiceEvent);
begin
if @value <> @FFAfterInstall then
@FFAfterInstall := @value;
end;
我有两个问题。首先是,我是否采用了正确的方法来重新引入事件处理程序,同时确保我的基础 class 及其后代都支持此事件?如果我的逻辑是正确的,那么 Setter 访问器方法我做错了什么?
Am I taking the correct approach to reintroducing an event handler?
可能是的。由于 TService
class 的笨拙设计,您无法覆盖引发事件的方法。
What am I doing wrong with the Setter accessor method?
问题实际上出在您的构造函数中:
constructor TTPMBaseService.Create(AOwner: TComponent);
begin
inherited;
// Hook-up the AfterInstall event handlers
Self.AfterInstall := CallAfterInstall;
…
end;
其中的注释表明您正在设置继承的事件处理程序,但这不是注释下面的代码所做的。尽管分配给 Self.AfterInstall
,但您正在设置重新引入的值 属性。这就是您设置继承 属性:
constructor TTPMBaseService.Create(AOwner: TComponent);
begin
inherited;
// Hook-up the AfterInstall event handlers
inherited AfterInstall := CallAfterInstall;
…
end;
But my SetAfterInstall method raises a compile-time exception, reporting that there are not enough parameters.
准确地说,setter 方法中的 if
语句出现语法错误。这只是因为这不是您在 Delphi 中比较方法引用的方式。参见 How to check if two events are pointing to the same procedure in Delphi。为什么你甚至需要进行这样的比较?您可以放心地省略它。