【问题标题】:EInvalidCast exception is raised when assign a procedure of object, via TRttiProperty.SetValue通过 TRttiProperty.SetValue 分配对象过程时引发 EInvalidCast 异常
【发布时间】:2012-04-14 02:34:28
【问题描述】:

我正在尝试使用TRttiProperty.SetValue 过程通过rtti 分配procedure of object 类型的属性,但是当我尝试分配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.

我该如何解决这个问题?

【问题讨论】:

    标签: delphi delphi-xe2 rtti


    【解决方案1】:

    当我追踪到错误行时,我最终使用了隐式 TClass->TValue 转换例程。看起来@Bar 是一个指针,编译器隐式地将它转换为 TClass,从那里一切都搞砸了。这不是你想要的。

    你需要的是一个类型和值匹配 Bar 的实际 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.
    

    【讨论】:

    • @Salvador:不客气。您可能希望将此作为错误报告给 QC:指向方法引用的指针不应该被编译器隐式转换为 TClass!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-17
    • 2011-12-04
    • 1970-01-01
    相关资源
    最近更新 更多