Delphi:invoke构造函数引发EInvalidCast [英] Delphi: invoke constructor raises EInvalidCast

查看:127
本文介绍了Delphi:invoke构造函数引发EInvalidCast的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试调用通过RTTI(运行D2010版本14.0.3593.25826)获得的构造函数.构造函数将字符串和对象的混合作为其参数,所有这些都应初始化为'' nil .(免责声明:我知道所需的构造函数将是具有最多参数数量的构造函数,因此虽然设计欠佳,但外观看起来很怪异.)

I'm trying to invoke a constructor obtained via RTTI (running D2010 version 14.0.3593.25826). The constructor takes a mixture of strings and objects as its arguments, all of which should be initialized to '' or nil. (Disclaimer: I know that the desired constructor will be the one with maximum number of parameters, hence the weird-looking, although suboptimal design.)

代码如下:

program sb_rtti;
{$APPTYPE CONSOLE}
uses RTTI, TypInfo, SysUtils;

type

TMyClass = class (TObject)
  FField1:  string;
  FObject1: TObject;
public
  constructor Create(Field1: string = ''; Object1: TObject = nil);
end;

constructor TMyClass.Create(Field1: string; Object1: TObject);
begin
  FField1 := Field1;
  FObject1 := Object1;
end;

function GetConstructor(rType: TRttiType) : TRttiMethod;
var
  MaxParams:  integer;
  Methods:    TArray<TRttiMethod>;
  Method:     TRttiMethod;
  Params:     TArray<TRttiParameter>;
begin
  Methods := rType.GetMethods('Create');
  MaxParams := 0;
  for Method in Methods do begin
    Params := Method.GetParameters();
    if (Length(Params) > MaxParams) then begin
      Result := Method;
      MaxParams := Length(Params);
    end;
  end;
end;

procedure InitializeParam(Param: TRttiParameter; ActualParam: TValue);
begin
  if (Param.ParamType.TypeKind = TTypeKind.tkClass) then begin
    ActualParam := TValue.From<TObject>(nil);
  end else if (Param.ParamType.TypeKind = TTypeKind.tkString) then begin
    ActualParam := TValue.From<string>('');
  end else if (Param.ParamType.TypeKind = TTypeKind.tkUString) then begin
    ActualParam := TValue.From<UnicodeString>('');
  end else begin
    // Other types goes here
  end;
end;

var
  Context:      TRttiContext;
  Constr:       TRttiMethod;
  Params:       TArray<TRttiParameter>;
  ResultValue:  TValue;
  rType:        TRttiType;
  ActualParams: array of TValue;
  i:            integer;
  CurrentParam: TRttiParameter;
begin
  Context := TRttiContext.Create();
  rType := Context.GetType(TypeInfo(TMyClass));
  Constr := GetConstructor(rType);
  try
    if (Constr <> nil) then begin
      Params := Constr.GetParameters();
      SetLength(ActualParams, Length(Params));
      for i := 0 to Length(Params) - 1 do begin
        CurrentParam := Params[i] as TRttiParameter;
        InitializeParam(CurrentParam, ActualParams[i]);
      end;
      ResultValue := Constr.Invoke(rType.AsInstance.MetaclassType, ActualParams);
    end;
  except
    on E : Exception do
      WriteLn(E.ToString);
  end;
  ReadLn;
end.

现在,当执行 ResultValue行:= Constr.Invoke(rType.AsInstance.MetaclassType,ActualParams); 时,将引发EInvalidCast异常.异常可以追溯到第1336行的 TValue.Cast 方法.

Now, when the line ResultValue := Constr.Invoke(rType.AsInstance.MetaclassType, ActualParams); is executed, an EInvalidCast exception is raised. The exception may be traced to the TValue.Cast-method at line 1336.

但是,问题的根源似乎在调用堆栈的前一点,更确切地说是在rtti.pas中的第4093行( argList [currArg]:= Args [i] .Cast(parList[i] .ParamType.Handle); ).

However, the meat of the problem seems to be found at the previous point in the call stack, more precisely at line 4093 in rtti.pas (argList[currArg] := Args[i].Cast(parList[i].ParamType.Handle);).

我敢打赌,我正在以我不应该使用的方式使用rtti,但是,我找不到任何地方描述的正确方法".有人能指出我正确的方向吗?谢谢!

My bet is that I'm using rtti in ways I'm not supposed to, yet, I can't find the "right way" described anywhere. Can anybody please point me in the right direction? Thanks!

推荐答案

您在 InitializeParam 过程中遇到问题,因为在分配 ActualParam 参数时,您是设置该参数的本地副本的值–请记住, TValue ( ActualParam 的类型)是一条记录.因此,要解决此问题,您必须将 ActualParam 作为var参数传递.

You have a problem in the InitializeParam procedure because in the assignment of the ActualParam parameter, you are setting the value of the local copy of that parameter – remember that TValue (the type of ActualParam) is a record. So to fix the problem you must pass the ActualParam as a var parameter.

procedure InitializeParam(Param: TRttiParameter; var ActualParam: TValue);

这篇关于Delphi:invoke构造函数引发EInvalidCast的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆