【问题标题】:Parse boolean condition into expression tree将布尔条件解析为表达式树
【发布时间】:2011-02-01 18:08:33
【问题描述】:

如果我有一个采用布尔值的方法,例如:

public void Foo(boolean condition)

然后这样称呼它:

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

我可以将它组合成一个表达式树,以便构造一个对其他数据源的查询,这些数据源将使用 MyField 作为一个参数,使用 MyValue 和另一个。 我似乎只能将该条件变成一个计算结果为假的表达式。

更新

    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 是一个具有两个属性的类,名称和值

【问题讨论】:

  • 我认为您的“更新”中有一个错误:Expression.Parameter 的第二个参数只是 参数的逻辑名称 - 所以传入 field 看起来非常错误。同样,使用常量文字 "Name" 作为字段/属性看起来......不太可能。

标签: c# linq expression-trees


【解决方案1】:

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);
}

并使用Foo("MyField", "MyValue)(其中隐含&lt;string&gt;,由编译器提供)或Foo("MyField", 123) 调用,如果prop 是int(隐含&lt;int&gt;),

最后一个场景是"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 很好的答案,虽然在我的编辑中,我不得不稍微修改它......谢谢!
  • @Johan - 有什么具体的失败吗?另外,如果您提前知道"Name",您可以使用x =&gt; x.Name == value...?
  • 当我使用 x 时,它没有说 x 不是 Field...ideas 的已知属性?
  • @Johan 是的,我认为你已经混淆了 Expression.ParameterExpression.PropertyOrField 的参数 - parameter 应该被调用(类似于)x -属性通常应该不同
【解决方案2】:

In 可以从委托创建表达式树。例如,如果您将方法定义为将委托作为参数,则可以按如下方式使用它:

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
}

但是,在您的情况下,您会发现您的表达式是一个值为“false”的布尔常量,这是因为编译器已经评估了"MyField" == "MyValue",这当然是错误的。

如果您只想要名称-值对,而不仅仅是使用 Dictionary&lt;string, string&gt;

【讨论】:

  • +1。很好的答案,但有一点不准确:名称action 暗示了Action 委托类型——即。 delegate void ()——而不是Func&lt;T&gt;。我将该标识符重命名为例如fnlazyBool,或类似的东西。
  • "In can create expression trees from delegates" - 呃,不行
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-12-04
  • 2021-12-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多