gpt4 book ai didi

delphi - 方法指针和常规过程不兼容

转载 作者:行者123 更新时间:2023-12-03 14:36:03 25 4
gpt4 key购买 nike

我有一个应用程序,它有多种形式。所有这些窗体都有一个弹出菜单。我以编程方式构建菜单项,全部位于公共(public)根菜单项下。我希望所有菜单项都调用相同的过程,并且菜单项本身基本上充当参数......

当我只有一个表单执行此功能时,我就可以使用此功能。我现在有多种表格需要执行此操作。我正在将所有代码移动到一个公共(public)单元。

Example.
Form A has PopupMenu 1. When clicked, call code in Unit CommonUnit.
Form B has PopupMenu 2. When clicked, call code in unit CommonUnit.

当我需要从每个表单调用弹出窗口时,我调用顶级过程(位于 CommonUnit 单元中),将每个表单的顶部菜单项的名称传递到公共(public)单元中的顶级过程。

我正在使用代码将项目添加到我的 PopupMenu 中。

M1 := TMenuItem.Create(TopMenuItem);
M1.Caption := FieldByName('NAME').AsString;
M1.Tag := FieldByName('ID').AsInteger;
M1.OnClick := BrowseCategories1Click;
TopMenuItem.Add(M1);

我在编译时收到错误消息。具体来说,OnClick 行正在提示

不兼容的类型:“方法指针和常规过程”。

我已经定义了 BrowseCategories1Click ,就像我以前在单个表单上执行此操作时一样。唯一的区别是它现在是在通用单元中定义的,而不是作为表单的一部分。

定义为

procedure BrowseCategories1Click(Sender: TObject);
begin
//
end;

解决这个问题最简单的方法是什么?

谢谢GS

最佳答案

一些背景...

Delphi 有 3 种程序类型:

  • 独立或单位范围的函数/过程指针声明如下:

    var Func: function(arg1:string):string;
    var Proc: procedure(arg1:string);

  • 方法指针声明如下:

    var Func: 函数(arg1:string):对象字符串;
    var Proc: 对象的过程(arg1:string);

  • 而且,自 Delphi 2009 以来,匿名(见下文)函数/方法指针声明如下:

    var Func:对函数(arg1:string):string的引用;
    var Proc:对 procedure(arg1:string) 的引用;

独立指针和方法指针不可互换。其原因是可以在方法中访问隐式 Self 参数。 Delphi 的事件模型依赖于方法指针,这就是为什么您不能将独立函数分配给对象的事件属性。

因此,您的事件处理程序必须定义为某些类定义、任何类定义的一部分,以安抚编译器。

正如 TOndrej 建议的那样,您可以绕过编译器,但如果这些事件处理程序位于同一单元中,那么它们应该已经相关了,因此您也可以继续将它们包装到一个类中。

我还没有看到的另一个建议是稍微回溯一下。让每个表单实现自己的事件处理程序,但让该处理程序将责任委托(delegate)给新单元中声明的函数。

TForm1.BrowseCategoriesClick(Sender:TObject)
begin
BrowseCategories;
end;

TForm2.BrowseCategoriesClick(Sender:TObject)
begin
BrowseCategories;
end;
<小时/>
unit CommonUnit

interface
procedure BrowseCategories;
begin
//
end;

这还有一个额外的好处,将对用户操作的响应与触发该操作的控件分开。您可以轻松地将工具栏按钮和弹出菜单项的事件处理程序委托(delegate)给同一函数。

您选择哪个方向最终取决于您,但我建议您关注哪个选项将使将来的可维护性更容易,而不是当前最方便的选项。


匿名方法

匿名方法是一种完全不同的野兽。匿名方法指针可以指向独立函数、方法或声明为内联的未命名函数。最后一个函数类型是他们获得名称“anonymous”的来源。匿名函数/方法具有捕获在其范围之外声明的变量的独特能力

function DoFunc(Func:TFunc<string>):string
begin
Result := Func('Foo');
end;

// elsewhere
procedure CallDoFunc;
var
MyString: string;
begin
MyString := 'Bar';
DoFunc(function(Arg1:string):string
begin
Result := Arg1 + MyString;
end);
end;

这使它们成为最灵活的过程指针类型,但它们也可能具有更多的开销。变量捕获与内联声明一样会消耗额外的资源。编译器对内联声明使用隐藏的引用计数接口(interface),这会增加一些小的开销。

关于delphi - 方法指针和常规过程不兼容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11314641/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com