使用Delphi RTTI构建和评估表达式

时间:2013-05-20 13:18:27

标签: 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 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,并获得动物身高和体重的值。但是,我如何评估用户提供的表达式?

我的应用程序启动时是否可以使用任何机制来准备用户表达式,在运行时,只需发送动物实例来检索值。用户可以随时更改表达式,应用程序必须评估表达式。

我正在使用Delphi XE3。

1 个答案:

答案 0 :(得分:2)

您可以使用Live Binding来评估表达式。这是一个简单的例子:

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.

注意,我故意省略了释放对象的代码,因此这段代码泄露了。我选择这样做,所以我们可以专注于表达评估方面。