Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 如何在TRttiMethod.Invoke中正确使用字符串作为参数?_Delphi_Delphi Xe3_Rtti - Fatal编程技术网

Delphi 如何在TRttiMethod.Invoke中正确使用字符串作为参数?

Delphi 如何在TRttiMethod.Invoke中正确使用字符串作为参数?,delphi,delphi-xe3,rtti,Delphi,Delphi Xe3,Rtti,我试图使用RTTI用Text属性概括可视化组件的内容验证,但当我尝试将字符串值传递到TRttiMethod.Invoke时,我得到消息“Invalid Typecast”。(实际上是“Ungültige Typumwandlung”,但我想,这是一个合适的翻译。) 假设所有传递的对象都是完美的,下面的代码将去掉所有安全措施、断言等 procedure ValidateTextFieldAndSetFocus(const Field: TObject; const Validator: TObje

我试图使用RTTI用Text属性概括可视化组件的内容验证,但当我尝试将字符串值传递到TRttiMethod.Invoke时,我得到消息“Invalid Typecast”。(实际上是“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;

这里调用的是类函数,但传递的是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.

请提供一个答案,这样我们就不必猜测丢失的部件。从目前的情况来看,这个问题应该作为离题而结束。因为你没有提供复制品。一旦你纠正了这个错误(见上面评论中的链接),我们就可以回答了。实际上代码提供了足够的信息来发现错误。@StefanGlienke所以你不相信提交完整的复制品?就我个人而言,我喜欢鼓励最佳实践,并教人们如何隔离问题和提交最少的复制品。我敢肯定,当人们向Spring4D提交问题时,你也会有同样的感受。我强烈地感觉到,我们应该教育人们完整的代码对于重现问题的重要性。我很失望你似乎不同意这种观点。
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.