c# - 无法从一组表达式创建复合表达式 <Func<string, bool>>

标签 c# .net expression expression-trees

(向底部回答)

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

Func<T, bool> 

委托(delegate)到一个 ExpressionTree 中,它允许我传入一个值(在本例中为 badValue),如果谓词全部返回 true 并且考虑了二进制操作,则得到一个 bool 值。这是我第一次使用 Expression/ExpressionTrees,所以请保持温和。

我收到这个错误:

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

在这一行:

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

我以这种方式设置了那条线,因为我需要在所有表达式中共享对 value 的引用(对吧?)。

我理想的情况是只有一堆

Expression<Func<blah, blah, bool>> 

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

这在我要去的路线上有可能吗?如果没有,我将不胜感激一些指导我走上正确道路的指示。

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

回答 我没有以正确的方式推送参数,下面是多个表达式之间共享的多个参数的示例,这些表达式被放入 ExpressionTree 中,并且单个 bool 值来自编译的 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

最佳答案

如果你想用表达式来做,像这样的东西会起作用。这不会短路,尽管您可以将其内置。您已经很接近了。您需要将一个参数表达式贯穿整个参数树。

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

关于c# - 无法从一组表达式创建复合表达式 <Func<string, bool>>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16703504/

相关文章:

c# - 物理或逻辑分离我的 dll?

c# - Windows Phone - SyndicationFeed 问题

c# - WCF 没有正确超时?

java - Python boolean 语句

javascript - 表达式解析 : how to tokenize

c# - AForge.NET 中的 "Source pixel format is not supported by the filter"错误

c# - 如何从 3d 数组中随机选择 2d 数组?

python - 将 Iron Python 与 Solidworks API 结合使用

.net - 使用 REST 公开 SQL Server 数据库

c# - Where() 的 IEnumerable lambda 表达式