2013-05-20 28 views
0

我面臨的任務是允許用戶使用啓用了RTTI的已編譯類定義表達式。讓我以一種簡單的方式來說明。使用Delphi 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; 

,我有一個程序,這將與提供的表達式評估動物

​​

用戶表達 (TAnimal.Weight * TAnimal.Height)/(TAnimal.Weight + TAnimal.Height)

現在,我可以使用RTTI場景中獲得TAnimal和獲得動物身高和體重的價值。但是,我如何評估用戶提供的表達式?

是否有任何機制可以用來在我的應用程序啓動時和運行時準備用戶表達式,只需發送動物實例以檢索值。用戶可以隨時更改表達式,應用程序必須評估表達式。

我正在使用Delphi XE3。

+0

我會爲此使用JclExprEval。更重要的是,屬性是實例屬性而不是類屬性。 –

+0

對於數學解析器,請參見['Delphi中的數學表達式解析器?'](http://stackoverflow.com/q/1326258/576719)。根據表達式的複雜程度,可以使用腳本語言,請參見['Delphi腳本庫](http://stackoverflow.com/q/226135/576719)。 –

+0

@LURD但是,確實使用腳本庫引入了任何性能瓶頸?就像表達一直被解析一樣。 –

回答

2

您可以使用實時綁定來評估表達式。這裏有一個簡單的例子:

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. 

注意,我故意省略了代碼,免費的對象,因此該代碼泄漏。我選擇這樣做,所以我們可以專注於表達評估方面。

+0

行expr.Evaluate,它會嘗試再次解析表達式還是將它編譯爲一些任意代碼堆棧並進行評估?原因在於,表達式需要通過接近實時處理的方式針對許多同類物體進行評估。無論如何,我會按照你所建議的相同的方式進行操作,並檢查其性能。 –

+0

表達式在調用'CreateUnmanagedBinding'時被編譯。它不會被編譯爲可執行代碼,僅僅是對錶達式的中間表示進行評估。 –