I am trying to convert an Expression of type Expression<Func<Entity, bool>> to a Func<Entity, bool>.
The background here is that I am trying to mock a repository so that it will return one of a collection of mock entities for a given key value. (I could hard code the input values to the mocked method but this seems like the wrong approach for a large number of items).
So I am trying to mock the First method on my repository like this:
var collection = new List<Entity>
{
mockedEntity1,
mockedEntity2,
mockedEntity3,
...
};
mockRepository
.Setup(rep => rep.First(It.IsAny<Expression<Func<Entity, bool>>>()))
.Returns<Expression<Func<Entity, bool>>>(e => collection.First(e));
This doesn't work because collection.First takes a Func rather than an Expression>. So I have got to the point where I need to convert the Expression to the Func that it contains.
Perhaps there a simpler or better to do this?
You need to call Compile on the expression.
It already is a lambda expression. But to get a delegate from the lambda, call .Compile().
In the general sense - to make a lambda from an Expression you would use Expression.Lambda, indicating the desired type and including the parameter (declaration) instances (from Expression.Parameter). However, this is not required here.
Related
I have the following code;
IQueryable<MyClass> query = listOfObjects.Where(x => x.SomeProp == 1);
I pass this to a method on a particular API that is expecting an IQueryable, which is fine.
However, I want to dynamically build up the predicate, so I'm using Expression.Lambda to achieve this, and I then .Compile it to turn it back into a Func<MyObject, bool>.
I would have expected that the following would have worked;
Func<MyClass, bool> predicate = x => GetPredicate();
IQueryable<MyClass> query = list.Fields.Where(predicate);
However, passing predicate to Where has changed the return type to IEnumerable<MyClass>, which isn't the type required by the API obviously.
I did (naively) try predicate.AsQueryable(), but the API in question (SharePoint Client Object model) just fails with a generic "Specified method is not supported." error message.
I don't know if this a limitation of the LINQ provider that is behind the scenes, but regardless... I'm keen to understand why pulling the Func out into its own variable and passing it in to Where affects the type inference in the way it does.
IQueryable is using an expression tree to build predicate. So, instead of
Func<MyClass, bool> predicate = x => GetPredicate();
use:
Expression<Func<MyClass, bool>> predicate = x => GetPredicate();
Keep in mind:
While using IQueryable expression tree is built (tree that represents operation (as operands and arguments) made on collection). In order to translate tree into other form (let's say sql query, depends on LINQ proider) translator must know all operands used in to tree. It looks like that translator in service where you are passing IQueryable don't know what does GetPredicate function do (and don't know how to translate it to sql query) so throws Not Supported Exception..
The same thing is with Func instead of Expression. Func is complied version of predicate (stored as delegate) - provider don't know how to translate delegates. When Expression is used, the predicate is stored as tree, so provider can "look inside" an expression and translate it correctly.
I need a little piece of magic. I believe what I am trying to do makes sense, but if it I've not seen a problem with the plan the reasons why would be just as welcome.
I have an expression
Expression<Func<Entity, bool>>
and I want to cast/convert or even create a whole new expression:
Expression<Func<Derived, bool>>
This is being used as an EF filter query, passed as an argument to a repository method. The repository returns an enumerable of Entity, so I could use covariance easy enough, but I want to do some post processing on the query in it's derived state before returning it.
It seems to me that EF must be doing this itself internally, but I'd like to be able to run my query so that the type of the result is Derived type rather than Entity.
Thanks for helping.
Working on the Expression level, you can build a new expression having the Derived type as parameter:
var entityExpr = (Expression<Func<Entity, bool>>)(e => e.Str == "");
var derivedExpr = Expression.Lambda<Func<Derived, bool>>(entityExpr.Body, entityExpr.Parameters);
If you have your expression Expression<Func<Entity, bool>> you can add a Cast<Derived> to it to filter down to all entities that are of that specific type.
Say I have a method with an input parameter named collectionSelector of type Func<TEntity, ICollection<TCollection>>.
I'd like to use this input parameter to load EF entities by using this method on an instance of DbContext:
context.Entry(entity).Collection(collectionExpression).Load()
The Collection method accepts a parameter of type Expression<Func<TEntity, ICollection<TElement>>>
I've searched around, but can't figure out how to initialize an Expression instance from an Func instance. Anyone an idea? Thanks in advance!
How about if you define your method to take an expression:
void Process(Expression<Func<TEntity,ICollection<TCollection>>> collectionSelector)
{
context.Entry(entity).Collection(collectionExpression).Load()
}
Now you can call it passing in a lambda:
Process(x=>x.GenerateCollection());
And the C# compiler will take care of converting the lambda to an expression for you.
I've searched around, but can't figure out how to initialize an Expression instance from an Func instance.
You can't. A Func is a delegate that points to a compiled method, there's no way to get an expression tree from that (well, maybe it's possible, but certainly not easily since you would need to decompile the method).
Depending on the context, a lambda expression can be compiled either to an anonymous method or to an expression tree. There is no conversion between the method and the expression...
I've been trying to learn more about using Lamba expression trees and so I created a simple example. Here is the code, this works in LINQPad if pasted in as a C# program.
void Main()
{
IEnumerable<User> list = GetUsers().Where(NameContains("a"));
list.Dump("Users");
}
// Methods
public IEnumerable<User> GetUsers()
{
yield return new User{Name = "andrew"};
yield return new User{Name = "rob"};
yield return new User{Name = "chris"};
yield return new User{Name = "ryan"};
}
public Expression<Func<User, bool>> NameContains(string namePart)
{
return u => u.Name.Contains(namePart);
}
// Classes
public class User
{
public string Name { get; set; }
}
This results in the following error:
The type arguments for method 'System.Linq.Enumerable.Where(System.Collections.Generic.IEnumerable, System.Func)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
However if I just substitute the first line in main with this:
IEnumerable<User> list = GetUsers().Where(u => u.Name.Contains("a"));
It works fine. Can tell me what I'm doing wrong, please?
The Enumerable.Where method takes a Func<T, bool>, not an Expression<Func<T, bool>>. Perhaps you're confusing with Queryable.Where, which does take an expression as a parameter... In your case you don't need an expression, you just need a delegate that can be executed against each item in the sequence. The purpose of expressions is (mostly) to be analysed and translated to something else (SQL for instance), to perform the query against an external data source
Change the return type of NameContains from Expression<Func<User, Bool>> to simply Func<User, Bool>. In this situation, there's no need to return the Expression, you actually want to return the compiled delegate. There's a difference between the expression that makes up the lambda, and the lambda (which is a delegate) itself.
If you send a lambda into a method, the method can accept the lambda either as an expression, or as a compiled delegate type, depending on what you specify in the parameters. If the incoming parameter type is an Expression, you can send in something that looks like a delegate, however, if the method is expecting a delegate, you have to give it a compiled delegate, not simply an expression. That being said, you can also do something like:
var certainUsers = GetUsers().Where(NameContains("a").Compile());
Which would compile the expression, and return a Func<User, Bool>.
Lambda expressions can be treated as either code (delegates) or as data (expression trees)
In your example your are attempting to treat the lambda expression as code.
You would use the Expression<> declaration when you want to treat the lambda expression as data.
Why would you want to do this?
Here is a quote from the Book Linq In Action,
" Expression trees can be given to tools at runtime, which use them to guide
their execution or translate them into something else, such as SQL in the case of
LINQ to SQL."
Using Expression Trees allows you to take the lambda expression and convert it to data, this is how Linq to SQL works, it takes the lambda expression or query operators or query expressions and converts them to SQL. You of course can view and modify the created expression tree once converted to sql.
There is a huge difference between Expression and Func<...>, the Func is a pure delegate you can invoke it directly, the expression is a data structure holds information about an expression like information about lambda expression or Linq Syntax (e.g. From x in list where x.Id = 1 select x). The expression cannot be invoked directly it must be compiled first, Expressions is used to convert the expression from a way to another like Link To Sql which converts an expression to Sql statements, the best way to do this to change the return type of the NameContains Method to Func insted of expression cuz you are working with Linq To Objects, but when using with Linq To Sql you can use both Expression or func.
Here the context for my question:
A common technique is to declare the parameter of a method as a Lambda expression rather than a delegate. This is so that the method can examine the expression to do interesting things like find out the names of method calls in the body of the delegate instance.
Problem is that you lose some of the intelli-sense features of Resharper. If the parameter of the method was declared as a delegate, Resharper would help out when writing the call to this method, prompting you with the x => x syntax to supply as the argument value to this method.
So... back to my question I would like to do the follow:
MethodThatTakesDelegate(s => s.Length);
}
private void MethodThatTakesDelegate(Func<string, object> func)
{
//convert func into expression
//Expression<Func<string, object>> expr = "code I need to write"
MethodThatTakesExpression(expr);
}
private void MethodThatTakesExpression(Expression<Func<string, object>> expr)
{
//code here to determine the name of the property called against string (ie the Length)
}
Everywhere that you're using the term "lambda expression" you actually mean "expression tree".
A lambda expression is the bit in source code which is
parameters => code
e.g.
x => x * 2
Expression trees are instances of the System.Linq.Expressions.Expression class (or rather, one of the derived classes) which represent code as data.
Lambda expressions are converted by the compiler into either expression trees (or rather, code which generates an expression tree at execution time) or delegate instances.
You can compile an instance of LambdaExpression (which is one of the subclasses of Expression) into a delegate, but you can't go the other way round.
In theory it might be possible to write such a "decompiler" based on the IL returned by MethodBase.GetMethodBody in some situations, but currently there are various delegates which can't be represented by expression trees. An expression tree represents an expression rather than a statement or statement block - so there's no looping, branching (except conditionals), assignment etc. I believe this may change in .NET 4.0, though I wouldn't expect a decompilation step from Microsoft unless there's a really good reason for one.
I don't believe it's possible to achieve what you'd like here. From the comments in your code it looks like you are attempting to capture the name of the property which did the assignment in MethodThatTakesExpression. This requires an expression tree lambda expression which captures the contexnt of the property access.
At the point you pass a delegate into MethodThatTakesDelegate this context is lost. Delegates only store a method address not any context about the method information. Once this conversion is made it's not possible to get it back.
An example of why this is not possible is that there might not even be a named method backing a delegate. It's possible to use ReflectionEmit to generate a method which has no name whatsoever and only exists in memory. It is possible though to assign this out to a Func object.
No, it is not possible.