在 "complex types" 中使用 LambdaExpression 对列表进行排序
Sort lists by using LambdaExpression in "complex types"
各位。在过去的几个小时里,我尝试使用 Google 找到答案,并使用即时 Window 进行绝望的测试,但我认为我没有提出正确的问题。
我的应用程序中有一个 OrderByExtender,我用它来进行排序,只使用 属性 名称和一个布尔值来判断它是 ASC 还是 DESC 排序。
public static IOrderedEnumerable<T> OrderBy<T>(this IEnumerable<T> collection, string key, bool isAscending)
{
LambdaExpression sortLambda = BuildLambda<T>(key);
if (isAscending)
return collection.OrderBy((Func<T, object>)sortLambda.Compile());
else
return collection.OrderByDescending((Func<T, object>)sortLambda.Compile());
}
private static LambdaExpression BuildLambda<T>(string key)
{
ParameterExpression TParameterExpression = Expression.Parameter(typeof(T), "p");
LambdaExpression sortLambda = Expression.Lambda(Expression.Convert(Expression.Property(TParameterExpression, key), typeof(object)), TParameterExpression);
return sortLambda;
}
当我使用通用类型属性(字符串、整数等)时,它就像一个魅力。但现在我想到了以下场景:我有一个名为 BusinessOrder 的对象,在它里面有一个类型为 Quarter[=27] 的 属性 =].这个 Quarter 对象具有三个属性:Year(int)、Quarter(int) 和 Abbreviation(string)。我必须使用缩写 属性 执行 OrderBy。换句话说,我必须这样做:
BusinessOrderList.OrderBy(b => b.Quarter.Abbreviation);
但我想将这种排序可能性放入我的 Extender 中,通过作为 key 参数传递 "Quarter.Abbreviation" 之类的东西并且 Extender 方法理解这是一个问题在 "complex object".
中获取 属性
我相信我可以在创建 sortLambda 变量的 "Expression.Lambda" 方法中做一些事情,但我不知道如何使用表达式复制此行为.有人能帮我吗?提前致谢。
您无法一次访问复杂的 属性。您必须递归地构建表达式链:
private Func<TInput, object> BuildLambda<TInput>(string complexPropertyPath)
{
var parameter = Expression.Parameter(typeof(TInput), "p");
var propertyPathParts = complexPropertyPath.Split('.');
MemberExpression complexPropertyAccessExpression = null;
foreach (var propertyPathPart in propertyPathParts)
{
complexPropertyAccessExpression = complexPropertyAccessExpression == null
? Expression.Property(parameter, propertyPathPart)
: Expression.Property(complexPropertyAccessExpression, propertyPathPart);
}
var lambda = (Func<TInput, object>)Expression.Lambda(complexPropertyAccessExpression, parameter).Compile();
return lambda;
}
如果可能,我建议将 string key
参数替换为 Expression<Func<T, object>> key
参数。这样,您的函数调用就可以像您描述的那样 BusinessOrderList.OrderBy(b => b.Quarter.Abbreviation);
。由于所有 OrderBy/OrderByDescending 方法都接受此表达式作为字符串的替代方法,所以我看不出将 key
保留为字符串有什么好处。
您可以传递 Func
来对您的 collection
进行排序
public static IOrderedEnumerable<T> OrderBy<T>(this IEnumerable<T> collection,
Func<IEnumerable<T>,IOrderedEnumerable<T>> OrderBy)
{
if(OrderBy != null)
return OrderBy(collection);
return collection;
}
你必须这样称呼它
{
Func<IEnumerable<Book>,IOrderedEnumerable<Book>> sort =
list => list.OrderBy(B=>B.Author.Name).ThenByDescending(B=>B.Title) ;
List.OrderBy(sort);
}
各位。在过去的几个小时里,我尝试使用 Google 找到答案,并使用即时 Window 进行绝望的测试,但我认为我没有提出正确的问题。
我的应用程序中有一个 OrderByExtender,我用它来进行排序,只使用 属性 名称和一个布尔值来判断它是 ASC 还是 DESC 排序。
public static IOrderedEnumerable<T> OrderBy<T>(this IEnumerable<T> collection, string key, bool isAscending)
{
LambdaExpression sortLambda = BuildLambda<T>(key);
if (isAscending)
return collection.OrderBy((Func<T, object>)sortLambda.Compile());
else
return collection.OrderByDescending((Func<T, object>)sortLambda.Compile());
}
private static LambdaExpression BuildLambda<T>(string key)
{
ParameterExpression TParameterExpression = Expression.Parameter(typeof(T), "p");
LambdaExpression sortLambda = Expression.Lambda(Expression.Convert(Expression.Property(TParameterExpression, key), typeof(object)), TParameterExpression);
return sortLambda;
}
当我使用通用类型属性(字符串、整数等)时,它就像一个魅力。但现在我想到了以下场景:我有一个名为 BusinessOrder 的对象,在它里面有一个类型为 Quarter[=27] 的 属性 =].这个 Quarter 对象具有三个属性:Year(int)、Quarter(int) 和 Abbreviation(string)。我必须使用缩写 属性 执行 OrderBy。换句话说,我必须这样做:
BusinessOrderList.OrderBy(b => b.Quarter.Abbreviation);
但我想将这种排序可能性放入我的 Extender 中,通过作为 key 参数传递 "Quarter.Abbreviation" 之类的东西并且 Extender 方法理解这是一个问题在 "complex object".
中获取 属性我相信我可以在创建 sortLambda 变量的 "Expression.Lambda" 方法中做一些事情,但我不知道如何使用表达式复制此行为.有人能帮我吗?提前致谢。
您无法一次访问复杂的 属性。您必须递归地构建表达式链:
private Func<TInput, object> BuildLambda<TInput>(string complexPropertyPath)
{
var parameter = Expression.Parameter(typeof(TInput), "p");
var propertyPathParts = complexPropertyPath.Split('.');
MemberExpression complexPropertyAccessExpression = null;
foreach (var propertyPathPart in propertyPathParts)
{
complexPropertyAccessExpression = complexPropertyAccessExpression == null
? Expression.Property(parameter, propertyPathPart)
: Expression.Property(complexPropertyAccessExpression, propertyPathPart);
}
var lambda = (Func<TInput, object>)Expression.Lambda(complexPropertyAccessExpression, parameter).Compile();
return lambda;
}
如果可能,我建议将 string key
参数替换为 Expression<Func<T, object>> key
参数。这样,您的函数调用就可以像您描述的那样 BusinessOrderList.OrderBy(b => b.Quarter.Abbreviation);
。由于所有 OrderBy/OrderByDescending 方法都接受此表达式作为字符串的替代方法,所以我看不出将 key
保留为字符串有什么好处。
您可以传递 Func
来对您的 collection
public static IOrderedEnumerable<T> OrderBy<T>(this IEnumerable<T> collection,
Func<IEnumerable<T>,IOrderedEnumerable<T>> OrderBy)
{
if(OrderBy != null)
return OrderBy(collection);
return collection;
}
你必须这样称呼它
{
Func<IEnumerable<Book>,IOrderedEnumerable<Book>> sort =
list => list.OrderBy(B=>B.Author.Name).ThenByDescending(B=>B.Title) ;
List.OrderBy(sort);
}