delphi - 如何正确使用 TRttiMethod.Invoke 中的字符串作为参数?

标签 delphi delphi-xe3 rtti

我正在尝试使用 RTTI 通过文本属性来概括可视组件的内容验证,但是当我尝试将字符串值传递到 TRttiMethod.Invoke 时,我收到消息“无效类型转换”。 (实际上是“Ungültige Typumwandlung”,但我想,这是一个合适的翻译。)

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

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;

验证器的执行只有一个字符串参数。我见过将字符串直接传递到 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;

最佳答案

您在这里调用一个类函数,但传递一个 TObject 作为第一个参数(这是非静态方法的隐藏 Self 参数)。在类方法上,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.

关于delphi - 如何正确使用 TRttiMethod.Invoke 中的字符串作为参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32393566/

相关文章:

delphi - 如何从 PAnsichar 转换为 PWidechar?

Delphi - 防止 Windows 从托盘应用程序关闭

delphi - Rtti 不适用于用作类字段的泛型类型

c++ - 尝试计算派生类的实例,type_id 不起作用

delphi - 在运行时获取delphi记录中字段的偏移量

delphi - 如何确定当前光标位置的事件监视器

delphi - 类型参数 'T' 必须是类类型

Delphi 和 TIdTCPServer.OnExecute : How to correctly merge data

delphi - 在 Delphi 中包装函数调用泛型

multithreading - Delphi - 在单次成功执行或用户取消后终止线程