Reputation: 16482
I'm trying assign a property which is of type procedure of object
via rtti using the TRttiProperty.SetValue
procedure, but this exception is raised when i try the made the assignment EInvalidCast: Invalid class typecast
This sample application shows the issue
{$APPTYPE CONSOLE}
uses
Rtti,
SysUtils;
type
TMyCallBack = procedure (const Foo : string) of object;
TMyClass = class
procedure DoSomething(const Foo: String);
end;
TMyAnotherClass = class
private
FDoSomething: TMyCallBack;
published
property DoSomething : TMyCallBack read FDoSomething Write FDoSomething;
end;
{ TMyClass }
procedure TMyClass.DoSomething(const Foo: String);
begin
Writeln('Hello');
end;
Var
MyClass : TMyClass;
t : TRttiInstanceType;
v : TValue;
p : TRttiProperty;
Bar : TMyCallBack;
begin
try
MyClass:=TMyClass.Create;
try
t:=TRttiContext.Create.GetType(TMyAnotherClass).AsInstance;
v:=t.GetMethod('Create').Invoke(t.MetaclassType,[]);
p:=t.GetProperty('DoSomething');
Bar:=MyClass.DoSomething;
if p<>nil then
p.SetValue(v.AsObject, @Bar); //here the exception is raised
finally
MyClass.Free;
end;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
How i can fix this issue?
Upvotes: 2
Views: 2068
Reputation: 84630
When I traced into the error line, I ended up on the implicit TClass->TValue conversion routine. It looks like @Bar is a pointer, and the compiler is implicitly converting that to a TClass, and from there everything gets messed up. That's not what you want.
What you need is an actual TValue whose type and value match Bar. Try this:
Var
MyClass : TMyClass;
t : TRttiInstanceType;
v : TValue;
p : TRttiProperty;
Bar : TMyCallBack;
vBar : TValue;
begin
try
MyClass:=TMyClass.Create;
try
t:=TRttiContext.Create.GetType(TMyAnotherClass).AsInstance;
v:=t.GetMethod('Create').Invoke(t.MetaclassType,[]);
p:=t.GetProperty('DoSomething');
Bar:=MyClass.DoSomething;
vBar := TValue.From<TMyCallback>(bar);
if p<>nil then
p.SetValue(v.AsObject, vBar); //here the exception is raised
finally
MyClass.Free;
end;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
Upvotes: 5