dynamic method invocation in expression tree - c#

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)))

Related

Passing a method to a LINQ query

In a project I'm currently working on, we have many static Expressions that we have to bring in local scope with a variable when we call the Invoke method on them and pass our lambda expressions' arguments to.
Today, we declared a static method whose parameter is exactly the type that the query is expecting. So, my coworker and I were messing around to see if we could get this method to do the project in the Select statement of our query, instead of invoking it on the whole object, without bringing it into local scope.
And it worked! But we do not understand why.
Imagine code like this
// old way
public static class ManyExpressions {
public static Expression<Func<SomeDataType, bool> UsefulExpression {
get {
// TODO implement more believable lies and logic here
return (sdt) => sdt.someCondition == true && false || true;
}
}
}
public class ARealController : BaseController {
/* many declarations of important things */
public ARealClass( /* many ninjected in things */) {
/* many assignments */
}
public JsonNet<ImportantDataResult> getSomeInfo(/* many useful parameter */) {
var usefulExpression = ManyExpressions.UsefulExpression;
// the db context is all taken care of in BaseController
var result = db.SomeDataType
.Where(sdt => usefulExpression.Invoke(sdt))
.Select(sdt => new { /* grab important things*/ })
.ToList();
return JsonNet(result);
}
}
And then you get to do this!
// new way
public class SomeModelClass {
/* many properties, no constructor, and very few useful methods */
// TODO come up with better fake names
public static SomeModelClass FromDbEntity(DbEntity dbEntity) {
return new SomeModelClass { /* init all properties here*/ };
}
}
public class ARealController : BaseController {
/* many declarations of important things */
public ARealClass( /* many ninjected in things */) {
/* many assignments */
}
public JsonNet<SomeModelClass> getSomeInfo(/* many useful parameter */) {
// the db context is all taken care of in BaseController
var result = db.SomeDataType
.Select(SomeModelClass.FromDbEntity) // TODO; explain this magic
.ToList();
return JsonNet(result);
}
}
So when ReSharper prompts me to do this (which is not often, as this condition of matching the type that is expected by the Delegate isn't often satisfied), it says convert to a Method Group. I kind of vaguely understand that a Method Group is a set of methods, and the C# compiler can take care of converting the method group to an explicitly typed and appropriate overload for the LINQ provider and what not... but I'm fuzzy on why this works exactly.
What's going on here?
It's great to ask a question when you don't understand something, but the problem is that it can be hard to know which bit someone doesn't understand. I hope I help here, rather than tell you a bunch of stuff you know, and not actually answer your question.
Let's go back to the days before Linq, before expressions, before lambda, and before even anonymous delegates.
In .NET 1.0 we didn't have any of those. We didn't even have generics. We did though have delegates. And a delegate is related to a function pointer (if you know C, C++ or languages with such) or function as argument/variable (if you know Javascript or languages with such).
We could define a delegate:
public delegate int MyDelegate(double someValue, double someOtherValue);
And then use it as a type for a field, property, variable, method argument or as the basis of an event.
But at the time the only way to actually give a value for a delegate was to refer to an actual method.
public int CompareDoubles(double x, double y)
{
if (x < y) return -1;
return y < x ? 1 : 0;
}
MyDelegate dele = CompareDoubles;
We can invoke that with dele.Invoke(1.0, 2.0) or the shorthand dele(1.0, 2.0).
Now, because we have overloading in .NET, we can have more than one thing that CompareDoubles refers to. That isn't a problem, because if we also had e.g. public int CompareDoubles(double x, double y, double z){…} the compiler could know that you could only possibly have meant to assign the other CompareDoubles to dele so it's unambiguous. Still, while in the context CompareDoubles means a method that takes two double arguments and returns an int, outside of that context CompareDoubles means the group of all the methods with that name.
Hence, Method Group which is what we call that.
Now, with .NET 2.0 we got generics, which is useful with delegates, and at the same time in C#2 we got anonymous methods, which is also useful. As of 2.0 we could now do:
MyDelegate dele = delegate (double x, double y)
{
if (x < y) return -1;
return y < x ? 1 : 0;
};
This part was just syntactic sugar from C#2, and behind the scenes there's still a method there, though it has an "unspeakable name" (a name that is valid as a .NET name but not valid as a C# name, so C# names can't clash with it). It was handy if, as was often the case, one was creating methods just to have them used once with a particular delegate though.
Move forward a bit further, and at .NET 3.5 have covariance and contravariance (great with delegates) the Func and Action delegates (great for reusing the same name based on type, rather than having a bunch of different delegates which were often very similar) and along with it came C#3 which had lambda expressions.
Now, these are a bit like anonymous methods in one use, but not in another.
That's why we can't do:
var func = (int i) => i * 2;
var works out what it means from what's been assigned to it, but lamdas work out what they are from what they've been assigned to, so this is ambiguous.
It could mean:
Func<int, int> func = i => i * 2;
In which case it's shorthand for:
Func<int, int> func = delegate(int i){return i * 2;};
Which in turn is shorthand something like for:
int <>SomeNameImpossibleInC# (int i)
{
return i * 2;
}
Func<int, int> func = <>SomeNameImpossibleInC#;
But it can also be used as:
Expression<Func<int, int>> func = i => i * 2;
Which is shorthand for:
Expression<Func<int, int>> func = Expression.Lambda<Func<int, int>>(
Expression.Multiply(
param,
Expression.Constant(2)
),
param
);
And we also with .NET 3.5 have Linq which makes heavy use of both of these. Indeed, Expressions is considered part of Linq and is in the System.Linq.Expressions namespace. Note that the object we get here is a description of what we want done (take the parameter, multiply it by two, give us the result) not of how to do it.
Now, Linq operates in two main ways. On IQueryable and IQueryable<T> and on IEnumerable and IEnumerable<T>. The former defines operations to be used on "a provider" with just what "a provider does" being up to that provider, and the latter defines the same operations on in-memory sequences of values.
We can move from one to the other. We can turn an IEnumerable<T> into an IQueryable<T> with AsQueryable which will give us a wrapper on that enumerable, and we can turn the IQueryable<T> into an IEnumerable<T> just by treating it as one, because IQueryable<T> derives from IEnumerable<T>.
The enumerable form uses the delegates. A simplified version of how Select works (there are many optimisations this version leaves out, and I'm skipping error checking and in indirection to ensure that error checking happens immediately) would be:
public static IEnumerable<TResult> Select(this IEnumerable<TSource> source, Func<TSource, TResult> selector)
{
foreach(TSource item in source) yield return selector(item);
}
The queryable version on the other hand works by taking the expression tree from the Expression<TSource, TResult> making it part of an expression that includes the call to Select, and the source queryable, and returns an object wrapping that expression. So in other words a call to queryable's Select returns an object that represents a call to queryable's Select!
Just what is done with that depends on the provider. Database providers turn them into SQL, enumerables call Compile() on the expression to create a delegate and then we're back at the first version of Select above, and so on.
But that history considered, let's go backwards through the history again. A lambda can represent either an expression or a delegate (and if an expression, we can Compile() it to get the same delegate). A delegate is a way of pointing to a method through a variable, and a method is part of a method group. All of this is built on technology which in the first version could only be called by creating a method and then passing that.
Now, lets say we have a method that takes a single argument and has a result.
public string IntString(int num) { return num.ToString(); }
Now lets say we referenced it in a lambda selector:
Enumerable.Range(0, 10).Select(i => IntString(i));
We have a lambda creating an anonymous method for a delegate, and that anonymous method in turn calls a method with the same argument and return types. In a way that's a bit like if we had:
public string MyAnonymousMethod(int i){return IntString(i);}
MyAnonymousMethod is a bit pointless here; all it does is call IntString(i) and return the result, so why not just call IntString in the first place and cut out going through that method:
Enumerable.Range(0, 10).Select(IntString);
We've cut out a needless (though see note below about delegate caching) level of indirection by taking the lambda-based delegate and converting it to a method group. Hence ReSharper's advice "Convert to Method Group" or however it's worded (I don't use ReSharper myself).
There is though something to be careful of here. IQueryable<T>'s Select only takes expressions, so the provider can try to work out how to convert it to its way of doing stuff (e.g. SQL against a database). IEnumerable<T>'s Select only takes delegates so they can be executed in the .NET application itself. We can go from the former to the latter (when the queryable is really a wrapped enumerable) with Compile(), but we can't go from the latter to the former: We don't have a way of taking a delegate and turning it into an expression that means anything other than "call this delegate" which isn't something that can be turned into SQL.
Now when we use a lambda expression like i => i * 2 it will be an expression when used with IQueryable<T> and a delegate when used with IEnumerable<T> due to overload resolution rules favouring the expression with queryable (as a type it can handle both, but the expression form works with the most derived type). If though we explicitly give it a delegate, whether because we typed it somewhere as Func<> or it comes from a method group, then the overloads taking expressions aren't available and those taking delegates are used. This means it doesn't get passed to the database but rather the linq expression up to that point becomes the "database part" and it gets called and the rest of the work done in memory.
95% of the time that's best avoided. So 95% of the time if you get advice of "convert to method group" with a database-backed query you should think "uh oh! that's actually a delegate. Why is that a delegate? Can I change it to be an expression?". Only the remaining 5% of the time should you think "that'll be slightly shorter if I just pass in the method name". (Also, using a method group instead of a delegate prevents caching of delegates the compiler can do otherwise, so it might be less efficient).
There, I hope I covered the bit that you didn't understand in the course of all that, or at least there's a bit here you can point to and say "that bit there, that's the bit I don't grok".
Select(SomeModelClass.FromDbEntity)
This uses Enumerable.Select which is not what you want. This transitions out of "queryable-LINQ" into LINQ to objects. This means the database cannot execute this code.
.Where(sdt => usefulExpression.Invoke(sdt))
Here, I assume you meant .Where(usefulExpression). This passes the expression into the expression tree underlying the query. The LINQ provider can translate this expression.
When you perform experiments like this use SQL Profiler to see what SQL goes over the wire. Make sure all relevant parts of the query are translatable.
I don't want to disappoint you, but there is no magic at all. And I would suggest you to be very careful with this "new way".
Always check the result of a function by hovering it in VS. Remember that IQueryable<T> "inherits" IEnumerable<T> and also Queryable contains the extension methods with the same names as the Enumerable, and the only difference is that the former works with Expression<Func<...>> while the later just with Func<..>.
So anytime you use Func or method group over IQueryable<T>, the compiler will pick the Enumerable overload, thus silently switching from LINQ to Entities to LINQ to Objects context. But there is a huge difference between the two - this former is executed in database while the later in memory.
The key point is to stay as long as possible in the IQueryable<T> context, so the "old way" should be preferred. E.g. from your examples
.Where(sdt => sdt.someCondition == true && false || true)
or
.Where(ManyExpressions.UsefulExpression)
or
.Where(usefulExpression)
but not
.Where(sdt => usefulExpression.Invoke(sdt))
And never
.Select(SomeModelClass.FromDbEntity)
This solution threw up some red flags for me. Key among them was:
var result = db.SomeDataType
.Select(SomeModelClass.FromDbEntity) // TODO; explain this magic
.ToList(); // <<!!!!!!!!!!!!!
Whenever you're dealing with Entity Framework, you can read "ToList()" as "Copy the whole thing into memory." So "ToList()" should only be done at the last possible second.
Consider: there are lots of useful object you can pass around when dealing with EF:
The database context
The specific dataset you're targeting (e.g. context.Orders)
Queries against a context:
.
var query = context.Where(o => o.Customer.Name == "John")
.Where(o => o.TxNumber > 100000)
.OrderBy(o => o.TxDate);
//I've pulled NO data so far! "var query" is just an object I can pass around
//and even add on to! For example, I can now do this:
query = query.ThenBy(o => o.Items.Description); //and now I've appended that to my query
The real magic is that those lambdas can be thrown in to a variable too. Here's a method I use in one of my projects to do that:
/// <summary>
/// Generates the Lambda "TIn => TIn.memberName [comparison] value"
/// </summary>
static Expression<Func<TIn, bool>> MakeSimplePredicate<TIn>(string memberName, ExpressionType comparison, object value)
{
var parameter = Expression.Parameter(typeof(TIn), "t");
Expression left = Expression.PropertyOrField(parameter, memberName);
return (Expression<Func<TIn, bool>>)Expression.Lambda(Expression.MakeBinary(comparison, left, Expression.Constant(value)), parameter);
}
With this code, you can write something like the following:
public GetQuery(string field, string value)
{
var query = context.Orders;
var condition = MakeSimplePredicate<Order>(field, ExpressionType.Equal, value);
return query.Where(condition);
}
The best thing is that at this time, no data call has been. You can continue to add conditions as you wish. When you're ready to fetch the data, simply iterate through it or call ToList().
Enjoy!
Oh, and check this out if you'd like to see a more thoroughly-developed solution, albeit from a different context.
My Post on Linq Expression Trees

Restrict lambda expression argument to the properties of a class

I have a base class which needs to process the names of the properties of derived classes (explicit access). To do so, I created a method which takes a lambda expression as input:
private string GetMemberName(Expression<Func<object>> expression)
{
//gets the property name (MemberExpression or UnaryExpression)
//out of scope
return propertyName;
}
This allows me to call the method like so:
derived.GetMemberName(() => derived.MyPropertyInt);
derived.GetMemberName(() => derived.MyPropertyStr);
The problem is that object is not restrictive at all. I can also call:
derived.GetMemberName(() => "something"); //does not "return" anything but compiles (out of scope)
derived.GetMemberName(() => anotherClass.RandomMember); //not derived from "base"
How can I restrict the GetMemberName method so that it can only accept as input the members of the classes which derive from my base class? Setting GetMemberName(Expression<Func<MyBaseClass>> expression) restricts access to an entire class. Setting GetMemberName(Expression<Func<MyBaseClass, object>> expression) restricts access to the current instance but still allows "random" objects to be passed.
EDIT:
The comment for derived.GetMemberName(() => "something"); was in the context of returning the property name, not the "value" of the lambda expression. The GetPropertyName method does not return anything, due to the fact that I'm only analyzing MemberExpression or UnaryExpression.
How can I restrict the GetMemberName method so that it can accept only members of the classes which derive from my base class?
It's not clear what you mean by "accept" here, but if you're trying to restrict the set of valid lambda expressions to ones which uses members of your class, you can't. Lambda expressions and expression trees happen to be useful for getting this information, but that's not what they're designed for, so there are no specific features accommodating this. You'll always be able to use a lambda expression which doesn't just use a property.
The simplest approach is probably just to check this at execution time. You won't be able to stop people abusing your method at compile-time, but so long as it's simple to do the right thing, I wouldn't worry too much about callers doing the wrong thing - just make the error message really clear.

How to define LINQ expression from generic Func delegate?

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...

Cache delegate of compiled Dynamic Linq Func<> *without* params?

I'm using the Dynamic.ParseLambda method from the Dynamic LINQ library to create expressions, compile each to a Func<>, and cache each in a dictionary:
// parse some dynamic expression using this ParseLambda sig:
Expression<Func<TArgument,TResult>> funcExpr =
System.Linq.Dynamic.ParseLambda<TArgument, TResult>(
expressionString, // string for dyn lambda expression
parameters); // object[] params
// then compile & cache the output of this as a delegate:
Func<TArgument,TResult> func = funcExpr.Compile(); //<-cache this
// then to execute, use:
return func(entityInstance);
The problem is, this forces me to cache a different delegate instance for every distinct set of parameter values. This seems kind of wasteful; all the overhead with Dynamic LINQ is in the parsing and compilation; once created, the delegates are near directly coded lambdas in performance. Is there any way to move the params outside of the expression, so I can pass different values to a common cached delegate in when I call it (instead of when I'm creating it)?
// e.g. with params...
return func(entityInstance,parameters);
// or if params are the issue, multiple signatures are ok:
return func(entityInstance, intValue, stringValue);
I don't see any parameter-free .ParseLambda or .Compile signatures in System.Linq.Dynamic, so my hopes aren't high. Anyone know of a quick way to achieve this?
Thanks!
There is a trick here, that I have used before; you do something like an Expression<Func<object[], object>>, and embed the fetch-by-index and casting inside the expression. Then you have as many parameters as you could want, a single signature, and reasonable performance. It does, however, make writing the lambda a bit tricker.
I don't have my old code for this "to hand", but if I needed to reverse engineer it, I would simply write something typical like the following, and then look in reflector to see what it used:
Expression<Func<object[], object>> func = arr => ((string)arr[0]) + (int)arr[1];
(in particular, paying attention to the indexer usage, the casting from inputs, and the casting to output)

Is it possible to cast a delegate instance into a Lambda expression?

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.

Categories

Resources