Executing collection of Expressions - c#

I have this
List<Expression> levl1expressions;
Collection contains binary expressions like Expression.NotEqual, Expression.Equal
etc
I have another collection which is And and Or Conditions
List<Expression> levl2expressions;
I would like to execute these two expression collections
levl1expressions[0]+levl2expressions[0]+levl1expressions[1]+levl2expressions[1]....
Is this possible?
eg:
object.Name = "something" && object.Category != "myCategory"(//I transformed the string to expressions)
levl1expressions[0] = Expression.Equal(
Expression.Property(Expression.Parameter(typeof(MyObject), "m")),
Expression.Constant("something")
levl1expressions[1] = Expression.NotEqual(....)
levl2expressions[0]= Expression.And(/*Would like to join levl1expressions*/)

If I understand your problem correctly, you should not use lists at all. Instead you can create a single expression which will look like that:
var finalExpression = Expression.And(Expression.Equal(...), Expression.NotEqual(...));
If you would like to combine more logical operators then you can use a result of Expression.And as the right operand:
var finalExpression = Expression.And(Expression.Equal(...), Expression.And(Expression.NotEqual(...), Expression.Equal(...)));
To invoke the expression you need to compile first:
var action = Expression.Lambda<Action<bool>>(finalExpression).Compile();
Here Action<bool> is specifying what kind of function you create. Action<bool> basically means a function which is returning a boolean and has no parameters. Once you have that you can simply call it:
var result = action();
Bear in mind that expression compilation process is very expensive. Cache the result if you can.

Related

Can I dynamically create an expression representing a lambda which calls a method on the input parameter?

Let's say I have an object of a certain class A.
Let's say I need an Expression which calls method M on class A.
Is this even doable?
Basically, I need to programatically get this lambda
a => a.M();
The trick is, I want to do this generically, i.e. I plan to use reflection to figure out that the method is called M and what parameters it wants.
I tried using Expression.Lambda(MethodCallExpression method, ParameterExpression params).
The issue there is that when I define the method call expression, I have to specify an instance (or leave it at null if it's a static method, which it isn't). I don't want this. I want whatever the parameter is passed into the lambda (a in my example) to be the instance.
Is this possible?
Yes, it's possible to construct a linq expression at a runtime.
E.g. below is an example of constructing an expression of a method call which returns an object. This is really a dummy example as it's better to avoid object in favor of strict types.
static Expression<Func<T, object>> ComposeMethodCallExpressionAsFuncObject<T>(string methodName)
{
MethodInfo mi = typeof(T).GetMethod(methodName, types: new Type[0])
?? throw new ArgumentException($"There is no '{methodName}' method in the '{typeof(T).Name}' with the empty arguments list!");
var paramExpression = Expression.Parameter(typeof(T));
var methodCallExpression = Expression.Call(paramExpression, mi);
var result = Expression.Lambda<Func<T, object>>(methodCallExpression, paramExpression);
return result; // (T obj) =>obj.methodName()
}
, and example of usage:
int foo = 9988;
var expression = ComposeMethodCallExpressionAsFuncObject<int>(nameof(int.ToString));
//expression: (int obj) => obj.ToString()
var result = expression.Compile()(foo);
Assert.AreEqual("9988", result);

How to concatenate a property expression and a lambda using Select?

I would like to create the following expression dynamically:
e.Collection.Select(inner => inner.Property)
I created this code to do it, however I have an issue when I execute the expression call, someone knows what I'm doing wrong?
private static Expression InnerSelect<TInnerModel>(IQueryable source, ParameterExpression externalParameter, string complexProperty)
{
// Creates the expression to the external property. // this generates: "e.Collection".
var externalPropertyExpression = Expression.Property(externalParameter, complexProperty);
// Creates the expression to the internal property. // this generates: "inner => inner.Property"
var innerParameter = Expression.Parameter(typeof(TInnerModel), "inner");
var innerPropertyExpression = Expression.Property(innerParameter, "Property");
var innerLambda = Expression.Lambda(innerPropertyExpression, innerParameter);
return Expression.Call(typeof(Queryable), "Select", new [] { typeof(TInnerModel) }, externalPropertyExpression, innerLambda);
}
Error:
No generic method 'Select' 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.
So, first off, the primary problem is very simple. As the error message says, you haven't passed enough type arguments to Select. But when you fix that, you'll still have a problem, and that problem will be much harder for you to see and understand.
Let's dig into that.
You wish to represent this as an expression tree:
e.Collection.Select(inner => inner.Property)
Let's begin by rewriting it in its non-extension-method form.
Queryable.Select<A, B>(e.Collection, inner => inner.Property)
Where A is the collection member type and B is the type of Property.
Now, suppose you had this expression in your program. What would it actually do at runtime? It would construct an expression tree for the lambda and pass it to Queryable.Select. That is, it would do something like:
var innerParameter = parameterFactory(whatever);
var lambdaBody = bodyFactory(whatever);
var lambda = makeALambda(lambdaBody, innerParameter);
Queryable.Select<TInnerModel>(e.Collection, lambda);
Right? You with me so far?
Now, suppose we wish to translate this program fragment to an expression tree that could itself be the body of a lambda. That would be:
var theMethodInfoForSelect = whatever;
var receiverE = valueFactory(whatever);
var thePropertyInfoForCollection = whatever;
var theFirstArgument = propertyFactory(receiverE, thePropertyInfoForCollection);
...
Again, with me so far? Now, the crucial question: what is the second argument? It is NOT the value of lambda, which is what you are passing. Remember, what we are doing here is constructing an expression tree which represents the code that the compiler is generating for that thing, and the expression tree that is in lambda is not that. You're mixing levels!
Let me put it this way: the compiler is expecting "add one and three". You are passing 4. Those are very different things! One of them is a description of how to obtain a number and the other one is a number. You are passing an expression tree. What the compiler is expecting is a description of how to obtain an expression tree.
So: do you have to now write code that generates expression trees for all of lambda's construction code? Thank goodness no. We provided you a handy way to turn an expression tree into a description of how to produce an expression tree, which is the Quote operation. You need to use it.
So, what is the right sequence of events that you need to do to build your expression tree? Let's walk through it:
First, you'll need a ParameterExpression of the type of e, which you already have in hand. Let's suppose that is:
ParameterExpression eParam = Expression.Parameter(typeof(E), "e");
Next, you will need a method info for the Select method. Let's suppose you can correctly get that.
MethodInfo selectMethod = whatever;
That method takes two arguments, so let's make an array of argument expressions:
Expression[] arguments = new Expression[2];
You'll need a property info for your Collection property. I assume you can get that:
MethodInfo collectionGetter = whatever;
Now we can build the property expression:
arguments[0] = Expression.Property(eParam, collectionGetter);
Super. Next we need to start building that lambda. We need a parameter info for inner:
ParameterExpression innerParam = Expression.Parameter(typeof(Whatever), "inner");
We'll need a property info for Property, which I assume you can get:
MethodInfo propertyGetter = whatever;
Now we can build the body of the lambda:
MemberExpression body = Expression.Property(innerParam, propertyGetter);
The lambda takes an array of parameters:
ParameterExpression[] innerParams = { innerParam };
Build the lambda from the body and the parameters:
var lambda = Expression.Lambda<Func<X, int>>(body, innerParams);
Now the step you missed. The second argument is the quoted lambda, not the lambda:
arguments[1] = Expression.Quote(lambda);
Now we can build the call to Select:
MethodCallExpression callSelect = Expression.Call(null, selectMethod, arguments);
And we're done.
Give someone an expression tree and you give them an expression tree for a day; teach them how to find expression trees themselves and they can do it for a lifetime. How did I do that so fast?
Since I wrote the expression tree code generator, I had some immediate familiarity with the problem that you were likely to have. But that was ten years ago, and I did not do the above entirely from memory. What I did was I wrote this program:
using System;
using System.Linq.Expressions;
public interface IQ<T> {}
public class E
{
public IQ<X> C { get; set; }
}
public class X
{
public int P { get; set; }
}
public class Program
{
public static IQ<R> S<T, R>(IQ<T> q, Expression<Func<T, R>> f) { return null; }
public static void Main()
{
Expression<Func<E, IQ<int>>> f = e => S<X, int>(e.C, c => c.P);
}
}
Now I wished to know what code was generated by the compiler for the body of the outer lambda, so I went to https://sharplab.io/, pasted in the code, and then clicked on Results --> Decompile C#, which will compile the code to IL and then decompile it back to human-readable C#.
This is the best way I know of to quickly understand what the C# compiler is doing when it builds an expression tree, regardless of whether you know the compiler source code backwards and forwards. It's a very handy tool.

using expression trees to compare objects by a single property nets InvalidOperationException

I am trying to use Expression Trees because based on description, that seems to be the most correct (performant, configurable) approach.
I expect to be able to craft a statement that gets the first item from the existingItems collection that matches the propertyNameToCompareOn value of the incomingItem.
I have a method with the following signature and simulated code body...
DetectDifferences<T>(List<T> incomingItems, List<T> existingItems)
{
var propertyNameToCompareOn = GetThisValueFromAConfigFile(T.FullName());
//does this belong outside of the loop?
var leftParam = Expression.Parameter(typeof(T), "left");
var leftProperty = Expression.Property(leftParam, identField);
var rightParam = Expression.Parameter(typeof(T), "right");
var rightProperty = Expression.Property(rightParam, identField);
//this throws the error
var condition = Expression.Lambda<Func<T, bool>>(Expression.Equal(leftProperty, rightProperty));
foreach (var incomingItem in incomingItems) //could be a parallel or something else.
{
// also, where am I supposed to provide incomingItem to this statement?
var existingItem = existingItems.FirstOrDefault(expression/condition/idk);
// the statement for Foo would be something like
var existingFoos = exsistingItems.FirstOrDefault(f => f.Bar.Equals(incomingItem.Bar);
//if item does not exist, consider it new for persistence
//if item does exist, compare a configured list of the remaining properties between the
// objects. If they are all the same, report no changes. If any
// important property is different, capture the differences for
// persistence. (This is where precalculating hashes seems like the
// wrong approach due to expense.)
}
}
At the marked line above, I get an "Incorrect number of parameters supplied for lambda declaration" InvalidOperationException. At this point I am just hacking crap together from the web and I really dont know what this wants. There are a bunch of overloads that VS can full my screen with, and none of the examples make sense from the articles on MSDN/SO.
PS - I dont really want an IComparer or similar implementation if it can be helped. I can do that with reflection. I do need to make this as rapid as possible, but allow it to be called for multiple types, hence the choice of expression trees.
When working with expression trees, it's important to first understand, in real code, what you want to do.
I always begin by first writing out (in static code) what the resulting expression looks like with real C# lambda syntax.
Based on your description, your stated goal is that you should be able to (dynamically) look up some property of the type T that gives some sort of quick comparison. How would you write this if both T and TProperty were both known at compile time?
I suspect it would look something like this:
Func<Foo, Foo, bool> comparer = (Foo first, Foo second) =>
first.FooProperty == second.FooProperty;
Right away we can see that your Expression is wrong. You don't need one input T, you need two!
It should also be obvious why you're getting the InvalidOperationException as well. You never supplied any parameters to your lambda expression, only the body. Above, 'first' and 'second' are the parameters provided to the lambda. You'll need to provide them to the Expression.Lambda()call as well.
var condition = Expression.Lambda<Func<T,T, bool>>(
Expression.Equal(leftProperty, rightProperty),
leftParam,
rightParam);
This simply uses the Expression.Lambda(Expression, ParameterExpression[]) overload for Expression.Lambda. Each ParameterExpression is the parameter that is used in the body. That's it. Don't forget to .Compile() your expression into a delegate if you want to actually invoke it.
Of course this doesn't mean that your technique will be necessarily fast. If you're using fancy expression trees to compare two lists with a naive O(n^2) approach, it won't matter.
Here's a method to make a property access expression;
public static Expression<Func<T, object>> MakeLambda<T>(string propertyName)
{
var param = Expression.Parameter(typeof(T));
var propertyInfo = typeof(T).GetProperty(propertyName);
var expr = Expression.MakeMemberAccess(param, propertyInfo);
var lambda = Expression.Lambda<Func<T, object>>(expr, param);
return lambda;
}
which you can use like this;
var accessor = MakeLambda<Foo>("Name").Compile();
accessor(myFooInstance); // returns name
Making your missing line
var existingItem = existingItems.FirstOrDefault(e => accessor(e) == accessor(incomingItem));
Be aware the == only works well for value types like ints; careful of comparing objects.
Here's proof the lambda approach is much faster;
static void Main(string[] args)
{
var l1 = new List<Foo> { };
for(var i = 0; i < 10000000; i++)
{
l1.Add(new Foo { Name = "x" + i.ToString() });
}
var propertyName = nameof(Foo.Name);
var lambda = MakeLambda<Foo>(propertyName);
var f = lambda.Compile();
var propertyInfo = typeof(Foo).GetProperty(nameof(Foo.Name));
var sw1 = Stopwatch.StartNew();
foreach (var item in l1)
{
var value = f(item);
}
sw1.Stop();
var sw2 = Stopwatch.StartNew();
foreach (var item in l1)
{
var value = propertyInfo.GetValue(item);
}
sw2.Stop();
Console.WriteLine($"{sw1.ElapsedMilliseconds} vs {sw2.ElapsedMilliseconds}");
}
As someone's also pointed out, though, the double-loop in the OP is O(N^2) and that should probably be the next consideration if efficiency is the driver here.

Convert generic getter expression to object getter expression

I have a expression getter like that:
var expression = () => SomeInstance.Nr;
It is passed into a method:
public void AddExpression<T>(Expression<Func<T>> func)
Now I would like to convert that generic expression to
Expression<Func<object>>
I'm not quite sure if I can even do that. I tried something like this:
var converted = Expression.Convert(func, typeof(object));
var objectExpression = Expression.Lambda<Func<object>>(Expression.Call(converted.Method), func.Parameters);
But when I call
var number = objectExpression.Compile()();
It won't return the property value.
The code can be tested here:
http://volatileread.com/utilitylibrary/snippetcompiler?id=25062
Update:
It seems that the invoke is wrapped a second time:
var converted = Expression.Convert(func, typeof(object));
var objectExpression = Expression.Lambda<Func<object>>(Expression.Call(converted.Method), func.Parameters);
var anotherDelegate = objectExpression.Compile().Invoke(); // would have expected the value here
var value = ((Delegate)anotherDelegate).DynamicInvoke(); // this now does return the value
Don't use Expression.Call on delegates - that's only there to call methods. Instead, you want to use Expression.Invoke, which is specifically there to invoke delegates. Also, the key to doing expression trees is wrapping - invoke the inner delegate, convert the result, and wrap this in a lambda:
Expression<Func<int>> inputExpression = () => 42;
var newLambda =
Expression.Lambda<Func<object>>
(
Expression.Convert
(
Expression.Invoke(inputExpression),
typeof(object)
)
);
Console.WriteLine(newLambda.Compile()()); // Prints 42.
newLambda is Expression<Func<object>> and invoking it gives you 42, as you'd expect.
And of course, this makes it rather easy to make this an extension method (although you probably want to use templates to generate all the different Func<...> overloads if you need them).
Do note that this is only going to work if whatever LINQ provider you're using actually supports Invoke - in this case, it's not a problem because the lambda compiler can handle it, but if you need to use something like this with e.g. EntityFramework, you'll need to take a slightly different approach - you'll need to unwrap the inner lambda, convert the body of the inner lambda, and then wrap it again in another lambda. For a parameter-less expression, this is rather easy:
Expression<Func<int>> inputExpression = () => 42;
var newLambda =
Expression.Lambda<Func<object>>
(
Expression.Convert(inputExpression.Body, typeof(object))
);
Console.WriteLine(newLambda.Compile()()); // Prints 42.
Also, for completeness, note that this only works if the inner expression is really a constant expression, and not a quote - but if you needed quoted nested expressions, you probably wouldn't be asking this question :D

Multiple assignment operations in one lambda expression

I am trying to create a dynamic lambda expression (parsed from text), that does more than one assignment. Creating the individual assignments was fairly easy, however I am stuck on how to combine them. So what I'm trying to achieve is the same as:
Action<Entity> action = (entity) =>
{
entity.Property1 = "1";
entity.Property2 = "2";
};
Is there a way to combine more than one Expression.Assign expressions into one (since Expression.Lambda only takes one Expression as input)?
--Edit:
So for clarification the code I wrote was just pseudo-code, so the typo (now corrected) doesn't change anything. The code I have right now is something like :
Expression parameter = Expression.Parameter(typeof(Entity), "param");
Expression firstProperty = Expression.Property(parameter, "Property1");
Expression first = Expression.Assign(firstProperty, "1");
Expression secondProperty = Expression.Property(parameter, "Property2");
Expression second = Expression.Assign(secondProperty, "2");
Expression final = [INSERT MAGIC HERE]
Action<Entity> action = Expression.Lambda<Action<Entity>>(final, entity).Complie();
Note that the property name actually come from text input, and the number of assigment expressions isn't limited to 2, it's just for demonstration purposes. My question is, is there an expression the lets me combine the assigment expressions or do I have to create different lambdas for each one?
Try this magic:
Expression.Block(first, second);

Categories

Resources