如何使用转换构造LambdaExpression

时间:2012-11-19 16:43:53

标签: c# linq sorting dynamic lambda

我需要按列名排序ajax响应网格。列值是作为字符串存储的数字。

让我们说一些琐碎的课程(在现实生活中,没有可能修改这个课程):

class TestObject
{
    public TestObject(string v)
    {
        this.Value = v;
    }
    public string Value { get; set; }
}
然后进行简单测试:

[Test]
public void LambdaConstructionTest()
{
   var queryable = new List<TestObject>
                   {
                       new TestObject("5"),
                       new TestObject("55"),
                       new TestObject("90"),
                       new TestObject("9"),
                       new TestObject("09"),
                       new TestObject("900"),
                   }.AsQueryable();

    var sortingColumn = "Value";

    ParameterExpression parameter = Expression.Parameter(queryable.ElementType);

    MemberExpression property = Expression.Property(parameter, sortingColumn);
    //// tried this one: var c = Expression.Convert(property, typeof(double));

        LambdaExpression lambda = Expression.Lambda(property, parameter); //// constructs: o=>o.Value

        var callExpression = Expression.Call(typeof (Double), "Parse", null, property); 

        var methodCallExpression = Expression.Call(
            typeof(Queryable),
            "OrderBy",
            new[] { queryable.ElementType, property.Type },
            queryable.Expression,
            Expression.Quote(lambda)); // works, but sorts by string values.
            //Expression.Quote(callExpression)); // getting: System.ArgumentException {"Quoted expression must be a lambda"}

        var querable =  queryable.Provider.CreateQuery<TestObject>(methodCallExpression);

        // return querable; // <- this is the return of what I need. 
}

很抱歉在我的第一篇文章中没有明白@SLaks答案是正确的但我不知道在这种情况下如何构造正确的lambda表达式。

终于找到了解决方案,这对任何在列中都有字符串且需要按转换后的双值排序的人都有好处:(特别感谢@SLaks他的帖子令人大开眼界):

    [Test]
    public void LambdaConstructionTest2()
    {
        // GIVEN
        var queryable = new List<TestObject>
                            {
                                new TestObject("5"),
                                new TestObject("55"),
                                new TestObject("90"),
                                new TestObject("9"),
                                new TestObject("09"),
                                new TestObject("900"),
                            }.AsQueryable();

        var sortingColumn = "Value";

        // WHEN
        ParameterExpression parameter = Expression.Parameter(queryable.ElementType);

        MemberExpression property = Expression.Property(parameter, sortingColumn);

        MethodCallExpression callExpression = Expression.Call(typeof (Double), "Parse", null, property);

        LambdaExpression lambda = Expression.Lambda(callExpression, parameter); // = {Param_0 => Parse(Param_0.Value)}

        UnaryExpression unaryExpression = Expression.Quote(lambda); // Expression<Func<TestObject,double>> = {Param_0 => Parse(Param_0.Value)}

        var methodCallExpression = Expression.Call(
            typeof (Queryable),
            "OrderByDescending",
            new[] { queryable.ElementType, lambda.ReturnType },
            queryable.Expression,
            unaryExpression);

        var querable = queryable.Provider.CreateQuery<TestObject>(methodCallExpression);

        // THEN
        var expectedMaxValue = queryable.Max(x => Convert.ToDouble(x.Value));
        var expectedMinValue = queryable.Min(x => Convert.ToDouble(x.Value));

        var list = querable.ToList();

        var actualMaxValue = Convert.ToDouble(list.First().Value);
        var actualMinValue = Convert.ToDouble(list.Last().Value);
        Assert.AreEqual(expectedMaxValue, actualMaxValue);
        Assert.AreEqual(expectedMinValue, actualMinValue);
    }

1 个答案:

答案 0 :(得分:2)

您可以调用Expression.Call()来创建一个调用方法的表达式节点。

Expression.Call(typeof(Double), "Parse", null, property)