Delphi 虚拟方法表
我正在使用这个区块:Delphi 虚拟方法表,delphi,rtti,Delphi,Rtti,我正在使用这个区块: procedure ExecMethod(Target: TClass; const MethodName: string; const Args: array of TValue); var LContext: TRttiContext; LType: TRttiType; LMethod: TRttiMethod; begin LType := LContext.GetType(Target); for LMethod in LType.GetMet
procedure ExecMethod(Target: TClass; const MethodName: string; const Args: array of TValue);
var
LContext: TRttiContext;
LType: TRttiType;
LMethod: TRttiMethod;
begin
LType := LContext.GetType(Target);
for LMethod in LType.GetMethods do
if (LMethod.Parent = LType) and (LMethod.Name = MethodName) then begin
LMethod.Invoke(Target.Create, Args);
break;
end;
end;
像这样:
ExecMethod(TFuncClass, 'Test1', []);
ExecMethod(TFuncClass, 'Test2', ['hey']);
ExecMethod(TFuncClass, 'Test3', [100]);
procedure ExecMethod(Target: TObject; const MethodName: string; const Args: array of TValue);
var
LContext: TRttiContext;
LType: TRttiType;
LMethod: TRttiMethod;
begin
LType := LContext.GetType(Target.ClassType);
for LMethod in LType.GetMethods(MethodName) do
// TODO: Beware of overloaded methods
LMethod.Invoke(Target, Args);
end;
在这门课上:
TFuncClass = class(TObject)
published
procedure Test1;
procedure Test2(const str: string);
procedure Test3(i: integer);
// there's more, each one with different prototype
end;
var
FuncClass: TFuncClass;
但后来,我不断收到访问违规。。。或者无效的强制转换指针类(或其他任何类型)正如我在中所指出的,它会泄漏内存,因为它创建给定类的实例而从未释放它们。但是,这不应该立即导致任何运行时错误,因此这不是当前问题的原因
问题的代码将原始代码推广到任何给定的类上,这样做在技术上是错误的。要了解原因,您需要了解Delphi如何从类引用构造对象:
在类引用变量上调用构造函数时(如在Target.Create
中),编译器使用编译时的知识来决定调用哪个构造函数。在本例中,调用的目标是TClass
,编译器知道的唯一可用于该类型的构造函数是TObject.Create
,因此调用的构造函数就是该构造函数。如果TFuncClass
有其他构造函数,即使它与从TObject
继承的零参数签名匹配,也不会调用它。所创建对象的类型仍将显示为TFuncClass
,但是-ClassType
函数将返回TFuncClass
,并且is
操作符将按预期工作
当代码对一个类调用错误的构造函数时,它最终会得到所需类的某个半有效实例。拥有无效实例可能会导致各种问题。如果其中包括访问冲突、无效类型转换、无效结果或其他内容,我不会感到惊讶
问题中显示的代码不应该有我描述的问题,因为TFuncClass
没有新的构造函数。然而,给定的代码显然是不完整的,所以在这里可能过于简化了
最好让调用方负责提供一个实例来调用方法,如下所示:
ExecMethod(TFuncClass, 'Test1', []);
ExecMethod(TFuncClass, 'Test2', ['hey']);
ExecMethod(TFuncClass, 'Test3', [100]);
procedure ExecMethod(Target: TObject; const MethodName: string; const Args: array of TValue);
var
LContext: TRttiContext;
LType: TRttiType;
LMethod: TRttiMethod;
begin
LType := LContext.GetType(Target.ClassType);
for LMethod in LType.GetMethods(MethodName) do
// TODO: Beware of overloaded methods
LMethod.Invoke(Target, Args);
end;
像这样使用该函数:
FuncClass := TFuncClass.Create(...);
try
ExecMethod(FuncClass, 'Test1', []);
ExecMethod(FuncClass, 'Test2', ['hey']);
ExecMethod(FuncClass, 'Test3', [100]);
finally
FuncClass.Free
end;
注意,这都是假设第二个参数,即方法的字符串名,实际上是由某个变量提供的,该变量的值在运行时之前是未知的。如果您要将字符串文本传递给
ExecMethod
,那么您应该停止调用ExecMethod
,停止与RTTI混在一起,直接调用所需的方法:FuncClass.Test2('hey')
,不清楚您需要什么。你只是不知道如何调用一个类方法吗?或者你需要从另一个类的方法中调用该方法吗?问题中的代码与你描述的相同。这个问题的标题与它的主体有什么关系?很抱歉,如果我很难理解我,让我重新表述一下我的意思。。。我希望ExecMethod成为类的一部分,并且它将在它所属的同一个类中执行方法。。而不必把目标放在课堂上……;]你说你有两种完全不同的错误,“或者别的什么。”请准确一点。复制并粘贴您得到的实际错误文本。说“或随便什么”告诉我你不必费心去注意这个问题。如果您不介意的话,为什么其他人要这么做呢?我试过这样的代码:键入MyClass=class发布的过程TestFunc;ExecMethod(MyClass,'TestFunc',[])<代码>给出异常..当然它没有编译,对吗?这是因为该示例中的MyClass
不是类型为TObject
的值TestFunc
是一个实例方法。它要求您拥有MyClass
的实例。RTTI不允许您回避该要求。是否希望TestFunc
成为类方法而不是实例方法?您希望它是一个静态方法吗?请记住,没有人能读懂你的心思。你需要问你想要什么我试过你的密码。。这给了我一个例外。我用TClass替换了TObject。。。但我仍然会出错。ExecMethod
已经可以处理所有这些问题。正如我之前所建议的,也许您可以发布一些代码来演示您所面临的问题。您可以单击问题下方的“编辑”链接并添加到其中;问题空间提供了比这些注释更好的格式。如果你发布的代码不起作用也没关系。很明显,你很难用文字来解释你的任务,所以也许用代码来解释对你来说会更容易。我现在注意到,事实上,这两种方法并不匹配。您将其添加到类中并引入了错误。我没有检查来源,因为我认为你发布了一些已知的好消息。今天和你一起工作特别困难。