How to get dynamic predicate using expressions when joining in Linq - c#

I wrote a static method which will give appropriate predicate lambda using expression api for different type of fields.
static Func<T, bool> Process<T>(string type)
{
ParameterExpression parameter = Expression.Parameter(typeof(T));
Expression predicate = Expression.Constant(true);
if (type == "Start")
{
Expression prop = Expression.Property(parameter, type);
Expression filter = Expression.LessThan(prop, Expression.Constant(DateTime.Now));
predicate = Expression.AndAlso(predicate, filter);
}
//TODO: more if statments to come
var lambda = Expression.Lambda<Func<T, bool>>(predicate, parameter);
return lambda.Compile();
}
The above code works fine if I do a single query operation in linq like this:
var del = Process<MyClass>("Start");
var data = DbContext.MyClass.Where(del); //gets the result data
public class MyClass
{
public DateTime Start { get; set; }
public DateTime End { get; set; }
public long Id { get; set; }
}
Now, if I do a join on the MyClass entity
var data = DbContext.MyClass
.Join(DbContext.Detail, mc => mc.Id, detail => detail.Id, (m, d) =>
new { m = m, d = d})
.Where(del);
The above lines are giving compile time error
Error CS1929 'IQueryable<<anonymous type: MyClass m, Detail d>>' does not contain a definition for 'Where' and the best extension method overload 'EnumerableRowCollectionExtensions.Where<MyClass>(EnumerableRowCollection<MyClass>, Func<MyClass, bool>)' requires a receiver of type 'EnumerableRowCollection<MyClass>'
I understand that .Where() now expects an anonymous type which has m and d but not sure how to resolve this.
I'm pretty new to Expression API. Not sure how to achieve.
I've tried to achieve that by creating anonymous type variable, but that is a variable and not the type itself to pass it to Process<T>().

The result of your Process method is a Where clause for objects of type MyClass, so you can't use it to filter anonymous objects { m, d }. Instead filter before the Join:
var data = DbContext.MyClass.Where(del);
.Join(DbContext.Detail,
mc => mc.Id,
detail => detail.Id,
(m, d) => new { m, d }
);

Related

Expression Tree: Get property value of dynamic object

I have list of dynamic objects where I want to query by custom property. In other words, it would look like this if I wasn't going for reflection:
IEnumerable<User> FilterUsers(IEnumerable<User> users, string selectedValue)
{
users.Where(user => user.Name == selectedValue);
}
So far I've come up with the following implementation that works if users is typed:
IEnumerable<User> FilterUsers(IEnumerable<User> users, string selectedField, string selectedValue)
{
LabelTarget returnTarget = Expression.Label(typeof(bool));
ParameterExpression userParameter = Expression.Parameter(typeof(User));
MemberExpression userSelectedField = Expression.Property(userParameter, selectedField);
Expression test = Expression.Equal(userSelectedField, Expression.Constant(selectedValue));
Expression iftrue = Expression.Return(returnTarget, Expression.Constant(true));
Expression iffalse = Expression.Return(returnTarget, Expression.Constant(false));
var ex = Expression.Block(
Expression.IfThenElse(test, iftrue, iffalse),
Expression.Label(returnTarget, Expression.Constant(false)));
var whereClause = Expression.Lambda<Func<User, bool>>(
ex,
new ParameterExpression[] { userParameter }
).Compile();
return users.Where(user => whereClause(user));
}
What I am really trying to do is to make users dynamic object:
IEnumerable<dynamic> FilterUsers(IEnumerable<dynamic> users, string selectedField, string selectedValue) {
// ...
ParameterExpression userParameter = Expression.Parameter(typeof(object)); // ???
MemberExpression userSelectedField = Expression.Property(userParameter, selectedField); // throws
// ...
}
This throws the following exception: Instance property 'Name' is not defined for type 'System.Object' (Parameter 'propertyName'). What am I missing?
Alternatively, how can I use Dictionary<string, object>?
Using dynamic here doesn't get you much: you'd be better off using generics if you can:
IEnumerable<T> FilterUsers<T>(IEnumerable<T> users, string selectedField, string selectedValue)
{
var userParameter = Expression.Parameter(typeof(T));
var userSelectedField = Expression.Property(userParameter, selectedField);
// etc...
}
If you do need to use dynamic, then you'll need to get the runtime type of each user, using .GetType(). However bear in mind that there's nothing stopping someone from passing in an IEnumerable containing lots of different types of object, and they don't all have to have a property called selectedField!
Or, they might pass in lots of different types of object, each of one has a property called selectedField, but they're distinct properties (e.g. class A { public string Foo { get; set; } } and class B { public string Foo { get; set; } } -- those two Foo properties are distinct).
So you'll have to call .GetType() on each one of them, which means you won't be able to get the performance benefits of using compiled expressions.
If you can guarantee that all elements have the same type, you can do something like:
private static IEnumerable<dynamic> FilterCollection(IEnumerable<dynamic> collection, string property, string value)
{
if (!collection.Any()) return collection;
var collectionItemType = collection.First().GetType();
var userParameter = Expression.Parameter(typeof(object));
var convertedUser = Expression.Convert(userParameter, collectionItemType);
var userSelectedField = Expression.Property(convertedUser, selectedField);
...
}
Beware however that you're enumerating users twice, which is probably a bad thing. You might do better to get the IEnumerator yourself and work with it explicitly.
As #canton7 said you should be using a generic method. I also see in your question you specified you're looking for properties, why not use regular old reflection?
public static IEnumerable<T> FilterItems<T>(IEnumerable<T> items, string property, string value)
{
var prop = typeof(T).GetProperties().First(p => p.Name == property);
return items.Where(i => prop.GetValue(i).ToString().Contains(value));
}
Of course that code should be enhanced to handle different errors....

MemberExpression as object of its type

I'm building Linq Extension methods.
Shortly, I've built an extension method in order to create a MemberExpression looks like:
public static Expression Field<T>(this object entity, string field)
{
Type entityType = entity.GetType();
PropertyInfo propertyInfo = entityType.GetProperty(field);
if (propertyInfo == null)
throw new ArgumentException(string.Format("{0} doesn't exist on {1}", field, entityType.Name));
ParameterExpression parameterExpression = Expression.Parameter(entityType, "e");
return Expression.Property(parameterExpression, propertyInfo);
}
So, I'm able to do that:
IEnumerable<C> classes = this.backend.cs.Where(
c => c.Field<C>("Matter").EndsWith(string.Empty)<<<<<<<< Compilation error.
);
Since MemberExpression have not EndsWith method, I'm not able to extend this MemberExpression like a String property access like:
IEnumerable<C> classes = this.backend.cs.Where(
c => c.Matter.EndsWith(string.Empty)
);
Is there some way to do that.
As you are able to figure out I'm trying to get something a bit more complex, Nevertheless, this example is for explaining the situation.
I hope it's enought clear.
Scope
My UI is using a backend.
This backend have three implementations. Each one of them provides a Linq implementation (Linq collections, NHibernate, custom-made Linq provider).
So, my UI is able to work on collections, a database or getting data from our server.
I'd like to provide util extension methods like AnyField().
So, after digging a bit I'm thinking on two approaches:
AnyField() generates an expression tree which is able to be translated by every Linq provider (first answer of this post).
Provide a default implementation of Anyfield() for Linq Collections, and then use each Linq provider extension mechanism for handle it. Or, if you are building a Linq Provider, support it on implementation.
Okay, so you're getting tripped up on the syntactic sugar that C# provides for you when building ExpressionTrees
Where expects Expression<Func<TObjectType, TReturnType>> or a compiled lambda; Func<TObjectType, TReturnType>.
Your method Field currently only returns an untyped Expression. That means your query is actually returning Expression<Func<TObjectType, Expression>>. That's not right! It should be returning a Expression<Func<TObjectType, string>>! But how do we do that? That would mean our method would have to return a string, but we want to build an expression tree.
To get it working as you're expecting, it's quite a bit more difficult than you would imagine, but that's only because we're so spoiled with the syntactic sugar.
What we actually need to do is write methods which accept lambda methods, and return lambda methods, each one re-writing the body a little bit.
So... what does that look like?
public static Expression<Func<TElementType, object>> Field<TElementType, TReturnType>(this Expression<Func<TElementType, TReturnType>> expr, string field)
{
Type entityType = expr.Body.Type;
PropertyInfo propertyInfo = entityType.GetProperty(field);
if (propertyInfo == null)
throw new ArgumentException(string.Format("{0} doesn't exist on {1}", field, entityType.Name));
ParameterExpression parameterExpression = Expression.Parameter(entityType, "e");
return Expression.Lambda<Func<TElementType, object>>(
Expression.Property(parameterExpression, propertyInfo),
parameterExpression
);
}
Notice that it's almost the exact same as what you wrote, but we wrap it with Lambda<Func<TElementType, TReturnType>>. And the signature is a bit different too.
Instead of operating on an object, we want to operate on a lambda expression. We also return a lambda expression.
So how do we use it?
var classes = objects.Where(
ExpressionExtensions.Field<Test, Test>(q => q, "Matter")
);
Great! Now we're passing Expression<Func<Test, string>> to Where, rather than Expression<Func<Test, MemberExpression>>. Making progress.
But that won't compile, and rightly so. We're returning a string, but we're using a filtering method, which requires a bool.
So let's now write EndsWith:
public static Expression<Func<T, bool>> EndsWith<T, TReturnType>(this Expression<Func<T, TReturnType>> expr, string str)
{
var endsWithMethod = typeof(string).GetMethod("EndsWith", new[] { typeof(string) });
var newBody = Expression.Call(expr.Body, endsWithMethod, Expression.Constant(str));
var result = Expression.Lambda<Func<T, bool>>(newBody, expr.Parameters);
return result;
}
And using it:
var classes = objects.Where(
ExpressionExtensions.Field<Test, Test>(q => q, "Matter")
.EndsWith("A")
);
Which is now compiling! And the expression tree looks like this:
UserQuery+Test[].Where(e => e.Matter.EndsWith("A"))
That's not too pretty, having Field take a redundant lambda, though. Let's add a helper method to make it look prettier:
public static Expression<Func<TElementType, TElementType>> Query<TElementType>(this Expression<Func<TElementType, TElementType>> expr)
{
return expr;
}
Putting it all together:
void Main()
{
var objects = new[] { new Test { Matter = "A" } }.AsQueryable();
var classes = objects.Where(
ExpressionExtensions.Query<Test>(q => q)
.Field("Matter")
.EndsWith("A")
);
classes.Expression.Dump();
}
public class Test
{
public string Matter { get; set;}
}
public static class ExpressionExtensions
{
public static Expression<Func<TElementType, TElementType>> Query<TElementType>(this Expression<Func<TElementType, TElementType>> expr)
{
return expr;
}
public static Expression<Func<TElementType, object>> Field<TElementType, TReturnType>(this Expression<Func<TElementType, TReturnType>> expr, string field)
{
Type entityType = expr.Body.Type;
PropertyInfo propertyInfo = entityType.GetProperty(field);
if (propertyInfo == null)
throw new ArgumentException(string.Format("{0} doesn't exist on {1}", field, entityType.Name));
ParameterExpression parameterExpression = Expression.Parameter(entityType, "e");
return Expression.Lambda<Func<TElementType, object>>(
Expression.Property(parameterExpression, propertyInfo),
parameterExpression
);
}
public static Expression<Func<T, bool>> EndsWith<T, TReturnType>(this Expression<Func<T, TReturnType>> expr, string str)
{
var endsWithMethod = typeof(string).GetMethod("EndsWith", new[] { typeof(string) });
var newBody = Expression.Call(expr.Body, endsWithMethod, Expression.Constant(str));
var result = Expression.Lambda<Func<T, bool>>(newBody, expr.Parameters);
return result;
}
}
I don't know if you mess the code to show a piece of code or if it was intended, but you have a generic extension that wants A T but you don't use it
Anyway if what you want is a method that returns you the value of a property, why don't you do a static exception that return T ?
public static class EntityExtension {
public static T Field<T>(this object entity, string field) {
Type entityType = entity.GetType();
PropertyInfo propertyInfo = entityType.GetProperty(field);
if (propertyInfo == null) {
throw new ArgumentException(string.Format("{0} doesn't exist on {1}", field, entityType.Name));
}
return (T)propertyInfo.GetValue(entity);
}
}
this is a fiddle i've done to show you the usage, pretty simple
https://dotnetfiddle.net/PoSfli
posting the code too in case fiddle get lost:
using System;
using System.Reflection;
using System.Linq.Expressions;
public class Program
{
public static void Main()
{
YourClass c = new YourClass() {
PropA = 1,
PropB = 2,
PropC = "ciao"
};
var propBValue = c.Field<int>("PropB");
Console.WriteLine("PropB value: {0}", propBValue);
var propCValue = c.Field<string>("PropC");
Console.WriteLine("PropC value: {0}", propCValue);
}
}
public static class EntityExtension {
public static T Field<T>(this object entity, string field) {
Type entityType = entity.GetType();
PropertyInfo propertyInfo = entityType.GetProperty(field);
if (propertyInfo == null) {
throw new ArgumentException(string.Format("{0} doesn't exist on {1}", field, entityType.Name));
}
return (T)propertyInfo.GetValue(entity);
}
}
public class YourClass {
public int PropA { get; set; }
public int PropB { get; set; }
public string PropC { get; set; }
}
nota that you can improve a lot, using a typed extension and a property expression as argument instead of a string
You can also do something really simple like if you want to use the property name:
IEnumerable<C> classes = this.backend.cs.Where(
c => c.Field<C>("Matter").ToString().EndsWith(string.Empty)
Or if your are filtering by property type:
IEnumerable<C> classes = this.backend.cs.Where(
c => c.Field<C>("Matter").Type.ToString().EndsWith(string.Empty)
How about something like this? Actually, your generic approach is not of use right now.
public static bool Evaluate<TField>(this object entity, string fieldName, Predicate<TField> condition)
{
Type entityType = entity.GetType();
PropertyInfo propertyInfo = entityType.GetProperty(field);
if (propertyInfo == null)
throw new ArgumentException(string.Format("{0} doesn't exist on {1}", field, entityType.Name));
var value = (TField)propertyInfo.GetValue(entity); //read the value and cast it to designated type, will raise invalid cast exception, if wrong
return condition.Invoke(value); //invoke the predicate to check the condition
}
Usage would be then.
.Where(item => item.Evaluate<string>("Matter", prop => prop.EndsWith(string.Empty))
You can add a new extension method which returns your desired type.
public static T Compile<T>(this Expression expression)
{
return Expression.Lambda<Func<T>>(expression).Compile()();
}
In your statement you just have to add .Compile<type>()
IEnumerable<C> classes = this.backend.cs.Where(
c => c.Field<C>("Matter").Compile<string>().EndsWith(string.Empty));

Combining AndAlso The parameter 'foo' was not bound in the specified LINQ to Entities query expression

I have an entity.
public class Foo
{
public int Id { get; set; }
public string Name { get; set; }
public string Code { get; set; }
}
I want to create my own expression predicate. For that I have created a method that accepts property name and the value.
private static Expression<Func<Foo, bool>> Condition(string pName, object value)
{
var pe = Expression.Parameter(typeof(Foo), "foo");
var left = Expression.Property(pe, pName);
var right = Expression.Constant(value);
var equal = Expression.Equal(left, right);
var predicate = Expression.Lambda<Func<Foo, bool>>(equal, pe);
return predicate;
}
This is the predicate which works fine for a single condition.
using (var db = new MyEntities())
{
var predicate = Condition("Name", "foo");
var foos = db.Foos.Where(predicate).ToArray();
}
But when I tried to combine two conditions by following this post, it throws exception.
The parameter 'foo' was not bound in the specified LINQ to Entities
query expression.
using (var db = new MyEntities())
{
var cond1 = Condition("Name", "foo");
var cond2 = Condition("Code", "bar");
var body = Expression.AndAlso(cond1.Body, cond2.Body);
var predicate = Expression.Lambda<Func<Foo,bool>>(body, cond1.Parameters[0]);
var foos = db.Foos.Where(predicate).ToArray(); // exception
}
Please enlighten me.
The problem is that ParameterExpression in LINQ expressions is identified by reference equality, but the two Parameter objects are different references. (The name in ParameterExpression only exists for debugging purposes).
(If you reread the mentioned post, it says that the method that you tried would only work if both lambdas are defined on the same ParameterExpression object).
You have two big possibilities at this stage: either you define a way for the Condition function to accept a ParameterExpression object, or you create an ExpressionVisitor that will replace the original ParameterExpression with another. (Of course, given that you want to do an AndAlso, you could also conceivably chain two Where clauses, but that is less general.)

Trying to use parent property as parameter in child collection expression; LinqKit throws "Unable to cast MethodCallExpressionN to LambdaExpression"

I'm trying to dynamically construct an expression similar to the one below, where I can use the same comparison function, but where the values being compared can be passed in, since the value is passed from a property 'higher-up' in the query.
var people = People
.Where(p => p.Cars
.Any(c => c.Colour == p.FavouriteColour));
I believe I've constructed the query correctly, but the ExpressionExpander.VisitMethodCall(..) method throws the following exception when I try to use it:
"Unable to cast object of type 'System.Linq.Expressions.InstanceMethodCallExpressionN' to type 'System.Linq.Expressions.LambdaExpression'"
In real-world code, using Entity Framework and actual IQueryable<T>, I often get:
"Unable to cast object of type 'System.Linq.Expressions.MethodCallExpressionN' to type 'System.Linq.Expressions.LambdaExpression'" as well.
I've constructed a LinqPad-friendly example of my problem, as simple as I could make it.
void Main()
{
var tuples = new List<Tuple<String, int>>() {
new Tuple<String, int>("Hello", 4),
new Tuple<String, int>("World", 2),
new Tuple<String, int>("Cheese", 20)
};
var queryableTuples = tuples.AsQueryable();
// For this example, I want to check which of these strings are longer than their accompanying number.
// The expression I want to build needs to use one of the values of the item (the int) in order to construct the expression.
// Basically just want to construct this:
// .Where (x => x.Item1.Length > x.Item2)
var expressionToCheckTuple = BuildExpressionToCheckTuple();
var result = queryableTuples
.AsExpandable()
.Where (t => expressionToCheckTuple.Invoke(t))
.ToList();
}
public Expression<Func<string, bool>> BuildExpressionToCheckStringLength(int minLength) {
return str => str.Length > minLength;
}
public Expression<Func<Tuple<string, int>, bool>> BuildExpressionToCheckTuple() {
// I'm passed something (eg. Tuple) that contains:
// * a value that I need to construct the expression (eg. the 'min length')
// * the value that I will need to invoke the expression (eg. the string)
return tuple => BuildExpressionToCheckStringLength(tuple.Item2 /* the length */).Invoke(tuple.Item1 /* string */);
}
If I'm doing something obviously wrong, I'd really appreciate a nudge in the right direction! Thanks.
Edit: I know that the following would work:
Expression<Func<Tuple<string, int>, bool>> expr = x => x.Item1.Length > x.Item2;
var result = queryableTuples
.AsExpandable()
.Where (t => expr.Invoke(t))
.ToList();
However, I'm trying to separate the comparison from the location of the parameters, since the comparison could be complex and I would like to re-use it for many different queries (each with different locations for the two parameters). It is also intended that one of the parameters (in the example, the 'min length') would actually be calculated via another expression.
Edit: Sorry, I've just realised that some answers will work when attempted against my example code since my example is merely masquerading as an IQueryable<T> but is still a List<T> underneath. The reason I'm using LinqKit in the first place is because an actual IQueryable<T> from an EntityFramework DbContext will invoke Linq-to-SQL and so must be able to be parsed by Linq-to-SQL itself. LinqKit enables this by expanding everything to expressions.
Solution! Thanks to Jean's answer below, I think I've realised where I'm going wrong.
If a value has come from somewhere in the query (i.e. not a value that is known before-hand.) then you must build the reference/expression/variable to it into the expression.
In my original example, I was trying to pass the 'minLength' value taken from within the expression and pass it to a method. That method call could not be done before-hand, since it used a value from the expression, and it could not be done within the expression, since you can't build an expression within an expression.
So, how to get around this? I chose to write my expressions so that they can be invoked with the additional parameters. Though this has the downside that the parameters are no longer 'named' and I could end up with an Expression<Func<int, int, int, int, bool>> or something down the line.
// New signature.
public Expression<Func<string, int, bool>> BuildExpressionToCheckStringLength() {
// Now takes two parameters.
return (str, minLength) => str.Length > minLength;
}
public Expression<Func<Tuple<string, int>, bool>> BuildExpressionToCheckTuple() {
// Construct the expression before-hand.
var expression = BuildExpressionToCheckStringLength();
// Invoke the expression using both values.
return tuple => expression.Invoke(tuple.Item1 /* string */, tuple.Item2 /* the length */);
}
OK, so what you are trying to do (the transformation from a function that takes a single argument, that returns another function that takes a single argument f(x)(y) into a function that takes two arguments f(x, y)) is known as uncurrying. Look it up! :)
Now, the issue that you have in your code is that, in the expression returned by BuildExpressionToCheckTuple, there is a method call to BuildExpressionToCheckStringLength, which is not resolved. And you cannot resolve it because it takes an argument that is embedded in the tuple parameter.
The solution is, instead of using a method call, to use a lambda expression that will be equivalent to that method call.
That is:
public Expression<Func<int, Func<string, bool>>> ExpressionToCheckStringLengthBuilder() {
return minLength =>
str => str.Length > minLength;
}
public Expression<Func<Tuple<string, int>, bool>> BuildExpressionToCheckTuple() {
// I'm passed something (eg. Tuple) that contains:
// * a value that I need to construct the expression (eg. the 'min length')
// * the value that I will need to invoke the expression (eg. the string)
// Putting builder into a variable so that the resulting expression will be
// visible to tools that analyze the expression.
var builder = ExpressionToCheckStringLengthBuilder();
return tuple => builder.Invoke(tuple.Item2 /* the length */).Invoke(tuple.Item1 /* string */);
}
So you are looking for something like this:
public static class Program
{
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public static IQueryable<T> WherePropertyEquals<T, TProperty>(
this IQueryable<T> src, Expression<Func<T, TProperty>> property, TProperty value)
{
var result = src.Where(e => property.Invoke(e).Equals(value));
return result;
}
public static IQueryable<T> WhereGreater<T, TProperty>(
this IQueryable<T> src, Expression<Func<T, TProperty>> property, TProperty value)
where TProperty : IComparable<TProperty>
{
var result = src.Where(e => property.Invoke(e).CompareTo(value) > 0);
return result;
}
public static IQueryable<T> WhereGreater<T, TProperty>(
this IQueryable<T> src, Expression<Func<T, TProperty>> left, Expression<Func<T, TProperty>> right)
where TProperty : IComparable<TProperty>
{
var result = src.Where(e => left.Invoke(e).CompareTo(right.Invoke(e)) > 0);
return result;
}
public static void Main()
{
var persons = new List<Person>()
{
new Person
{
FirstName = "Jhon",
LastName = "Smith"
},
new Person
{
FirstName = "Chuck",
LastName = "Norris"
},
new Person
{
FirstName = "Ben",
LastName = "Jenkinson"
},
new Person
{
FirstName = "Barack",
LastName = "Obama"
}
}
.AsQueryable()
.AsExpandable();
var chuck = persons.WherePropertyEquals(p => p.FirstName, "Chuck").First();
var ben = persons.WhereGreater(p => p.LastName.Length, 6).First();
var barack = persons.WhereGreater(p => p.FirstName.Length, p => p.LastName.Length).First();
}

Lambda Expression to be used in Select() query

I am trying to build a lambda expression, containing two assignments (as shown further down), that I can then pass to a Queryable.Select() method.
I am trying to pass a string variable into a method and then use that variable to build up the lambda expression so that I can use it in a LINQ Select query.
My reasoning behind it is that I have a SQL Server datasource with many column names, I am creating a charting application that will allow the user to select, say by typing in the column name, the actual column of data they want to view in the y-axis of my chart, with the x-axis always being the DateTime. Therefore, they can essentially choose what data they chart against the DateTime value (it’s a data warehouse type app).
I have, for example, a class to store the retrieved data in, and hence use as the chart source of:
public class AnalysisChartSource
{
public DateTime Invoicedate { get; set; }
public Decimal yValue { get; set; }
}
I have (purely experimentaly) built an expression tree for the Where clause using the String value and that works fine:
public void GetData(String yAxis)
{
using (DataClasses1DataContext db = new DataClasses1DataContext())
{
var data = this.FunctionOne().AsQueryable<AnalysisChartSource>();
//just to get some temp data in....
ParameterExpression pe = Expression.Parameter(typeof(AnalysisChartSource), "p");
Expression left = Expression.MakeMemberAccess(pe,
typeof(AnalysisChartSource).GetProperty(yAxis));
Expression right = Expression.Constant((Decimal)16);
Expression e2 = Expression.LessThan(left, right);
Expression expNew = Expression.New(typeof(AnalysisChartSource));
LambdaExpression le = Expression.Lambda(left, pe);
MethodCallExpression whereCall = Expression.Call(
typeof(Queryable), "Where", new Type[] { data.ElementType },
data.Expression,
Expression.Lambda<Func<AnalysisChartSource, bool>>(e2, new ParameterExpression[] { pe }));
}
}
However……I have tried a similar approach for the Select statement, but just can’t get it to work as I need the Select() to populate both X and Y values of the AnalysisChartSource class, like this:
.Select(c => new AnalysisChartSource
{ Invoicedate = c.Invoicedate, yValue = c.yValue}).AsEnumerable();
How on earth can I build such an expression tree….or….possibly more to the point…..is there an easier way that I have missed entirely?
I find that the best way to work out how to build expression trees is to see what the C# compiler does. So here's a complete program:
using System;
using System.Linq.Expressions;
public class Foo
{
public int X { get; set; }
public int Y { get; set; }
}
class Test
{
static void Main()
{
Expression<Func<int, Foo>> builder =
z => new Foo { X = z, Y = z };
}
}
Compile that, open the results in Reflector and set the optimisation to .NET 2.0. You end up with this generated code for the Main method:
ParameterExpression expression2;
Expression<Func<int, Foo>> expression =
Expression.Lambda<Func<int, Foo>>(
Expression.MemberInit(
Expression.New((ConstructorInfo) methodof(Foo..ctor), new Expression[0]),
new MemberBinding[] { Expression.Bind((MethodInfo) methodof(Foo.set_X),
expression2 = Expression.Parameter(typeof(int), "z")),
Expression.Bind((MethodInfo) methodof(Foo.set_Y),
expression2) }
),
new ParameterExpression[] { expression2 });
Basically, I think Expression.MemberInit is what you're after.

Categories

Resources