2011-02-01 27 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