Unable to create a compound Expression> from a set of expressions

.net c# expression expression-trees

Question

(Response at the bottom)

I'm attempting to create a system that integrates

Func<T, bool> 

delegates into an ExpressionTree that enables me to send in a value (in this example, badValue) and get a bool in the event that all of the predicates return true and the binary operations are taken into consideration. Please be patient with me; this is my first time using Expression/ExpressionTrees.

This error is occurring for me:

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

over here:

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

That line is configured in that manner because I must share the reference tovalue between all of the Expressions, correct?

My ideal situation would be to simply have a lot of

Expression<Func<blah, blah, bool>> 

and I can input them together with the logical operators (And/Or/Not) into a system, getting a bool output at the conclusion. wishing to permit the dynamic construction of the laws via which a value must travel.

Is it even feasible to do that on my current course? If not, I would appreciate a few hints leading me in the proper direction.

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

Answer Below is an example of many arguments shared across various Expressions that are placed into an ExpressionTree, and a single boolean, isValid, comes out of the generated Func since I wasn't putting the parameter(s) through the appropriate method.

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
1
3
5/23/2013 7:52:57 PM

Accepted Answer

Like this would work if you wanted to do it using Expressions. Though you might include that, this doesn't short circuit. You were really near. One parameter expression must be threaded across 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();
3
5/23/2013 5:30:34 PM

Popular Answer

I believe that creating an expression tree is not at all necessary. Utilizing basic linq, you may join your functions (define them asFunc<string, bool> , notExpression<Func<string, bool>> ):

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

If you want to employ more than oneand , you may logically join your functions:

Func<string, bool> shouldValidate = 
    arg => isEmpty(arg) || (stringLengthMax(arg) && stringLengthMin(arg));


Related Questions





Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow