2015-09-04 89 views
5

我试图推广使用RTTI的文本属性的可视化组件的内容验证,但是当我尝试传递一个字符串值到TRttiMethod.Invoke,我得到消息“无效的类型转换”。 (实际上是“UngültigeTypumwandlung”,但我想,这是一个合适的翻译。)如何正确使用TRttiMethod.Invoke中的字符串作为参数?

下面的代码被剥夺了所有的安全措施,断言等,假设所有传递的对象都是完美的。

procedure ValidateTextFieldAndSetFocus(const Field: TObject; const Validator: TObject; const errorStates: array of TStringValidationResult; const sErrorMessage: string); 
var 
    context : TRttiContext; 
    objField : TRttiType; 
    objValid : TRttiType; 
    prop  : TRttiProperty; 
    execute : TRttiMethod; 
    I  : Integer; 
    validResult : TStringValidationResult; 
    value : TValue; 
begin 
    context := TRttiContext.Create; 
    objField := context.GetType(Field.ClassInfo); 
    objValid := context.GetType(Validator.ClassInfo); 
    prop  := objField.GetProperty('Text'); 
    value := prop.GetValue(Field); 
    execute := objValid.GetMethod('Execute'); 
    for I := 0 to High(errorStates) do 
    if execute.Invoke(Validator,[value]).TryAsType<TStringValidationResult>(validResult) then 
     if validResult = errorStates[I] then 
     begin 
     SetFocusIfCan(Field); 
     raise Exception.Create(sErrorMessage); 
     end; 
end; 

Validator的Execute只有一个字符串参数。我看过一些例子,其中字符串直接传递到TValue数组中,但是我得到了相同的类型转换错误。

编辑:出现在execute.Invoke(Validator,[value])

实际的错误。

TNoSemicolonNullValidator = class 
    class function Execute(const aStr: string): TStringValidationResult; 
end; 

procedure TestValidation; 
var 
    Validator : TNoSemicolonNullValidator; 
begin 
    Validator := TNoSemicolonNullValidator.Create; 
    try 
    ValidateTextFieldAndSetFocus(Edit1,Validator,[svInvalid],'Edit1 is invalid!'); 
    finally 
    Validator.Free; 
    end; 
end; 
+0

请提供[MCVE]所以,我们不必猜测,缺少 –

+0

零件就目前来看,这个问题应该是封闭的话题。因为你没有提供复制品。一旦你解决了这个问题(见上面评论中的链接),我们将能够回答。 –

+0

实际上,代码提供了足够的信息来发现错误。 –

回答

13

您在这里调用类的功能,但你传递一个TObject的作为第一个参数(即非静态方法隐藏自我参数)。在一个类方法中,Self参数不能是一个实例,而是它的类。所以,正确的调用是:

execute.Invoke(validator.ClassType, [value]); 

下面是一个小例子来证明:

program Project1; 

{$APPTYPE CONSOLE} 

uses 
    Rtti, 
    SysUtils; 

type 
    TValidator = class 
    class function Execute(const s: string): Boolean; 
    end; 

class function TValidator.Execute(const s: string): Boolean; 
begin 
    Writeln(s); 
end; 

var 
    ctx: TRttiContext; 
    v: TValidator; 
begin 
    v := TValidator.Create; 
    try 
    ctx.GetType(TValidator).GetMethod('Execute').Invoke(v, ['test']); 
    except 
    on E: Exception do 
     Writeln(E.ClassName, ': ', E.Message); 
    end; 
    try 
    ctx.GetType(TValidator).GetMethod('Execute').Invoke(v.ClassType, ['test']); 
    except 
    on E: Exception do 
     Writeln(E.ClassName, ': ', E.Message); 
    end; 
    Readln; 
end. 
相关问题