I trying to append where predicates and my goal is to create the same expression as:
Services.Where(s => s.Name == "Modules" && s.Namespace == "Namespace");
I have the following code:
Expression<Func<Service,string>> sel1 = s => s.Name;
Expression<Func<Service,string>> sel2 = s => s.Namespace;
var val1 = Expression.Constant("Modules");
var val2 = Expression.Constant("Namespace");
Expression e1 = Expression.Equal(sel1.Body, val1);
Expression e2 = Expression.Equal(sel2.Body, val2);
var andExp = Expression.AndAlso(e1, e2);
ParameterExpression argParam = Expression.Parameter(typeof(string), "s");
var lambda = Expression.Lambda<Func<string, bool>>(andExp, argParam);
This create the following output:
s => ((s.Name == "Modules") AndAlso (s.Namespace == "Namespace"))
However, this is faulty since the parameter for Name and Namespace isn't the same. If I change one of the expression selector to:
Expression<Func<Service,string>> sel2 = srv => srv.Namespace;
The output will be:
s => ((s.Name == "Modules") AndAlso (srv.Namespace == "Namespace"))
How can I create a valid expression with use of sel1 and sel2?
UPDATE (28 feb 2011)
I solved it by creating invoke expressions: Expression.Invoke
so the lambda expressions sel1 and sel2 don't necessary need to be a MemberExpression:
Expression<Func<Service,string>> sel1 = s => s.Name;
Expression<Func<Service,string>> sel2 = srv => srv.Namespace;
var val1 = Expression.Constant("Modules");
var val2 = Expression.Constant("Namespace");
Expression<Func<Service, bool>> lambda = m => true;
var modelParameter = lambda.Parameters.First();
// sel1 predicate
{
var invokedExpr = Expression.Invoke(sel1, modelParameter);
var binaryExpression = Expression.Equal(invokedExpr, val1);
lambda = Expression.Lambda<Func<Service, bool>>(Expression.AndAlso(binaryExpression, lambda.Body), lambda.Parameters);
}
// sel2 predicate
{
var invokedExpr = Expression.Invoke(sel2, modelParameter);
var binaryExpression = Expression.Equal(invokedExpr, val2);
lambda = Expression.Lambda<Func<Service, bool>>(Expression.AndAlso(binaryExpression, lambda.Body), lambda.Parameters);
}
You can create an Expression tree for nullable types, suppose you have a nullable field BoardId, you can create expression tree dynamically like this
you need to determine first Property type, whether its Nullable or not
Below code create a Dynamic tree expression for nullable and Non Nullable types
1- This Solution first checks for the Nullable value and generate the expression. This is How you can determine if the type is Nullable. I have created an extension method for that purpose
2- the second step is to check the type if its string then create an expression for a string.
3- the Third step is to check is value is not nullable not string then create an expression using equal
It's hard to mix compiler-generated expression trees and hand-made ones, precisely because of this sort of thing - extracting out the ParameterExpressions is tricky. So let's start from scratch:
One important aspect I've changed is the type passed to
Expression.Parameter
- it certainly looks like it should be aService
rather than astring
.I've given that a try, and it seemed to work when I called
lambda.Compile
and executed it on a couple of sampleService
objects...