Delphi Imbricated回调函数

时间:2016-11-02 11:01:24

标签: delphi firemonkey

我有以下情况。

我制作了一个组件。我想在使用一种方法时从组件中获得一些反馈。

与component.Method(param1:callback function);

类似 到目前为止,一切都很好,有光泽。

该项目有以下单位。

formMain - 可见表格。

dataModule - 使用组件。

表格主要需要传递给datamodule一个回调函数来接收他的反馈。此回调函数是与组件不同的函数(具有更多参数)。

我不知道该怎么做。

TFeedBackProcedure = procedure(param1 : Integer) of object;
TFeedBackProcedureByTypeOf = procedure(aTypeOf : Integer; param1 : Integer) of object;

// component
procedure Syncro(feedBack : TFeedBackProcedure);
begin
  //somewhere inside
  for i := 0 to 15 do begin
    feedBack(i);
  end;
end;
// the feeedback received so far when someone use the Syncro procedure is the value of i

// the datamodule
// inside of a method I need to pass also the i received from compoent also a typeof value used only inside datamodule
procedure UseMethod(feedbackProcedure : TFeedBackProcedureByTypeOf); // the extended callback
begin
  typeof = 1;
  if component.Syncro(???) then begin // <-------- how to ???
     // do stuff
  end;
end;

// the main form
// the real callback function
procedure TFormMain.Feddback(aTypeOf : Integer; param1: Integer);
begin
  if aTypeOf = 0 then begin
    label1.caption = IntToStr(param1);
  end else begin
    label2.caption = IntToStr(param1);
  end;
end;
// usage of datamodule
procedure TFormMain.btn1Click(Sender: TObject);
begin
  dataModule.UseMethod(Feddback);
end;

任何想法?任何其他方法来做到这一点? (我在FMX环境中也需要这个)

很多

勒兹

1 个答案:

答案 0 :(得分:2)

如果您自己编写了组件,那么最简单的方法是更改​​TFeedbackProcedure的类型声明,以便它也接受匿名方法(以及对象方法):

TFeedBackProcedure = reference to procedure(param1 : Integer);

这使您可以将扩展方法包装到位并调用它:

procedure UseMethod(feedbackProcedure : TFeedBackProcedureByTypeOf);
var
  _typeOf : integer; 
begin
  _typeOf = 1;
  component.Syncro(procedure(AParam : integer)
                   begin
                     feedbackProcedure(_typeOf, AParam);
                   end);
end;

我只是简单地在这里调用方法,因为你的例子写了.Synchro,好像它是一个返回布尔值的函数,实际上,你已经将它声明为一个简单的过程。

作为替代方案,如果您无法更改方法签名或将包装器添加到现有类,则始终可以编写包装类来执行此任务。我在这里展示了一个专用的包装器类,但您可以轻松地将这些字段和方法添加到任何合适的类中,以将功能包装到具有正确签名的对象方法中。

  TCallbackContainer = class
    private
      FParam : integer;
      FFeedbackProcByTypeOf : TFeedBackProcedureByTypeOf;
    public
      constructor Create(AProcByTypeOf : TFeedBackProcedureByTypeOf);
      procedure WrapCallback(AParam:integer);
      property IntParam : integer read FParam write FParam;
  end;

实施:

  constructor TCallbackContainer.Create(AProcByTypeOf : TFeedBackProcedureByTypeOf);
  begin
    FFeedbackProcByTypeOf := AProcByTypeOf;
  end;

  procedure TCallbackContainer.WrapCallback(AParam: Integer);
  begin
    FFeedbackProcByTypeOf(FParam, AParam);
  end;

然后你可以这样称呼:

procedure UseMethod(feedbackProcedure : TFeedBackProcedureByTypeOf);
var
  LCallbackContainer : TCallbackContainer;
begin
  LCallBackContainer := TCallbackContainer.Create(feedbackProcedure);
  try
    LCallBackContainer.IntParam := 1;
    component.Syncro(LCallbackContainer.WrapCallback);
  finally
    LCallBackContainer.Free; 
  end;
  { Or, make it FCallBackContainer and manage lifetime somehow...}
end;

与引用计数的匿名方法不同,您必须以某种方式管理LCallbackContainer对象生存期。我已经将它显示为本地,如果.Synchro实际上是完全同步的,那么就可以了,并且当它返回时你可以释放回调容器。如果。Synchro实际上是一个异步方法,并且在它的工作完成之前返回,那么你需要一些方法来管理回调包装器的生命周期。

您还应避免命名变量TypeOf,因为这会隐藏the standard method该名称。不推荐使用System.TypeOf,但仍然可以避免这样的命名冲突。