无法创建一个复合表达式< Func< string,bool>>>从一组表达式 [英] Unable to create a compound Expression<Func<string, bool>> from a set of expressions

查看:137
本文介绍了无法创建一个复合表达式< Func< string,bool>>>从一组表达式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

(底部回答)

我正在尝试构建一个结合

I'm trying to build a system that combines

Func<T, bool> 

委托给一个表达式,允许我传递一个值(在这种情况下为badValue),并获得一个如果谓词都返回true并且二进制操作被考虑,则返回bool。这是我第一次使用Expression / ExpressionTrees,所以请温柔。

delegates into an ExpressionTree that allows me to pass in a value (badValue in this case) and get a bool out if the predicates all return true and the binary operations are taken into account. This is my first time using Expression/ExpressionTrees, so please be gentle.

我收到此错误:

ArgumentException:无法调用类型System.Boolean的表达式

ArgumentException: Expression of type 'System.Boolean' cannot be invoked

/ p>

on this line:

collectAnswers = Expression.And(isEmpty.Body, Expression.Invoke(...

我已经设置了这一行,因为我需要分享对值的引用所有的表达式(对?)。

I've got that line set up that way because I need to share the reference to value among all the Expressions (right?).

我的理想情况是只需要一堆

My ideal scenario is to just have a bunch of

Expression<Func<blah, blah, bool>> 

我可以将它们与逻辑运算符(And / Or / Not)一起传递到一个系统中,并最终得到一个bool。希望允许动态构建一个值必须通过的规则。

and I can pass these into a system alongside logical operators (And/Or/Not) and get a bool out at the end. Hoping to allow a dynamic building of rules that a value has to pass through.

是否有可能在我要去的路线?如果没有,几点不要指望我正确的路径。

Is that even possible in the route I'm going? If not, a couple of pointers directing me down the right path would be appreciated.

string badValue = "hello!";
const int minSize = 8;
const int maxSize = 30;

Expression<Func<string, bool>> stringLengthMax = value => value.Length < maxSize;
Expression<Func<string, bool>> stringLengthMin = value => value.Length > minSize;
Expression<Func<string, bool>> isEmpty = value => !string.IsNullOrEmpty(value);

BinaryExpression collectAnswers = Expression.And(stringLengthMax.Body, Expression.Invoke(stringLengthMin, stringLengthMax.Parameters));
collectAnswers = Expression.And(isEmpty.Body, Expression.Invoke(collectAnswers, stringLengthMax.Parameters));

Func<string, bool> shouldValidate = Expression.Lambda<Func<string, bool>>(collectAnswers, stringLengthMax.Parameters).Compile();
bool result = shouldValidate(badValue);

答案
我没有推动参数s)正确的方式,下面是一些在多个表达式之间共享的多个参数的例子,这些表达式被放入到ExpressionTree中,一个布尔值来自编译的Func,isValid

Answer I wasn't pushing through the parameter(s) the right way, below is an example of multiple parameters shared among several Expressions that are put into an ExpressionTree and a single boolean comes out of the compiled Func, isValid

const int minSize = 8;
const int maxSize = 30;

Expression<Func<string, int, bool>> stringLengthMax = (value, max) => value.Length <= max;
Expression<Func<string, int, bool>> stringLengthMin = (value, min) => value.Length >= min;
Expression<Func<string, bool>> isEmpty = value => string.IsNullOrEmpty(value);

ParameterExpression valueParameter = Expression.Parameter(typeof(string));
ParameterExpression minParameter = Expression.Parameter(typeof(int));
ParameterExpression maxParameter = Expression.Parameter(typeof(int));

Expression<Func<string, int, int, bool>> minMaxCheck =
    Expression.Lambda<Func<string, int, int, bool>>(
        Expression.And(Expression.Invoke(stringLengthMax, valueParameter, maxParameter), 
            Expression.Invoke(stringLengthMin, valueParameter, minParameter)), valueParameter, minParameter, maxParameter);

minMaxCheck = Expression.Lambda<Func<string, int, int, bool>>(
    Expression.And(Expression.Invoke(minMaxCheck, valueParameter, minParameter, maxParameter), 
        Expression.Not(Expression.Invoke(isEmpty, valueParameter))), valueParameter, minParameter, maxParameter);

Func<string, int, int, bool> isValid = minMaxCheck.Compile();
bool resultFalse1 = isValid("hello!", minSize, maxSize); // false - too short
bool resultTrue1 = isValid("hello!", "hello!".Length, maxSize); // true - adjust min
bool resultFalse2 = isValid("1234567890123456789012345678901", minSize, maxSize); // false - too long
bool resultTrue2 = isValid("1234567890123456789012345678901", minSize, "1234567890123456789012345678901".Length); // true - adjust max
bool resultFalse3 = isValid(string.Empty, minSize, maxSize); // false - empty
bool shouldBeTrue = isValid("1234567890", minSize, maxSize); // true - just right
bool resultFalse4 = isValid("1234567890", maxSize, maxSize); // false - adjust min
bool resultFalse5 = isValid("1234567890", minSize, minSize); // false - adjust max


推荐答案

如果你想做它与表达式,这样的东西可以工作。这不会发生短路,虽然你可以建立它,你相当接近。您需要通过整个参数树线程一个参数表达式。

If you wanted to do it with Expressions, something like this would work. This doesn't short circuit, though you can build that in. You were quite close. You need to thread one parameter expression through the whole parameter tree.

string badValue = "hello!";
const int minSize = 8;
const int maxSize = 30;

Expression<Func<string, bool>> stringLengthMax = value => value.Length < maxSize;
Expression<Func<string, bool>> stringLengthMin = value => value.Length > minSize;
Expression<Func<string, bool>> isEmpty = value => !string.IsNullOrEmpty(value);

ParameterExpression pe = Expression.Parameter(typeof(string));

var x = Expression.Lambda<Func<string, bool>>(
    Expression.And(Expression.Invoke(stringLengthMax, pe), 
        Expression.And(Expression.Invoke(stringLengthMin, pe), Expression.Invoke(isEmpty, pe))), pe);

Func<string, bool> shouldValidate = x.Compile();
bool resultFalse1 = shouldValidate("hello!");
bool resultFalse2 = shouldValidate("1234567890123456789012345678901");
//bool resultFalse3 = shouldValidate(null); Throws an exception because you can't do (null).Length
bool shouldBeTrue = shouldValidate("123456789");

//LinqPad code to view results:
resultFalse1.Dump();
resultFalse2.Dump();
//resultFalse3.Dump();
shouldBeTrue.Dump();

这篇关于无法创建一个复合表达式&lt; Func&lt; string,bool&gt;&gt;&gt;从一组表达式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆