如果我尝试在事件处理程序上使用闭包,编译器会抱怨:
不兼容的类型:“方法指针和常规过程”
我理解..但是有没有办法在方法指针上使用 clouser?以及如何定义是否可以?
例如:
Button1.Onclick = procedure( sender : tobject ) begin ... end;
谢谢!
如果我尝试在事件处理程序上使用闭包,编译器会抱怨:
不兼容的类型:“方法指针和常规过程”
我理解..但是有没有办法在方法指针上使用 clouser?以及如何定义是否可以?
例如:
Button1.Onclick = procedure( sender : tobject ) begin ... end;
谢谢!
@Button1.OnClick := pPointer(Cardinal(pPointer( procedure (sender: tObject)
begin
((sender as TButton).Owner as TForm).Caption := 'Freedom to anonymous methods!'
end )^ ) + $0C)^;
2010年在德尔福工作
一个很好的问题。
据我所知,在当前版本的 Delphi 中是不可能的。这是非常不幸的,因为这些匿名过程非常适合快速设置对象的事件处理程序,例如在 xUnit 类型的自动测试框架中设置测试装置时。
CodeGear 应该有两种方式来实现这个特性:
1:允许创建匿名方法。像这样的东西:
Button1.OnClick := procedure( sender : tobject ) of object begin
...
end;
这里的问题是把什么作为匿名方法的自指针。可以使用创建匿名方法的对象的自指针,但只能从对象上下文创建匿名方法。一个更好的主意可能是在幕后简单地创建一个虚拟对象来包含匿名方法。
2:或者,可以允许事件类型同时接受方法和过程,只要它们共享定义的签名。通过这种方式,您可以按照您想要的方式创建事件处理程序:
Button1.OnClick := procedure( sender : tobject ) begin
...
end;
在我看来,这是最好的解决方案。
在以前的 Delphi 版本中,您可以通过将隐藏的 self 指针添加到参数并对其进行硬类型转换来使用常规过程作为事件处理程序:
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;
我不确定上面是否真的编译,但它应该给你一个大致的想法。我以前做过这个,它适用于常规程序。因为我不知道编译器为闭包生成什么代码,所以我不能说这是否适用于它们。
它很容易扩展下面来处理更多的表单事件类型。
用法
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.