2011-02-01 31 views
2

如果我有需要一個布爾值等的方法:解析布爾條件爲表達式樹

public void Foo(boolean condition) 

,並調用它是這樣的:

Foo("MyField" == "MyValue"); 

我可以撰寫到這一點,爲了一個表達式樹構建一個查詢到一些其他數據源,將使用MyField作爲一個參數和MyValue和另一個。 我似乎只能把這個條件變成一個表達式來評估爲false。

UPDATE

var param = Expression.Parameter(typeof(Field), field); 
    var prop = Expression.PropertyOrField(param, "Name"); 

    ConstantExpression @const = Expression.Constant(value, typeof(string)); 
    var body = Expression.Equal(prop, @const); 
    var lambda = Expression.Lambda<Func<Field, bool>>(body, param); 

其中field是具有兩個屬性,名稱和值

+0

我認爲你的「更新」中有一個錯誤:「Expression.Parameter」的第二個參數就是參數的*邏輯名* - 因此在`field`中傳遞看起來非常錯誤。同樣,使用不變的文字「Name」作爲字段/屬性看起來......不太可能。 – 2011-02-01 10:10:58

回答

4

Foo("MyField" == "MyValue")是,如問題底部所述,是一個常量false(在編譯器上)。你有幾個選擇這裏 - 最簡單的當然是做這樣的事情:

void Foo(Expression<Func<YourType,bool>> predicate) {...} 

Foo(x => x.MyField == "MyValue"); 

然後這裏打電話,沒有什麼剩下要做的;我們已經有了表達。所以,我認爲你的意思是「MyField的」只在運行時已知的字符串,在這種情況下:如果道具

void Foo<T>(string fieldName, T value) { 
    var param = Expression.Parameter(typeof(YourType), "x"); 
    var body = Expression.Equal(
        Expression.PropertyOrField(param, fieldName), 
        Expression.Constant(value, typeof(T)) 
       ); 
    var lambda = Expression.Lambda<Func<YourType, bool>>(body, param); 
} 

和(在那裏有一個隱含的<string>,編譯器提供)與Foo("MyField", "MyValue)打電話,或Foo("MyField", 123)int(隱式<int>),

最終的情形是,"MyValue"也是唯一已知的在運行時(EMPH:string) - 在這種情況下,我們需要對它進行解析:

void Foo(string fieldName, string value) { 
    var param = Expression.Parameter(typeof(YourType), "x"); 
    var prop = Expression.PropertyOrField(param, fieldName); 
    ConstantExpression @const; 
    if(prop.Type == typeof(string)) { 
     @const = Expression.Constant(value, typeof(string)); 
    } else { 
     object parsed = TypeDescriptor.GetConverter(prop.Type) 
      .ConvertFromInvariantString(value); 
     @const = Expression.Constant(parsed, prop.Type); 
    } 
    var body = Expression.Equal(prop,@const); 
    var lambda = Expression.Lambda<Func<YourType, bool>>(body, param); 
} 

這裏的通話總是2個字符串 - 所以Foo("MyField", "123")即使當int

1

在可以創建代表表達式樹的類。例如,如果你定義你的方法,以便它需要一個委託作爲參數,可以按如下方式使用它:

public void Foo(Func<bool> fn) 
{ 
    // invoke the passed delegate 
    var result = fn(); 
} 

Foo(() => "MyField" == "MyValue"); 

爲了創建一個表達式樹,而不是執行委託,改變方法如下:

public void Foo(Expression<Func<bool>> expression) 
{ 
    // inspect your expression tree here 
} 

然而,在你的情況,你會發現,你的表情是「假」的值的布爾常量,這是因爲編譯器評估"MyField" == "MyValue"這當然是錯誤的。

如果你只是想要名稱 - 值對,而不只是使用Dictionary<string, string>

+0

+1。很好的答案,只有一點點不準確:名字`行動`建議`行動`委託類型 - 即。 `委託void()` - 而不是'Func `。我會將該標識符重命名爲`fn`或`lazyBool`,或類似的東西。 – stakx 2011-02-01 09:10:33

+1

「在可以從代表創建表達式樹」 - 呃,不,它不能 – 2011-02-01 09:24:41