2012-04-10 28 views
5

Tôi đang tạo một thể hiện của một lớp bằng cách sử dụng hàm TRttiMethod.Invoke, nhưng khi hàm tạo hoặc phương thức bị quá tải, thì rtti không gọi phương thức thích hợp.Chức năng TRttiMethod.Invoke không hoạt động trong các phương thức quá tải?

Tôi đã viết một ứng dụng mẫu để khắc phục sự cố của mình.

program ProjectFoo; 

{$APPTYPE CONSOLE} 

{$R *.res} 

uses 
    Rtti, 
    System.SysUtils; 

type 
    TFoo=class 
    public 
    constructor Create(Value : Integer);overload; 
    constructor Create(const Value : string);overload; 
    function Bar(value : integer) : Integer; overload; 
    function Bar(const value : string) : string; overload; 
    end; 

{ TFoo } 

constructor TFoo.Create(Value: Integer); 
begin 
    Writeln(Value); 
end; 

function TFoo.Bar(value: integer): Integer; 
begin 
    Writeln(Value); 
    Result:=value; 
end; 

function TFoo.Bar(const value: string): string; 
begin 
    Writeln(Value); 
    Result:=value; 
end; 


constructor TFoo.Create(const Value: string); 
begin 
    Writeln(Value); 
end; 

var 
c : TRttiContext; 
t : TRttiInstanceType; 
r : TValue; 
begin 
    try 
    c := TRttiContext.Create; 
    t := (c.GetType(TFoo) as TRttiInstanceType); 
    r := t.GetMethod('Create').Invoke(t.MetaclassType,[444]);//this works 
    //r := t.GetMethod('Create').Invoke(t.MetaclassType,['hello from constructor string']);//this fails : EInvalidCast: Invalid class typecast 
    t.GetMethod('Bar').Invoke(r,[1]);// this works 
    //t.GetMethod('Bar').Invoke(r,['Hello from bar']); //this fails : EInvalidCast: Invalid class typecast 
    except 
    on E: Exception do 
     Writeln(E.ClassName, ': ', E.Message); 
    end; 
    readln; 
end. 

Đây là lỗi RTTI? hoặc tồn tại một cách khác để gọi các phương thức quá tải của một lớp bằng RTTI?

Trả lời

12

Không có gì sai với phương pháp TRttiMethod.Invoke, sự cố của bạn nằm ở số GetMethod. Hàm này gọi nội bộ tới số TRttiType.GetMethods và truy xuất con trỏ đến phương thức đầu tiên khớp với tên được chuyển làm tham số. Vì vậy, khi bạn đang thực hiện mã này t.GetMethod('Create') bạn luôn nhận được một con trỏ đến cùng một phương pháp.

Để thực thi phiên bản quá tải của hàm tạo hoặc phương pháp khác, bạn phải giải quyết địa chỉ phương thức để thực thi dựa trên tham số, sau đó gọi hàm TRttiMethod.Invoke.

Kiểm tra chức năng mẫu này.

function RttiMethodInvokeEx(const MethodName:string; RttiType : TRttiType; Instance: TValue; const Args: array of TValue): TValue; 
var 
Found : Boolean; 
LMethod : TRttiMethod; 
LIndex : Integer; 
LParams : TArray<TRttiParameter>; 
begin 
    Result:=nil; 
    LMethod:=nil; 
    Found:=False; 
    for LMethod in RttiType.GetMethods do 
    if SameText(LMethod.Name, MethodName) then 
    begin 
    LParams:=LMethod.GetParameters; 
    if Length(Args)=Length(LParams) then 
    begin 
     Found:=True; 
     for LIndex:=0 to Length(LParams)-1 do 
     if LParams[LIndex].ParamType.Handle<>Args[LIndex].TypeInfo then 
     begin 
     Found:=False; 
     Break; 
     end; 
    end; 

    if Found then Break; 
    end; 

    if (LMethod<>nil) and Found then 
    Result:=LMethod.Invoke(Instance, Args) 
    else 
    raise Exception.CreateFmt('method %s not found',[MethodName]); 
end; 

Bây giờ bạn có thể gọi các nhà thầu hoặc các phương pháp của lớp học của bạn trong một trong các cách

r := RttiMethodInvokeEx('Create', t, t.MetaclassType, [444]); 
    r := RttiMethodInvokeEx('Create', t, t.MetaclassType, ['hello from constructor string']); 
    r := RttiMethodInvokeEx('Create', t, t.MetaclassType, []); 
    RttiMethodInvokeEx('Bar', t, r.AsObject , ['this is a string']); 
    RttiMethodInvokeEx('Bar', t, r.AsObject , [9999]); 
Các vấn đề liên quan