使用参数和结果回调

时间:2016-01-19 10:39:50

标签: delphi callback

我花了很长时间才找到答案,但没有找到任何答案。我正在尝试将带有数据的回调传递给函数。

这是我的伪代码:

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;

2 个答案:

答案 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;