I want to provide a set of filters for a user to pick from, and each filter will correspond to an Expression<Func<X, bool>>. So, I might want to take a dynamic list of available items ('Joe', 'Steve', 'Pete', etc), and create a collection of "hard-coded" filters based on those names, and let the user select which filter(s) he wants to use. My problem is that even when I try to "hard-code" my expression based on a string value from the dynamic list, the expression is still storing the value as, what looks to me, a property hanging off of an anonymous type (and I don't know how to serialize the anon. type). Sorry if this is confusing, I'm not quite sure how to articulate this.
Here's my sample code:
public class Foo
{
public string Name { get; set; }
}
static void Main(string[] args)
{
Foo[] source = new Foo[]
{
new Foo() { Name = "Steven" } ,
new Foo() { Name = "John" } ,
new Foo() { Name = "Pete" },
};
List<Expression<Func<Foo, bool>>> filterLst = new List<Expression<Func<Foo, bool>>>();
foreach (Foo f in source)
{
Expression<Func<Foo, bool>> exp = x => x.Name == f.Name;
filterLst.Add(exp);
}
}
}
My problem is that when I look at when I look at the body of my expression, it reads as follows:
(x.Name = value(ConsoleApplication1.Program+<>c__DisplayClass3).value)
When what I really want is for the first one to read like this:
(x.Name = "Steven")
(if I change my code to this, instead, that's exactly what I get:
Expression<Func<Foo, bool>> exp = x => x.Name == "Steven";
)
I've tried forcing my value to a local string value before sticking it into the Expression, but it doesn't seem to help:
List<Expression<Func<Foo, bool>>> filterLst = new List<Expression<Func<Foo, bool>>>();
foreach (Foo f in source)
{
string value = f.Name;
Expression<Func<Foo, bool>> exp = x => x.Name == value;
filterLst.Add(exp);
}
I don't understand why (or really even how) it's still looking at some anonymous type even once I'm using a local variable that is declared to a string. Is there a way to make this work as I want it to?
The anon-type is actually the compiler-generated type it is using to perform capture of the variables. With delegates you can hack around this by implementing the capture by hand, but not with lambda expressions compiled to expression-trees.
Two choices:
build the expression tree explicitely on code via Expression.Constant etc
learn how to handle the anon types
The latter isn't too bad actually; they are just MemberExpression typically, although I have some code kicking around that covers this in full detail. I can also provide examples of buildin the expression tree, but I'm not at a PC at the moment and it doesn't lend itself well to iPod typing...
From a brief read of the question I'd look at the first option more than the second.
Oh, and watch out; the first foreach code in the question looks susceptible to the notorious l-value capture issue ;)
Edit: I found a PC ;p
var param = Expression.Parameter(typeof(Foo), "x");
var body = Expression.Equal(
Expression.PropertyOrField(param, "Name"),
Expression.Constant(f.Name, typeof(string)));
var exp = Expression.Lambda<Func<Foo, bool>>(body, param);
filterLst.Add(exp);
Marc Gravell's answer is correct, and here's how you'd implement his first choice:
var filters =
from f in source
let param = Expression.Parameter(typeof(Foo),"x")
select Expression.Lambda<Func<Foo, bool>>(
Expression.Equal(
Expression.Property(param, "Name"),
Expression.Constant(f.Name)), param);
But this typically isn't necessary. Your second example of the for loop should work with all major LINQ providers. Is there a reason you need the expression to use constants?
Related
There are methods in MongoDB C# driver (or any other libraries) that expect an expression only as a parameter like:
query.SortByDescending(x => x.Name) // sort by name for example
What I would like to do is to receive the field "Name" as a string and be able to sort by it at runtime:
var sortBy = "Name";
query.SortByDescending(x => x."SortyBy") // something like this
i.e how to create an expression to be x => x.(value of sortBy)?
This question basically has the same answer as your question yesterday.
The reason the answer is essentially the same is simply that FieldDefinition<T> is implicitly castable from string, so you can pass a string anywhere you see a FieldDefinition<T> argument.
Therefore, we can use the .Sort method (since that takes a SortDefinition<T>) and use Builders<T>.Sort.Descending which takes a FieldDefinition<TElement> and returns the SortDefinition<T> that we need:
query = query.Sort(Builders<Items>.Sort.Descending(sortBy));
I'm assuming your document type is Items here as it was in your question yesterday.
Note that the textual name you use here has to match the name in the database, which isn't necessarily the same as your document's property name. If you want to make it more robust, then you'll want to use expression trees to produce an expression for the property in question.
An alternative solution would be to build the Expression<Func<T, TElement>> that SortByDescending requires:
private static Expression<Func<TDocument, object>> GetPropertyExpression<TDocument>(string propertyName)
{
var parameter = Expression.Parameter(typeof(TDocument));
var property = Expression.Property(parameter, propertyName);
var castResult = Expression.Convert(property, typeof(object));
return Expression.Lambda<Func<TDocument, object>>(castResult, parameter);
}
query = query.SortByDescending(GetPropertyExpression<Items>(sortBy));
As far as Mongo is concerned, this is no different to having written query = query.SortByDescending(i => i.Name);
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.
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.
I am not very familiar with lambda expressions. So I have the following expression:
EnabledPropertySelector = l => l.FranchiseInfo.ExternalSystemType == ExternalSystemTypes.Master
And two properties:
public string VisibilityPropertyName { get; set; }
public object VisibilityPropertyValue { get; set; }
I want to extract some data from the expression so in the end I can get the values of the two properties:
VisibilityPropertyName == 'FranchiseInfo.ExternalSystemType';
VisibilityPropertyValue == ExternalSystemTypes.Master;
VisibilityPropertyName is always a string. This is the name of the property.
VisibilityPropertyValue can be of any type.
EDIT:
I have a lot of properties. Some of them are dependent on other properties. For every single property I have to manually write the name and the value of the parent property:
{ VisibilityPropertyName = 'FranchiseInfo.ExternalSystemType', VisibilityPropertyValue = ExternalSystemTypes.Master, EnabledPropertySelector = l => l.FranchiseInfo.ExternalSystemType == ExternalSystemTypes.Master}
Instead of writing all this I want to write only the expression and populate the properties from it.
This is the declaration of the expresion:
Expression<Func<TEntity, bool?>> EnabledPropertySelector
First off all, you need an Expression. What's the type of EnabledPropertySelector? It'll need to be something like Expression<Func<T, bool>> where T is whatever the type of "l" in your example is.
If you already have an Expression then you can use the Expression API to extract whatever you need:-
var body = EnabledPropertySelector.Body as BinaryExpression;
var left = body.Left as PropertyExpression;
var outerMemberName = left.Member.Name;
var innerMemberName = (left.Expression as PropertyExpression).Member.Name
VisibilityPropertyName = innerMemberName + "." + outerMemberName;
var right = body.Right as PropertyExpression;
var rightValueDelegate = Expression.Lambda<Func<object>>(right).Compile();
VisibilityPropertyValue = rightValueDelegate();
etc.
I really recommend doing some reading to properly grok the expression API before diving in though; there are a lot of corner cases depending on how flexible you need to be. E.g. is the expression always of the form parameter.Property.Property == constant? It gets really complicated really quickly, so you'll want a solid understanding of the fundamentals before trying to handle any real-world cases.
There's a reasonable introduction to expression trees on MSDN, but some focused googling might get you a better understanding quicker.
You can use Funciton and Action class, I'm not very sure of what you want be able to do, but I can give an tip.
Functions returns a value:
Function<InputType1,InputType2,ResultType> functionVariableName;
Usage:
functionVariableName = (param1, param2) => {
//...process both params
return result;
};
Actions, do not return values:
Action<InputType1,InputType2> actionVariableName;
Usage:
actionVariableName= (param1, param2) => {
//...process both params
};
If the lambda expression is simple (one line, with out if expression) you can make the lambda with out {}:
functionVariableName = (param1, param2) => //process values and result;
Hope this helps...
if you want to create an IEnumerable where the two properties are equal:
var results = EnabledPropertySelector.Where(l => l.FranchiseInfo.ExternalSystemType ==
ExternalSystemTypes.Master.ToString());
I have the following extension method:
public static string ToPropertyName<T,E>(this Expression<Func<E, T>> propertyExpression)
{
if (propertyExpression == null)
return null;
string propName;
MemberExpression propRef = (propertyExpression.Body as MemberExpression);
UnaryExpression propVal = null;
// -- handle ref types
if (propRef != null)
propName = propRef.Member.Name;
else
{
// -- handle value types
propVal = propertyExpression.Body as UnaryExpression;
if (propVal == null)
throw new ArgumentException("The property parameter does not point to a property", "property");
propName = ((MemberExpression)propVal.Operand).Member.Name;
}
return propName;
}
I use linq expression when passing property names instead of strings to provide strong typing and I use this function to retrieving the name of the property as a string. Does this method use reflection?
My reason for asking is this method is used quite a lot in our code and I want it to be reasonably fast enough.
As far as I know, reflection is not involved in the sense that some kind of dynamic type introspection happens behind the scenes. However, types from the System.Reflection such as Type or PropertyInfo are used together with types from the System.Linq.Expressions namespace. They are used by the compiler only to describe any Func<T,E> passed to your method as an abstract syntax tree (AST). Since this transformation from a Func<T,E> to an expression tree is done by the compiler, and not at run-time, only the lambda's static aspects are described.
Remember though that building this expression tree (complex object graph) from a lambda at run-time might take somewhat longer than simply passing a property name string (single object), simply because more objects need to be instantiated (the number depends on the complexity of the lambda passed to your method), but again, no dynamic type inspection à la someObject.GetType() is involved.
Example:
This MSDN article shows that the following lambda expression:
Expression<Func<int, bool>> lambda1 = num => num < 5;
is transformed to something like this by the compiler:
ParameterExpression numParam = Expression.Parameter(typeof(int), "num");
ConstantExpression five = Expression.Constant(5, typeof(int));
BinaryExpression numLessThanFive = Expression.LessThan(numParam, five);
Expression<Func<int, bool>> lambda1 =
Expression.Lambda<Func<int, bool>>(
numLessThanFive,
new ParameterExpression[] { numParam });
Beyond this, nothing else happens. So this is the object graph that might then be passed into your method.
Since you're method naming is ToPropertyName, I suppose you're trying to get the typed name of some particular property of a class. Did you benchmark the Expression<Func<E, T>> approach? The cost of creating the expression is quite larger and since your method is static, I see you're not caching the member expression as well. In other words even if the expression approach doesn't use reflection the cost can be high. See this question: How do you get a C# property name as a string with reflection? where you have another approach:
public static string GetName<T>(this T item) where T : class
{
if (item == null)
return string.Empty;
return typeof(T).GetProperties()[0].Name;
}
You can use it to get name of property or a variable, like this:
new { property }.GetName();
To speed up further, you would need to cache the member info. If what you have is absolutely Func<E, T> then your approach suits. Also see this: lambda expression based reflection vs normal reflection
A related question: Get all the property names and corresponding values into a dictionary