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...
Related
I have a Lazy<T> initialized with a lambda. How to see the body of the initializing lambda while debugging? I expect to have something like the DebugView of the Expression class but I've found nothing like that.
Because Lazy<T> takes a delegate, there is no Expression class involved. Your lambda is compiled like any other code in your project and there is no preview of that code during debug.
Lambda expression can be compiled either into IL or transformed into Expression Tree. Which one happens depends on the context. If your parameter is declared as delegate regular IL code will be generated. If it's Expression<TFunc> you'll get expression tree which can be previewed.
It's nicely explained on MSDN, based on Where method, which has two versions: Enumerable.Where which takes Func<T, bool> and Queryable.Where which takes Expression<Func<T, bool>>.
When you use method-based syntax to call the Where method in the
Enumerable class (as you do in LINQ to Objects and LINQ to XML) the
parameter is a delegate type System.Func<T, TResult>. A lambda
expression is the most convenient way to create that delegate. When
you call the same method in, for example, the System.Linq.Queryable
class (as you do in LINQ to SQL) then the parameter type is an
System.Linq.Expressions.Expression<Func> where Func is any of the Func
delegates with up to sixteen input parameters. Again, a lambda
expression is just a very concise way to construct that expression
tree. The lambdas allow the Where calls to look similar although in
fact the type of object created from the lambda is different.
When constructing an expression tree, I have to use nodes invoking external methods in order to obtain values the expression could then continue evaluation with.
These methods are supplied as Func<T> and my code has no knowledge of where they originate from.
What is the most correct way of performing the mentioned invocation? I've tried something like this:
private Dictionary<string, Delegate> _externalSymbols;
private Expression _forExternalSymbol(string identifier)
{
Delegate method = _externalSymbols[identifier];
return Expression.Call(method.Method);
}
which works as long as the method fetched from the dictionary was created in compile-time. However, in case of Func<T> being a dynamic method obtained, for instance, by compiling another expression in runtime, this won't work out throwing
ArgumentException: Incorrect number of arguments supplied for call to method 'Int32 lambda_method(System.Runtime.CompilerServices.ExecutionScope)'
The desired effect may be achieved by wrapping the given function into one extra expression, but that seems quite hideous comparing to what it used to look like:
private Expression _forExternalSymbol(string identifier)
{
Delegate method = _externalSymbols[identifier];
Expression mediator = method is Func<double> ?
(Expression)(Expression<Func<double>>)(() => ((Func<double>)method)()) :
(Expression<Func<string>>)(() => ((Func<string>)method)());
return Expression.Invoke(mediator);
}
Also, this is hardly an extensible approach should I need to add support for types other than double and string.
I would like to know if there are better options which would work with dynamically created methods (preferably applicable to .NET 3.5).
which works as long as the method fetched from the dictionary was created in compile-time
No, it works as long as the method is static. For example, it also won't work if the delegate is a lambda that references something from its parent score (i.e. it's a closure).
The correct way to invoke a delegate is to use Expression.Invoke(). To get an Expression that represents your delegate, use Expression.Constant():
Expression.Invoke(Expression.Constant(method)))
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.
At the page code.google.com/p/fakeiteasy/ I've noticed the line:
A.CallTo(() => shop.GetTopSellingCandy()).Returns(lollipop);
so the question is - how to pass a lambda expression as a method parameter ?
This function takes a parameter of type Func<T> (A normal delegate with a generic parameter), or, more likely, Expression<Func<T>> (an expression tree).
The function itself probably has a generic parameter which is inferred from the method passed.
By taking an expression tree, the function is able to inspect the code inside the expression and see what it does.
The code you've given is doing exactly that - passing a lambda expression as a paramter to a method call.
CallTo might have the signature 'CallTo(Action action)'. So lambda is passed as a delegate
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.