问题
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?
回答1:
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.
来源:https://stackoverflow.com/questions/2719762/lambda-expression-to-be-used-in-select-query