I would like to create a method that accepts an Expression<Func<T, bool>> and creates the logical inverse of it (i.e. it would return false where it would have returned true, and vice versa. This is much harder than I thought. This is where I am up to:
public static Expression<Func<T, bool>> Not<T>(this Expression<Func<T, bool>> expression)
{
return Expression.Lambda<Func<T, bool>>(Expression.Not(expression.Body));
}
This compiles fine but throws the following Exception when called:
Test method Tests.Common.Unit.LinqPredicateBuilderTests.CanInverseAPredicate threw exception:
System.ArgumentException: Incorrect number of parameters supplied for lambda declaration
I have no idea what I'm doing. Could anyone fill in the blanks?
You're calling Expression.Lambda to create an expression with no parameters at all, when you should be forwarding the single parameter of the source expression.
Note that we are trying to create an Expression<Func<T, bool>> and not an Expression<Func<bool>>.
Try this instead:
return Expression.Lambda<Func<T, bool>>(Expression.Not(expression.Body),
expression.Parameters);
Related
I have an expression of type Expression<Func<TOwner, object>> that was created using lambda (syntax). It has member-access expression somewhere in the body. I would like to create expression that selects another property of the mentioned expression's result.
I terms of C# it should look like this:
Expression<Func<MyClient, object>> exStartingPath = x => x.Address;
Expression<Func<MyClient, object>> exExtendedPath = ExtendSelection(exStartingPath, "Street");
//exExtendedPath should be equivalent to x => x.Address.Street
How should ExtendSelection(...) be implemented? Should I decompose already existing expression and compose new one using some traversing technique or is there any API that can just 'append' member selection?
Just grab the body of the lambda, apply the member access to that, and then wrap the whole thing back up into a new lambda.
public static Expression<Func<TSource, TTarget>> ExtendSelection<TSource, TTarget>(
Expression<Func<TSource, TTarget>> expression, string member)
{
var body = Expression.PropertyOrField(expression.Body, member);
return Expression.Lambda<Func<TSource, TTarget>>(body, expression.Parameters);
}
I'm using calculated properties on my EF object which can't be passed directly to a where() clause:
{"The specified type member 'SomeProp' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported."}
Based on what I read on SO, this could be avoided by passing a Expression<Func<T, bool>> as the argument to where().
Compiling the expression to a Func works fine:
Expression<Func<Foo, bool>> expr = e => f => f.SomeCalculatedProperty == 1;
Func<Foo, bool> compiled = expr.Compile();
Foo result = dbContext.Foo.Where(compiled);
But passing the expression gives me the error above, i.e:
Expression<Func<Foo, bool>> expr = e => f => f.SomeCalculatedProperty == 1;
Foo result = dbContext.Foo.Where(e);
Based on this, shouldn't the last example work fine?
In example one you are calling the extension method Queryable.Where<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate) this converts the query to sql and applies the filter server side.
In example two you are calling the extension method Enumerable.Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate), this returns all rows from the database then in memory in the program it applies the filter.
For your third example, I will just quote Servy's comment
Your first and third snippets are functionally identical. There must
be some difference that you haven't shown for one to work and another
to not.
I've been understanding PredicateBuilder extension methods written Joseph Albahari and I saw this Expression.Invoke and honestly I couldn't understand the reason of it in the following method :
public static Expression<Func<T, bool>> Or<T> (this Expression<Func<T, bool>>
expr1, Expression<Func<T, bool>> expr2)
{
var invokedExpr = Expression.Invoke (expr2,
expr1.Parameters.Cast<Expression> ());
return Expression.Lambda<Func<T, bool>>
(Expression.OrElse (expr1.Body, invokedExpr), expr1.Parameters);
}
Even though he explained it a little bit:
The interesting work takes place inside the And and Or methods. We
start by invoking the second expression with the first expression’s
parameters. An Invoke expression calls another lambda expression using
the given expressions as arguments. We can create the conditional
expression from the body of the first expression and the invoked
version of the second. The final step is to wrap this in a new lambda
expression.
MSDN tells me that:
Creates an InvocationExpression that applies a delegate or lambda
expression to a list of argument expressions.
and this makes sense to me little bit. So basically I don't have to pass in any arguments if I use the expression like that.
But for some reason I couldn't quite understand it. Maybe I am tired or something.
Questions:
When and in which situation does it makes sense to use InvocationExpression.
Can anyone explain how Or<T> method (or AndElse<T>) method works little better?
Update:
I was thinking about InvocationExpression when I was coming from work to home and it hinted in my mind like this:
When we invoke a method, we simple say CallMe(phoneNumber, time); and this is called method invocation. Then, InvocationExpression should be an expression that expresses CallMe(phoneNumber, time);. It is similar to LambdaExpression which express a lambda such as t => t + 2. So basically it is a method invocation that is applied to arguments (not parameters). So as invocation, it is no longer expected to need a parameters but perhaps return something since arguments are already applied to its parameters.
For more information about the code I am talking about, please visit http://www.albahari.com/nutshell/predicatebuilder.aspx
Imagine you weren't working with expressions, but with delegates. Then you could write Or like this:
public static Func<T, bool> Or<T>(this Func<T, bool> expr1, Func<T, bool> expr2)
{
return x => expr1(x) || expr2(x);
}
You create a new delegate that invokes the two delegates, combined using ||. When you rewrite this to use expressions, invoking a delegate turns into Expression.Invoke():
public static Expression<Func<T, bool>> Or<T>(
this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
{
var parameter = Expression.Parameter(typeof(T), "x");
var invokedExpr1 = Expression.Invoke(expr1, parameter);
var invokedExpr2 = Expression.Invoke(expr2, parameter);
return Expression.Lambda<Func<T, bool>>(
Expression.OrElse(invokedExpr1, invokedExpr2), parameter);
}
The reason why the actual Or isn't written like this is (most likely) an optimization: you don't have to invoke both expressions, you can reuse the body and parameter from one of them. (But you can't reuse both of them, because they have different parameters.)
Does anyone have/know of an IQueryable.OrderBy extension that takes an Expression (retrieved, for example, by Reflection)? I believe the function would look something like this:
public static IQueryable<TEntity> OrderBy<TEntity>
(this IQueryable<TEntity> source, Expression sortExpression)
Expression would be assumed to be an Expression<Func<TEntity, T>> where TEntity is the same object being sorted on, and T is a type that needs to be determined in order to create the new IQueryable.
I've found many examples of extensions that take a string, including Dynamic Linq, like this:
public static IQueryable<TEntity> OrderBy<TEntity>(
this IQueryable<TEntity> source, string sortExpression)
If it's possible to take the string and use Reflection to look up the type from the object in question, it should also be possible to take the Expression, and get the value type which is right there IN the Expression.
Following is a detailed explanation of why I'd like to have this, which you may or may not need.
I have a rather large list of complex records to sort. Because the list is so long, I prefer to have the sorting done on the database side. To handle more complex properties, I've created Expressions that provide the sorting functionality, like so:
if (model.sortExpression == "PlannedValue")
{
Expression<Func<BDopp, decimal>> sorter = BDopp.PlannedValueSorter;
if (model.sortDirection == "DESC")
opps = opps.OrderByDescending(sorter).AsQueryable();
else
opps = opps.OrderBy(sorter).AsQueryable();
}
BDOpp.PlannedValueSorter retrieves a static expression from the object which allows sorting to be done without opps are still of type IQueryable:
public static Expression<Func<BDopp, decimal>> PlannedValueSorter
{
get
{
return z => z.BudgetSchedules
.Where(s => s.Type == 1)
.Sum(s => s.Value * s.Workshare * z.valueFactor / 100 / 100);
}
}
Sorting for simple properties is done with Extension methods that use Reflection to build an expression based on the name of the property passed as a string.
This works well, but for the complex types, I still need branching logic, and I'd rather not do that. What I'd rather do is check for a static property containing the expression, and then simply apply it. I can get the expression like this:
PropertyInfo info = typeof(BDopp).GetProperty(model.sortExpression + "Sorter",
BindingFlags.Static | BindingFlags.Public);
Expression expr = (Expression)info.GetValue(null, null);
For the PlannedValue property, this gets me the expression sorted in PlannedValueSorter, which I already know works.
Update:
Various digging around has gotten me what I think might be some progress:
public static IQueryable<TEntity> OrderBy<TEntity>(this IQueryable<TEntity> source,
Expression<Func<TEntity, dynamic>> sortExpression)
{
var unary = sortExpression.Body as UnaryExpression;
Type actualExpressionType = unary.Operand.Type;
actualExpressionType is in fact the return type of the Expression (for this particular property, it's decimal).
Unfortunately I'm mostly just working by trial and error, since I haven't yet wrapped my brain around how all this works, so my attempt to update the query like so is not working:
MethodCallExpression resultExp = Expression.Call(typeof(Queryable),
"OrderBy",
new Type[] { typeof(TEntity), actualExpressionType },
source.Expression, sortExpression);
return source.Provider.CreateQuery<TEntity>(resultExp);
It compiles okay, but the following error is thrown at runtime:
No generic method 'OrderBy' on type 'System.Linq.Queryable' is
compatible with the supplied type arguments and arguments. No type
arguments should be provided if the method is non-generic.
As I understand it you have an Expression and want to order/filter by it. It might surprise you how simple it is:
Expression<Func<TEntity, T>> sortExpr = ...; //you already have this
var ordered = myQuery.OrderBy(sortExpr);
OrderBy always uses an Expression so you can directly use it. If you only have a variable of type Expression (which points to an object of type Expression<Func<TEntity, T>>) and don't know statically what T is, you can do this:
Expression sortExpr = ...; //you already have this
var ordered = myQuery.OrderBy((dynamic)sortExpr);
dynamic will figure this out at runtime using reflection. No need to do reflection yourself. All that is needed here is overload resolution (performed by the C# runtime binder).
Okay, I've got a solution:
public static IQueryable<TEntity> OrderBy<TEntity>(
this IQueryable<TEntity> source,
Expression<Func<TEntity, dynamic>> sortExpression,
bool descending)
{
var unary = sortExpression.Body as UnaryExpression;
var operand = unary.Operand;
Type actualExpressionType = operand.Type;
MethodCallExpression resultExp =
Expression.Call(typeof(Queryable),
descending? "OrderByDescending" : "OrderBy",
new Type[] { typeof(TEntity), actualExpressionType },
source.Expression,
Expression.Lambda(operand, sortExpression.Parameters));
return source.Provider.CreateQuery<TEntity>(resultExp);
}
The bool descending is to allow for the standard OrderBy and OrderByDescending overloads. Two major breakthroughs here, at least for me:
Getting the Operand out of the expression.
Using Expression.Call and Expression.Lambda to create the new expression - this allows me to use an actual "Type" variable, whereas the Expression<Func<TEntity, T>> syntax requires you to use a type that's known at compile time.
Try this:
public static IEnumerable<T> OrderBy<T>(
this IEnumerable<T> collection,
string columnName
//, SortDirection direction
)
{
ParameterExpression param = Expression.Parameter(typeof(T), "x"); // x
Expression property = Expression.Property(param, columnName); // x.ColumnName
Func<T, object> lambda = Expression.Lambda<Func<T, object>>( // x => x.ColumnName
Expression.Convert(property, typeof(object)),
param)
.Compile();
Func<IEnumerable<T>, Func<T, object>, IEnumerable<T>> expression = (c, f) => c.OrderBy(f); // here you can use OrderByDescending basing on SortDirection
IEnumerable<T> sorted = expression(collection, lambda);
return sorted;
}
Usage:
IEnumerable<T> collection = ...
IEnumerable<T> ordered = collection.OrderBy("PropName");
See Code Project and sandbox.
I have an expression in the format of Expression<Func<T, T2, bool>> that I need to convert into an expression on the format of Expression<Func<T2, bool>> by replacing the T in the first expression with a constant value.
I need this to stay as an expression so I can't just Invoke the expression with a constant as the first parameter.
I've looked at the other questions here about expression trees but I can't really find a solution to my problem. I suspect I have to walk the expression tree to introduce the constant and remove one parameter but I don't even know where to start at the moment. :(
You can use Expression.Invoke to create a new lambda expression that calls the other:
static Expression<Func<T2, bool>> PartialApply<T, T2>(Expression<Func<T, T2, bool>> expr, T c)
{
var param = Expression.Parameter(typeof(T2), null);
return Expression.Lambda<Func<T2, bool>>(
Expression.Invoke(expr, Expression.Constant(c), param),
param);
}