Delphi 通过TRttiProperty.SetValue分配对象的过程时引发EInvalidCast异常

Delphi 通过TRttiProperty.SetValue分配对象的过程时引发EInvalidCast异常,delphi,delphi-xe2,rtti,Delphi,Delphi Xe2,Rtti,我正在尝试使用TRttiProperty.SetValue过程通过rtti分配对象的procedure类型的属性,但是当我尝试进行分配EInvalidCast:Invalid class typecast 这个示例应用程序显示了这个问题 {$APPTYPE CONSOLE} uses Rtti, SysUtils; type TMyCallBack = procedure (const Foo : string) of object; TMyClass = class

我正在尝试使用
TRttiProperty.SetValue
过程通过rtti分配对象的
procedure类型的属性,但是当我尝试进行分配
EInvalidCast:Invalid class typecast

这个示例应用程序显示了这个问题

{$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.
{$APPTYPE控制台}
使用
Rtti,
SysUtils;
类型
TMyCallBack=对象的过程(const Foo:string);
TMyClass=类
程序剂量测量(常量Foo:String);
结束;
TMyAnotherClass=class
私有的
FDoSomething:TMyCallBack;
出版
属性DoSomething:TMyCallBack读取FDoSomething写入FDoSomething;
结束;
{TMyClass}
程序TMyClass.DoSomething(const Foo:String);
开始
书面语(“你好”);
结束;
变量
MyClass:TMyClass;
t:TRttiInstanceType;
v:TValue;
p:trtti属性;
酒吧:TMyCallBack;
开始
尝试
MyClass:=TMyClass.Create;
尝试
t:=TRttiContext.Create.GetType(TMyAnotherClass.AsInstance);
v:=t.GetMethod('Create').Invoke(t.MetaclassType,[]);
p:=t.GetProperty('DoSomething');
Bar:=MyClass.DoSomething;
如果是pnil那么
p、 设置值(v.AsObject,@Bar)//这里提出了一个例外
最后
MyClass.免费;
结束;
除了
关于E:Exception-do
Writeln(E.ClassName,“:”,E.Message);
结束;
Readln;
结束。

如何解决这个问题?

当我追踪到错误行时,我最终进入隐式TClass->TValue转换例程。看起来@Bar是一个指针,编译器正在隐式地将它转换为一个TClass,从那里一切都变得一团糟。那不是你想要的

您需要的是一个实际的TValue,它的类型和值匹配条。试试这个:

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.
Var
MyClass:TMyClass;
t:TRttiInstanceType;
v:TValue;
p:trtti属性;
酒吧:TMyCallBack;
vBar:TValue;
开始
尝试
MyClass:=TMyClass.Create;
尝试
t:=TRttiContext.Create.GetType(TMyAnotherClass.AsInstance);
v:=t.GetMethod('Create').Invoke(t.MetaclassType,[]);
p:=t.GetProperty('DoSomething');
Bar:=MyClass.DoSomething;
vBar:=TValue.From(巴);
如果是pnil那么
p、 设置值(v.AsObject,vBar)//这里提出了一个例外
最后
MyClass.免费;
结束;
除了
关于E:Exception-do
Writeln(E.ClassName,“:”,E.Message);
结束;
Readln;
结束。

@萨尔瓦多:不客气。您可能希望将此作为错误报告给QC:指向方法引用的指针不应该有资格由编译器隐式转换为TClass!