无法从一组表达式创建复合表达式<Func >

(对底部的回答)

我正在尝试构建一个结合的系统

Func 

委托给ExpressionTree,它允许我传入一个值(在这种情况下为badValue)并在谓词全部返回true并考虑二进制操作时获取bool。 这是我第一次使用Expression / ExpressionTrees,所以请保持温和。

我收到这个错误:

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

在这条线上:

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

我已经设置了那条线,因为我需要在所有表达式中共享对value的引用(对吗?)。

我理想的情况是只有一堆

 Expression<Func> 

我可以将它们与逻辑运算符(和/或/不)一起传递到系统中,并在最后得到一个bool。 希望能够动态构建值必须通过的规则。

在我要走的路上,这有可能吗? 如果没有,那么指引我走正确道路的几条指针将不胜感激。

 string badValue = "hello!"; const int minSize = 8; const int maxSize = 30; Expression<Func> stringLengthMax = value => value.Length < maxSize; Expression<Func> stringLengthMin = value => value.Length > minSize; Expression<Func> 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 shouldValidate = Expression.Lambda<Func>(collectAnswers, stringLengthMax.Parameters).Compile(); bool result = shouldValidate(badValue); 

回答我没有以正确的方式推进参数,下面是几个表达式之间共享的多个参数的示例,这些表达式被放入ExpressionTree中并且单个布尔值来自编译的Func,isValid

 const int minSize = 8; const int maxSize = 30; Expression<Func> stringLengthMax = (value, max) => value.Length <= max; Expression<Func> stringLengthMin = (value, min) => value.Length >= min; Expression<Func> 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> minMaxCheck = Expression.Lambda<Func>( Expression.And(Expression.Invoke(stringLengthMax, valueParameter, maxParameter), Expression.Invoke(stringLengthMin, valueParameter, minParameter)), valueParameter, minParameter, maxParameter); minMaxCheck = Expression.Lambda<Func>( Expression.And(Expression.Invoke(minMaxCheck, valueParameter, minParameter, maxParameter), Expression.Not(Expression.Invoke(isEmpty, valueParameter))), valueParameter, minParameter, maxParameter); Func 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 

如果你想用Expressions做这个,那么这样的东西就行了。 虽然你可以建立它,但这并不会造成短路。你非常接近。 您需要通过整个参数树线程化一个参数表达式。

 string badValue = "hello!"; const int minSize = 8; const int maxSize = 30; Expression> stringLengthMax = value => value.Length < maxSize; Expression> stringLengthMin = value => value.Length > minSize; Expression> isEmpty = value => !string.IsNullOrEmpty(value); ParameterExpression pe = Expression.Parameter(typeof(string)); var x = Expression.Lambda>( Expression.And(Expression.Invoke(stringLengthMax, pe), Expression.And(Expression.Invoke(stringLengthMin, pe), Expression.Invoke(isEmpty, pe))), pe); Func 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(); 

在我看来,你根本不需要构建表达式树。 您可以使用简单的linq组合您的func(将它们定义为Func ,而不是Expression> ):

 Func shouldValidate = arg => new[] {stringLengthMax, stringLengthMin, isEmpty}.All(func => func(arg)); 

如果你想使用的不仅仅是and ,你可以逻辑地组合你的func:

 Func shouldValidate = arg => isEmpty(arg) || (stringLengthMax(arg) && stringLengthMin(arg));