I have two different method pointers.
type
TComponentMethod = procedure(const AComponent: TComponent) of object;
TFormMethod = procedure(const AForm: TForm) of object;
The only difference is the type of the argument, but both are object references so it should not make any difference from the calling convention point of view.
(However it could be a type safety problem, because of co- / contravariance.)
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;
The compiler doesn't let me do it.
[dcc32 Error] Unit1.pas(32): E2010 Incompatible types: 'TComponent' and 'TForm'
Is there any way to type cast a method pointer to another "compatible" method pointer?
You can do this:
var
FormMethod: TFormMethod;
ComponentMethod: TComponentMethod;
begin
FormMethod := M2;
ComponentMethod := TComponentMethod(FormMethod);
end;
As far as I can see, the trick is that you need to assign to a temporary local variable before subsequently assigning that to ComponentMethod.
As you know, this is not typesafe. If ComponentMethod is invoked with an argument that is not derived from TForm, then the compiler won't be able to save you.
They're not compatible.
If M2 takes a TForm as one of its inputs, the compiler can reasonably expect form methods/members to be accessed in the body of M2.
A TComponentMethod event handler only requires a TComponent instance to call it. So the combination (if the compiler allowed it) would make it possible to access TForm members on TComponent instances. (Obviously a recipe for disaster.)
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;
That said, you can perform a hard-typecast. However, TComponentMethod(M2) wouldn't work because the compiler wants to call M2 almost any time you use the identifier. It's only a bit of "compiler magic" that that allows FormMethod := M2 in the first place. So you'd need an intermediate event handler variable to hold a reference to M2. And because an event handler variable is not a function, it can be typecast without trying to call it.
Temp := M2;
ComponentMethod := TComponentMethod(Temp);
WARNING This is a terrible idea, but it works:
ComponentMethod variable can be used as follows: ComponentMethod(AComponentThatsNotAForm).M2 is implemented, then you should have declared M2 as follows: procedure M2(const AComponent: TComponent); (If it doesn't need a form instance to do its job, don't ask for a form instance.) ... And you wouldn't have to bother trying so desperately to find a way to shoot yourself in the foot.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With