Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.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 RTTI构建和计算表达式_Delphi_Rtti_Delphi Xe3_Expression Evaluation - Fatal编程技术网

使用Delphi 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

我面临的任务是允许用户使用启用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 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
时编译的。它不是编译成可执行代码,只是编译成表达式的中间表示形式,然后对其求值。