运行时基于 LINQ 的通用多级对象排序器






4.43/5 (4投票s)
一个通用辅助函数,可动态地按编译时未知的对象属性对对象进行排序。
引言
我最近遇到了一种情况,我有一个对象列表,每个对象都有属性。这些对象是从 Active Directory 提取的,AD 对象的各种属性加载在 StringDictionary
中。我希望能够根据配置对这些对象进行排序,而无需硬编码任何特定的属性或排序顺序,并且我希望能够按多个属性排序,例如,LastName
升序,然后 FirstName
降序。
当然,你不能简单地遍历要排序的属性列表并进行排序,因为每次排序都会清除之前的排序结果。
LINQ 提供了处理这种情况的方法,OrderBy
和 ThenBy
。但如果不知道编译时要排序的属性,这就会稍微复杂一些。在本文中,我演示了一个简单的通用函数,它可以帮助对数据列表进行任意数量的排序键排序,并且每个排序级别都支持升序和降序。
函数
这是辅助函数
private IEnumerable<T> MultiLevelSort<T, SK>(
IEnumerable<T> list,
List<SK> sortKeys,
Func<T, SK, string> keySelector,
Func<SK, bool> ascendingSelector)
{
if (sortKeys.Count == 0) return list;
IOrderedEnumerable<T> res = null;
for (int i = 0; i < sortKeys.Count; i++)
{
SK sk = sortKeys[i];
bool ascending = ascendingSelector(sk);
if (i == 0)
{
if (ascending) res = list.OrderBy(r => keySelector(r, sk));
else res = list.OrderByDescending(r => keySelector(r, sk));
}
else
{
if (ascending) res = res.ThenBy(r => keySelector(r, sk));
else res = res.ThenByDescending(r => keySelector(r, sk));
}
}
return res;
}
这段代码接受四个参数
- 一个
IEnumerable<T>
对象列表,用于排序 - 一个
List<SK>
对象列表,其中包含排序顺序信息(请注意,此列表本身预计已按正确的排序顺序排列) - 一个
Func<T, SK, string>
,用于根据 SK 中的信息从T
中提取用于实际排序的值 - 一个
Func<SK, bool>
,用于从 SK 中提取升序/降序信息 -true
表示升序,false
表示降序
…它返回正确排序的列表作为 IEnumerable<T>
。请注意,只要至少有一个有效的排序键,实际返回的对象将是 IOrderedEnumerable<T>
。
Using the Code
这是一个如何使用辅助函数的示例。它假定你有一个名为“AllProperties
”的对象中包含“MyProperty
”的列表,其中一些指定了排序信息。
List<MyProperty> sortProps = AllProperties
.Where(sp => sp.Sort != string.Empty)
.OrderBy(sp => sp.SortOrder).ToList();
IEnumerable<MyObject> sortedResults = MultiLevelSort<MyObject, MyProperty>(
results, sortProps,
(r, sp) => r.Properties.ContainsKey(sp.Name) ? r.Properties[sp.Name] : string.Empty,
sp => sp.Sort == "Ascending"
);
... 在此示例中,MyObject
是一个包含名为“Properties
”的 StringDictionary
的对象,而 MyProperty
是一个包含名为“Sort
”(“升序/降序”)、“SortOrder
”(一个整数)和“Name
”(我们想要在 MyObject.Properties
集合中排序的属性的名称)的属性的对象。
你的对象显然可以拥有自己的结构或属性来提供用于排序的数据 - 它不必像此示例中的 StringDictionary
一样。
历史
- v1.0 - 2009 年 10 月 26 日 - 首次发布