如果我尝试在事件处理程序上使用闭包,编译器会抱怨:
不兼容的类型:“方法指针和常规过程”
我理解..但有没有办法在方法指针上使用clouser?以及如何定义是否可以?
例如:
Button1.Onclick = procedure( sender : tobject ) begin ... end;
谢谢!
答案 0 :(得分:10)
@Button1.OnClick := pPointer(Cardinal(pPointer( procedure (sender: tObject)
begin
((sender as TButton).Owner as TForm).Caption := 'Freedom to anonymous methods!'
end )^ ) + $0C)^;
Delphi 2010中的
答案 1 :(得分:5)
一个很好的问题。
据我所知,在当前版本的Delphi中无法做到。这非常不幸,因为这些匿名过程对于快速设置对象的事件处理程序非常有用,例如在xUnit类型的自动测试框架中设置测试夹具时。
CodeGear应该有两种方式来实现此功能:
1:允许创建匿名方法。像这样:
Button1.OnClick := procedure( sender : tobject ) of object begin
...
end;
这里的问题是作为匿名方法的自指针放置的内容。可以使用创建匿名方法的对象的self指针,但是只能从对象上下文创建匿名方法。更好的想法可能是在幕后创建一个虚拟对象以包含匿名方法。
2:或者,可以允许事件类型接受方法和过程,只要它们共享定义的签名即可。通过这种方式,您可以按照自己的方式创建事件处理程序:
Button1.OnClick := procedure( sender : tobject ) begin
...
end;
在我看来,这是最好的解决方案。
答案 2 :(得分:4)
在以前的Delphi版本中,您可以使用常规过程作为事件处理程序,方法是将隐藏的自我指针添加到参数中并对其进行强制转换:
procedure MyFakeMethod(_self: pointer; _Sender: TObject);
begin
// do not access _self here! It is not valid
...
end;
...
var
Meth: TMethod;
begin
Meth.Data := nil;
Meth.Code := @MyFakeMethod;
Button1.OnClick := TNotifyEvent(Meth);
end;
我不确定上面的内容确实可以编译,但它应该给你一般的想法。我以前做过这个,它适用于常规程序。由于我不知道编译器为闭包生成了什么代码,我不能说这是否适用于它们。
答案 3 :(得分:2)
很容易扩展下面的内容以处理更多表单事件类型。
用法
procedure TForm36.Button2Click(Sender: TObject);
var
Win: TForm;
begin
Win:= TForm.Create(Self);
Win.OnClick:= TEventComponent.NotifyEvent(Win, procedure begin ShowMessage('Hello'); Win.Free; end);
Win.Show;
end;
代码
unit AnonEvents;
interface
uses
SysUtils, Classes;
type
TEventComponent = class(TComponent)
protected
FAnon: TProc;
procedure Notify(Sender: TObject);
class function MakeComponent(const AOwner: TComponent; const AProc: TProc): TEventComponent;
public
class function NotifyEvent(const AOwner: TComponent; const AProc: TProc): TNotifyEvent;
end;
implementation
{ TEventComponent }
class function TEventComponent.MakeComponent(const AOwner: TComponent;
const AProc: TProc): TEventComponent;
begin
Result:= TEventComponent.Create(AOwner);
Result.FAnon:= AProc;
end;
procedure TEventComponent.Notify(Sender: TObject);
begin
FAnon();
end;
class function TEventComponent.NotifyEvent(const AOwner: TComponent;
const AProc: TProc): TNotifyEvent;
begin
Result:= MakeComponent(AOwner, AProc).Notify;
end;
end.