我需要按列名在 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);
}