【问题标题】:How to pass an array of Pointer types to RttiMethods.Invoke in Delphi如何在 Delphi 中将指针类型数组传递给 RttiMethods.Invoke
【发布时间】:2018-01-20 07:11:43
【问题描述】:

使用最新更新的 Delphi 10.2

我有一个程序(实际代码):

PyObject = packed record ... end;
PPyObject = ^PyObject
PPyObjectArray = array of PPyObject;

procedure invokeMethod (methodName : string; args : PPyObjectArray);
var  ctx: TRttiContext;
     rt : TRttiType;
     mt : TRttiMethod;
     py : TPyArithmetic;
     tv : array of TValue;
begin
   py := TPyArithmetic.Create;
   ctx := TRttiContext.Create;
   try
     rt := ctx.GetType(TPyArithmetic);
     mt := rt.GetMethod (methodName);

    setlength (tv, 1);
    tv[0].From(args);
    mt.Invoke(py, tv);
  finally
    ctx.Free;
  end;
end;

出于调试原因,代码本身在invokeMethod 中分布在多行上。该过程的目的是使用参数数组 args 调用方法 methodName。但是,我无法成功地将参数传递给调用的方法。尽管调用了正确的函数,但被调用方法的入口处的参数是乱码。我的问题是我应该如何将一个 T 数组传递给调用方法?

我也尝试使用调用调用

mt.Invoke(py, [args]);

但我得到编译错误:

E2250 没有可以使用这些参数调用的“Invoke”的重载版本。

试过了

mt.Invoke(py, [@args]);

但我得到运行时错误:

带有“Invalid case typecast”消息的 EInvalidCast,尝试跟踪调用,但未能成功找出错误的原因。

被调用端的代码是:

class function TPyArithmetic.add (args : PPyObjectArray) : double;
begin
   result := TArithmetic.add (GetPythonEngine.PyFloat_AsDouble (args[0]), GetPythonEngine.PyFloat_AsDouble (args[1]));
end;

有什么建议吗?

【问题讨论】:

  • 顺便说一句,我怀疑 PyObject 是否应该被打包。它不会影响布局,并且它们都是动态分配的,因此不会影响对齐。但是还是……
  • 这些类型来自另一个第三方库。我想准确地展示其他库是如何定义这些类型的,以防它对问题产生影响。
  • 当然。这是我不使用该库的原因之一。我不相信它。
  • 除了大卫在他的回答中指出的明显缺陷之外,实际查看被调用方法的代码来判断通过 RTTI 的调用是否正在做它应该做的事情会很有帮助。
  • 更新了问题以显示调用的代码。注意我还在探索这种做事方式,你看到的代码并不是最终的代码。

标签: delphi rtti


【解决方案1】:

TValue.From 是一个返回新值的函数。 A 这段代码是错误的:

tv[0].From(args);

没有任何东西被分配给tv[0]。你需要这样做:

tv[0] := TValue.From(args);

更简单的方法是移除动态数组并使用开放数组构造函数:

mt.Invoke(py, [TValue.From(args)]);

创建和销毁 RTTI 上下文的代码也是虚假的。它可以按您的方式正常工作,但同样可以:

procedure invokeMethod(methodName: string; args: PPyObjectArray);
var  
  ctx: TRttiContext;
  rt: TRttiType;
  mt: TRttiMethod;
  py: TPyArithmetic;
begin
  py := TPyArithmetic.Create;  
  rt := ctx.GetType(TPyArithmetic);
  mt := rt.GetMethod (methodName);
  mt.Invoke(py, [TValue.From(args)]);
end;

FWIW,您的代码似乎泄露了py

【讨论】:

  • 这可能很好地解释了为什么我在另一端没有得到任何东西。我明天试试这个。我意识到py泄露了。我假设像 GetType 这样的方法是类方法,这就是我们不需要在 ctx 上调用 create 的原因。
  • 没有。不是这个。 RTTI 上下文生命周期管理很奇怪。它会根据托管类型初始化自动创建自己。
猜你喜欢
  • 1970-01-01
  • 2012-10-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-01
  • 1970-01-01
  • 2018-02-06
  • 1970-01-01
相关资源
最近更新 更多