我有两个不同的方法指针。
type
TComponentMethod = procedure(const AComponent: TComponent) of object;
TFormMethod = procedure(const AForm: TForm) of object;
唯一的区别是参数的类型,但两者都是对象引用,所以它不应该与调用约定的观点有任何区别。
(但由于共同/逆转,它可能是一种类型安全问题。)
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
procedure M2(const AForm: TForm);
end;
procedure TForm1.FormCreate(Sender: TObject);
var
FormMethod: TFormMethod;
ComponentMethod: TComponentMethod;
begin
FormMethod := M2;
// How to cast this?
ComponentMethod := M2;
end;
编译器不允许我这样做。
[dcc32 Error] Unit1.pas(32): E2010 Incompatible types: 'TComponent' and 'TForm'
有没有办法输入方法指针到另一个"兼容"方法指针?
答案 0 :(得分:4)
你可以这样做:
var
FormMethod: TFormMethod;
ComponentMethod: TComponentMethod;
begin
FormMethod := M2;
ComponentMethod := TComponentMethod(FormMethod);
end;
据我所知,诀窍是你需要先分配一个临时局部变量,然后再将其分配给ComponentMethod
。
如您所知,这不是类型安全的。如果使用不是从ComponentMethod
派生的参数调用TForm
,则编译器将无法保存您。
答案 1 :(得分:3)
他们不兼容。
如果M2
将TForm
作为其输入之一,编译器可以合理地期望在M2
的正文中访问表单方法/成员。
TComponentMethod
事件处理程序只需要一个TComponent
实例来调用它。因此,组合(如果编译器允许)可以访问TForm
实例上的TComponent
成员。 ( 显然是灾难的秘诀 。)
E.g。
procedure TForm1.M2(const AForm: TForm);
begin
AForm.ModalResult := mrCancel;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
ComponentMethod: TComponentMethod;
begin
ComponentMethod := M2;
//The next line is legal. But if the previous line were legal,
//you'd attempt to access TForm(AComponent).ModalResult ...
//An AV if you're lucky, and weird behaviour if you're not.
ComponentMethod(TComponent.Create(Self));
end;
那就是说,你可以进行艰难的转型。但是,TComponentMethod(M2)
不起作用,因为编译器几乎在您使用标识符的任何时候都想调用M2
。它只是一点“编译魔术”,它首先允许FormMethod := M2
。因此,您需要一个中间事件处理程序变量来保存对M2
的引用。并且因为事件处理程序变量不是函数,所以可以在不尝试调用它的情况下进行类型转换。
Temp := M2;
ComponentMethod := TComponentMethod(Temp);
警告 这是一个糟糕的主意,但它有效:
ComponentMethod
变量的使用方法如下:ComponentMethod(AComponentThatsNotAForm)
。M2
的实施方式而安全,那么您应该按如下方式声明M2:procedure M2(const AComponent: TComponent);
(如果没有不需要一个表单实例来完成它的工作,不要求表单实例。)... 你不必费心去拼命寻找一种方法来射击自己。< / em>的答案 2 :(得分:-1)
戴维斯的回答很好。我编写了一个通用方法,以避免每次演示时都必须声明源类型的临时变量。
type
TOneArgMethod<T> = procedure(const A: T) of object;
function TForm1.CastMethod<TFrom, TTo>(AFrom: TOneArgMethod<TFrom>)
: TOneArgMethod<TTo>;
var
Method: TMethod;
begin
Method := TMethod(AFrom);
Result := TOneArgMethod<TTo>(Method);
end;