2012-04-14 1 views
2

Ich versuche, eine Eigenschaft zuweisen, die vom Typ procedure of object über rtti mit dem TRttiProperty.SetValue Verfahren, aber diese Ausnahme wird ausgelöst, wenn ich versuche, die die Zuordnung gemacht EInvalidCast: Invalid class typecastEInvalidCast Ausnahme ausgelöst wird, wenn ein Verfahren des Objekts zuweisen, über TRttiProperty.SetValue

Diese Beispielanwendung zeigt die Ausgabe

{$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. 

, wie ich dieses Problem beheben kann?

Antwort

5

Als ich in die Fehlerzeile eingezeichnet bin, landete ich auf der impliziten TClass-> TValue Konvertierungsroutine. Es sieht so aus, als wäre @Bar ein Zeiger, und der Compiler konvertiert das implizit in eine TClass, und von dort wird alles durcheinander gebracht. Das ist nicht was du willst.

Was Sie brauchen, ist ein tatsächlicher TValue, dessen Typ und Wert mit Bar übereinstimmen. Versuchen Sie dies:

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. 
+0

Vielen Dank, Mason. – Salvador

+1

@Salvador: Gern geschehen. Und Sie könnten dies QC als Fehler melden: Ein Zeiger auf eine Methodenreferenz sollte nicht für eine implizite Umwandlung in TClass durch den Compiler geeignet sein! –

Verwandte Themen