我花了很长时间才找到答案,但没有找到任何答案。我正在尝试将带有数据的回调传递给函数。
这是我的伪代码:
TGetFreeNumber = function(data: Pointer): integer;
procedure TMyClass.AddToDatabase(cb: TGetFreeNumber{???});
var
num: integer;
begin
num := {{Invoke cb with parameters}};
// INSERT INTO ... VALUES num ...
end;
procedure TMyClass.impl1(from, till: integer);
function myCB(data: Pointer);
begin
result := 123;
end;
begin
AddToDatabase(@myCB(someData){???});
end;
procedure TMyClass.impl2(from, till: integer);
function myCB(data: Pointer);
begin
result := 456;
end;
begin
AddToDatabase(@myCB(someData){???});
end;
我用TMethod做了一些实验,但我找不到像
这样的拟合Invoke方法procedure TMyClass.AddToDatabase(cb: TMethod);
var
num: integer;
begin
num := Invoke(cb.Code, cb.Data);
// INSERT INTO ... VALUES num ...
end;
答案 0 :(得分:4)
您需要进行两项更改。您的AddToDatabase
方法需要接受回调参数以及回调方法本身。这是必需的,以便它可以在调用它时将它们传递给回调。
procedure TMyClass.AddToDatabase(cb: TGetFreeNumber; data: Pointer);
var
num: integer;
begin
num := cb(data);
// INSERT INTO ... VALUES num ...
end;
并且您还必须不使用嵌套函数进行回调。引用嵌套函数是违反语言规则的。 documentation说:
嵌套过程和函数(在其他例程中声明的例程)不能用作过程值。
所以你应该像这样编写这段代码:
function myCB(data: Pointer);
begin
result := 456;
end;
procedure TMyClass.impl2(from, till: integer);
begin
AddToDatabase(myCB, someData);
end;
另请注意,我在传递回调时删除了@
的使用。删除@
允许编译器检查回调是否满足要求。在你的代码中它没有,因为它是一个嵌套的函数。您对@
的使用产生了无类型指针,因此避免了类型检查。
由于历史怪癖,如果使用@
运算符来抑制类型检查,32位Windows编译器将允许您使用嵌套函数作为过程变量。此外,只要嵌套函数不引用其外部作用域中的任何内容或Self
中包含的任何内容,对该程序变量的调用将起作用。但在我看来,这种行为不应该依赖。
如果您需要回调来访问实例的方法,请将其设置为方法类型:
type
TGetFreeNumber = function(data: Pointer): integer of object;
并传递你班级的方法。
或者如果你想使用匿名方法和变量捕获,并且你的Delphi版本支持它们,那么使用引用函数:
type
TGetFreeNumber = reference to function(data: Pointer): integer;
答案 1 :(得分:1)
应该是直截了当的:
TGetFreeNumber = function(data: Pointer): integer;
procedure TMyClass.AddToDatabase(cb: TGetFreeNumber; Data: Pointer);
var
num: integer;
begin
num := cb(Data);
// INSERT INTO ... VALUES num ...
end;