使用Delphi RTTI构建和计算表达式
我面临的任务是允许用户使用启用RTTI的编译类定义表达式。让我简单地说一下使用Delphi RTTI构建和计算表达式,delphi,rtti,delphi-xe3,expression-evaluation,Delphi,Rtti,Delphi Xe3,Expression Evaluation,我面临的任务是允许用户使用启用RTTI的编译类定义表达式。让我简单地说一下 TAnimal = class(TPersistent) private fWeight : Double; fHeight : Double; fName : string; published property Weight : Double read fWeight write fWeight; property Height : Double read fHeight write fHeigh
TAnimal = class(TPersistent)
private
fWeight : Double;
fHeight : Double;
fName : string;
published
property Weight : Double read fWeight write fWeight;
property Height : Double read fHeight write fHeight;
property Name : string read fName write fName;
end;
我有一个程序,用提供的表达式来评估动物
function EvaluateAnimal(const animal : TAnimal; expression : string) : Double;
begin
//Result := Turn expression to evaluation and give the result
end;
用户表达式是
(TAnimal.Weight*TAnimal.Height)/(TAnimal.Weight+TAnimal.Height)
现在,我可以使用RTTI上下文获得TAnimal,并获得动物的身高和体重值。但是,如何计算用户提供的表达式
是否有任何机制可以用于在应用程序启动时准备用户表达式,并在运行时发送animal实例以检索值。用户可以随时更改表达式,应用程序必须对表达式求值
我使用的是Delphi XE3。您可以使用动态绑定来计算表达式。下面是一个简单的例子:
program BindingsDemo;
{$APPTYPE CONSOLE}
uses
System.Rtti,
System.Bindings.Expression,
System.Bindings.EvalProtocol,
System.Bindings.Helper;
type
TFoo = class
Val1: Integer;
Val2: Integer;
Result: TValue;
end;
procedure Main;
var
Foo: TFoo;
scope: IScope;
expr: TBindingExpression;
begin
Foo := TFoo.Create;
Foo.Val1 := 42;
Foo.Val2 := 666;
scope := TBindings.CreateAssociationScope([Associate(Foo, 'Foo')]);
expr := TBindings.CreateUnmanagedBinding(
[Scope],
'Foo.Val1 + Foo.Val2',
[Scope],
'Foo.Result',
nil
);
expr.Evaluate;
Assert(Foo.Result.AsInteger=708);
Writeln(Foo.Result.ToString);
end;
begin
Main;
Readln;
end.
注意,我故意省略了释放对象的代码,因此这段代码会泄漏。我选择这样做是为了让我们能够专注于表达式计算方面。我会使用JclExprEval。此外,属性是实例属性而不是类属性。有关数学解析器,请参阅。根据表达式的复杂程度,可以使用脚本语言,请参阅。@LURD但是,使用脚本库会带来性能瓶颈吗??比如,如果表达式一直被解析。@DavidHeffernan如果我必须编写表达式计算器,那么起点应该是什么??我热衷于开发框架来解决我的问题。我想脚本语言的内部工作原理都有点不同。其中许多允许在运行时预编译并多次运行。我建议看看.expr.Evaluate行,它是再次尝试解析表达式,还是将其编译成任意代码堆栈并进行计算?原因是,需要对同一类型的许多对象的表达式进行近实时处理。无论如何,我将遵循您建议的相同行并检查性能。表达式是在调用
CreateUnmanagedBinding
时编译的。它不是编译成可执行代码,只是编译成表达式的中间表示形式,然后对其求值。