Expresión Lambda para ser utilizada en la consulta Select ()

c# expression-trees lambda

Pregunta

Estoy tratando de construir una expresión lambda, que contiene dos asignaciones (como se muestra más abajo), que luego puedo pasar a un método Queryable.Select ().

Estoy tratando de pasar una variable de cadena a un método y luego usar esa variable para construir la expresión lambda para que pueda usarla en una consulta de LINQ Select.

Mi razonamiento detrás de esto es que tengo un origen de datos de SQL Server con muchos nombres de columnas, estoy creando una aplicación de gráficos que permitirá al usuario seleccionar, por ejemplo, escribiendo el nombre de la columna, la columna real de datos que desea ver en el El eje y de mi gráfico, con el eje x siempre siendo el DateTime. Por lo tanto, esencialmente pueden elegir qué datos se comparan con el valor de DateTime (es una aplicación de tipo de almacén de datos).

Tengo, por ejemplo, una clase para almacenar los datos recuperados y, por lo tanto, utilizarlos como la fuente del gráfico de:

public class AnalysisChartSource
{
    public DateTime Invoicedate { get; set; }
    public Decimal yValue { get; set; }
}

He construido (puramente experimental) un árbol de expresiones para la cláusula Where utilizando el valor de String y eso funciona bien:

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

Sin embargo ... he intentado un enfoque similar para la declaración Select, pero no puedo hacer que funcione ya que necesito que Select () rellene los valores X e Y de la clase AnalysisChartSource, como esto:

.Select(c => new AnalysisChartSource 
{ Invoicedate = c.Invoicedate, yValue = c.yValue}).AsEnumerable();

¿Cómo diablos puedo construir un árbol de expresión ... o ... posiblemente más al punto ... hay una forma más fácil de extrañar por completo?

Respuesta aceptada

Me parece que la mejor manera de averiguar cómo construir árboles de expresión es ver qué hace el compilador de C #. Así que aquí hay un programa completo:

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 eso, abra los resultados en Reflector y establezca la optimización en .NET 2.0. Usted termina con este código generado para el método principal:

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

Básicamente, creo que Expression.MemberInit es lo que estás buscando.



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow