在 C# 中构建 LINQ 查询的动态排序子句





5.00/5 (3投票s)
概述一个辅助类,用于在 C# 的 LINQ 查询中构建动态排序子句
引言
很多时候,我们需要在 C# 中处理类似 SQL 的 OrderBy
。 这将帮助您解决动态排序问题。 这是一个 OrderBy
扩展,它接收一个类似 SQL 的 OrderBy 字符串
,并对 IQueryable
或 IEnumerable
集合进行排序。
背景
了解以下信息会很有帮助
yield
IQueryable
IEnumerable
Reflection(反射)
Using the Code
要使用此扩展,我们只需要传递列表和要排序列表的排序参数。 例如
SortingHelper.SortByClause(list, SortingParms).ToList();
public static class SortingHelper
{
private class SortByInfo
{
public SortDirection Direction { get; set; }
public string PropertyName { get; set; }
public bool Initial { get; set; }
}
private enum SortDirection
{
Ascending = 0,
Descending = 1
}
public static IEnumerable<T> SortByClause<T>
(this IEnumerable<T> enumerable, string sortBy)
{
return enumerable.AsQueryable().SortBy(sortBy).AsEnumerable();
}
public static IQueryable<T> SortBy<T>
(this IQueryable<T> collection, string sortBy)
{
foreach(SortByInfo sortByInfo in ParseOrderBy(sortBy))
collection = ApplyOrderBy<T>(collection, sortByInfo);
return collection;
}
private static IEnumerable<SortByInfo> ParseOrderBy(string sortBy)
{
if (String.IsNullOrEmpty(sortBy))
yield break;
string[] items = sortBy.Split(',');
bool initial = true;
foreach(string item in items)
{
string[] pair = item.Trim().Split('-');
if (pair.Length > 2)
throw new ArgumentException(String.Format
("Invalid OrderBy string '{0}'. Order By Format: Property,
Property2-DESC, Property2-ASC",item));
string prop = pair[0].Trim();
if(String.IsNullOrEmpty(prop))
throw new ArgumentException("Invalid Property.
Order By Format: Property, Property2-DESC, Property2-ASC");
SortDirection dir = SortDirection.Ascending;
if (pair.Length == 2)
dir = ("desc".Equals(pair[1].Trim(),
StringComparison.OrdinalIgnoreCase) ?
SortDirection.Descending : SortDirection.Ascending);
yield return new SortByInfo() { PropertyName = prop,
Direction = dir, Initial = initial };
initial = false;
}
}
private static IQueryable<T> ApplyOrderBy<T>
(IQueryable<T> collection, SortByInfo sortByInfo)
{
string[] props = sortByInfo.PropertyName.Split('.');
Type type = typeof(T);
ParameterExpression arg = Expression.Parameter(type, "x");
Expression expr = arg;
foreach (string prop in props)
{
PropertyInfo pi = type.GetProperty(prop);
expr = Expression.Property(expr, pi);
type = pi.PropertyType;
}
Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), type);
LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);
string methodName = String.Empty;
if (!sortByInfo.Initial && collection is IOrderedQueryable<T>)
{
if (sortByInfo.Direction == SortDirection.Ascending)
methodName = "ThenBy";
else
methodName = "ThenByDescending";
}
else
{
if (sortByInfo.Direction == SortDirection.Ascending)
methodName = "OrderBy";
else
methodName = "OrderByDescending";
}
return (IOrderedQueryable<T>)typeof(Queryable).GetMethods().Single(
method => method.Name == methodName
&& method.IsGenericMethodDefinition
&& method.GetGenericArguments().Length == 2
&& method.GetParameters().Length == 2)
.MakeGenericMethod(typeof(T), type)
.Invoke(null, new object[] { collection, lambda });
}
}
希望这能有所帮助!
历史
- 2022 年 6 月 5 日:初始版本