I'm trying to create a method that I can pass a list of Expression<Func<T, bool>> objects to, and have the method combine the expressions using an And. Here is my code.
public Expression<Func<T, bool>> CombineExpressions(params Expression<Func<T, bool>>[] expressions)
{
Expression<Func<T, bool>> combinedExpression = null;
foreach (Expression<Func<T, bool>> expression in expressions)
{
if (combinedExpression == null)
{
combinedExpression = expression;
}
else
{
// ---> I also don't understand why I get a compiler error if I specify expressions[0].Parameters instead of expression[0].Parameters[0]
var binaryExpression = Expression.And(combinedExpression.Body, Expression.Invoke(expression, expressions[0].Parameters[0]));
combinedExpression = Expression.Lambda<Func<T, bool>> binaryExpression, expressions[0].Parameters);
}
}
retu Expression.Lambda<Func<T, bool>>(combinedExpression, expressions[0].Parameters);
}
Here's the code that uses the retued Expression, which results in the exception:
[TestMethod]
public void CombineExpressions_TwoExpressions_CombinedExpressionShouldExecuteCorrectly()
{
#region Arrange
List<Model> items = new List<Model>();
items.Add(new Model { IntegerProperty = 1, StringProperty = "one" });
items.Add(new Model { IntegerProperty = 1, StringProperty = "two" });
items.Add(new Model { IntegerProperty = 2, StringProperty = "one" });
items.Add(new Model { IntegerProperty = 2, StringProperty = "two" });
ExpressionGenerator<Model> expressionGenerator = new ExpressionGenerator<Model>();
#endregion // Arrange
#region Act
// The GetExpression method retus an Expression<Func<T, bool>> expression which compares the specified property with the specified value
// I have a series of tests for this method and it's working correctly
var expression1 = expressionGenerator.GetExpression("IntegerProperty", 2);
var expression2 = expressionGenerator.GetExpression("StringProperty", "one");
var combinedExpression = expressionGenerator.CombineExpressions(expression1, expression2);
#endregion // Act
#region Assert
var results = items.Where(combinedExpression.Compile()).ToList();
Assert.AreEqual(1, results.Count);
Assert.AreEqual(2, results[0].IntegerProperty);
Assert.AreEqual("one", results[0].StringProperty);
#endregion // Assert
}
The exception that I'm getting is
Result StackTrace:
at System.Linq.Expressions.Expression.ValidateLambdaArgs(Type delegateType, Expression& body, ReadOnlyCollection`1 parameters)
at System.Linq.Expressions.Expression.Lambda[TDelegate](Expression body, String name, Boolean tailCall, IEnumerable`1 parameters)
at System.Linq.Expressions.Expression.Lambda[TDelegate](Expression body, IEnumerable`1 parameters)
at Comparison.ExpressionGenerator`1.CombineExpressions(Expression`1[] expressions) in C:UsersbrubinDocumentsVisual Studio 2015ProjectsToadComparisonExpressionGenerator.cs:line 88
at Comparison.Tests.ExpressionGeneratorTests.CombineExpressions_TwoExpressions_CombinedExpressionShouldExecuteCorrectly() in C:UsersbrubinDocumentsVisual Studio 2015ProjectsToadComparison.TestsExpressionGeneratorTests.cs:line 33
Result Message:
Test method Comparison.Tests.ExpressionGeneratorTests.CombineExpressions_TwoExpressions_CombinedExpressionShouldExecuteCorrectly threw exception:
System.ArgumentException: Expression of type 'System.Func`2[Comparison.Tests.Helpers.Model,System.Boolean]' caot be used for retu type 'System.Boolean'
I also don't understand why the Expression.Invoke call in my first block of code is giving me a compiler error if I specify expressions[0].Parameters instead of expressions[0].Parameters[0]. I commented that line in the code above.
I based a lot of this code on LINQ expressions. Variable 'p' of type referenced from scope, but it is not defined
