linq 为列表排序(MyObjects)
Posted
技术标签:
【中文标题】linq 为列表排序(MyObjects)【英文标题】:linq Order By for a List(Of myObjects) 【发布时间】:2010-10-11 01:21:33 【问题描述】:如何在我的对象列表中按传递的字符串值排序?我需要对我的 List(Of) 对象进行分页和排序,分页没问题,但我不知道该让谁来工作。
这是我目前正在做的事情,效果很好:
Return returnReports.Skip(PageSize * (PageNumber-1)).Take(PageSize).ToList()
如何让它工作?
Return returnReports.OrderBy(SortColumn).Skip(skip).Take(PageSize).ToList()
SortColumn 是一个传递的字符串值
【问题讨论】:
【参考方案1】:您可以使用 .Sort 代替 .OrderBy。只需为您的对象创建一个 Comparer 类,例如 this。
public class FooComparer : IComparer<Foo>
private readonly string _sortBy;
private readonly bool _sortDesc;
public FooComparer(string sortBy)
_sortBy = sortBy.ToLower();
_sortDesc = _sortBy.EndsWith(" desc");
_sortBy = _sortBy.Replace(" asc", string.Empty).Replace(" desc", string.Empty);
//implement IComparer method
public int Compare(Foo x, Foo y)
int ret = 0;
switch (_sortBy)
//must match lowercase sortname
case "date":
ret = DateTime.Compare(x.SomeDate, y.SomeDate);
break;
//other properties you can sort by as above...
//if there is a tie, break it consistently - this will be specific to your object
if (ret == 0)
ret = (DateTime.Compare(x.InsertDate, y.InsertDate));
if (_sortDesc)
ret *= -1;
return ret;
那么排序调用就变成了:
Return Foo.Sort(new FooComparer(sortName + " " + sortOrder)
所以,你的会变成(排序顺序在未指定时默认为升序):
returnReports.Sort(new ReturnReportsComparer(SortColumn));
return returnReports.Skip(skip).Take(PageSize).ToList()
【讨论】:
【参考方案2】:VB
Module OrderByExtensions
<System.Runtime.CompilerServices.Extension()> _
Public Function OrderByPropertyName(Of T)(ByVal e As IEnumerable(Of T), ByVal propertyName As String) As IOrderedEnumerable(Of T)
Dim itemType = GetType(T)
Dim prop = itemType.GetProperty(propertyName)
If prop Is Nothing Then Throw New ArgumentException("Object does not have the specified property")
Dim propType = prop.PropertyType
Dim funcType = GetType(Func(Of ,)).MakeGenericType(itemType, propType)
Dim parameter = Expression.Parameter(itemType, "item")
Dim exp = Expression.Lambda(funcType, Expression.MakeMemberAccess(parameter, prop), parameter)
Dim params = New Object() e, exp.Compile()
Return DirectCast(GetType(OrderByExtensions).GetMethod("InvokeOrderBy", Reflection.BindingFlags.Static Or Reflection.BindingFlags.NonPublic).MakeGenericMethod(itemType, propType).Invoke(Nothing, params), IOrderedEnumerable(Of T))
End Function
Private Function InvokeOrderBy(Of T, U)(ByVal e As IEnumerable(Of T), ByVal f As Func(Of T, U)) As IOrderedEnumerable(Of T)
Return Enumerable.OrderBy(e, f)
End Function
End Module
C#
public static class OrderByExtensions
public static IOrderedEnumerable<T> OrderByPropertyName<T>(this IEnumerable<T> e, string name)
var itemType = typeof(T);
var prop = itemType.GetProperty(name);
if (prop == null) throw new ArgumentException("Object does not have the specified property");
var propType = prop.PropertyType;
var funcType = typeof(Func<,>).MakeGenericType(itemType, propType);
var parameter = Expression.Parameter(itemType, "item");
var memberAccess = Expression.MakeMemberAccess(parameter, prop);
var expression = Expression.Lambda(funcType, memberAccess, parameter);
var x = typeof(OrderByExtensions).GetMethod("InvokeOrderBy", BindingFlags.Static | BindingFlags.NonPublic);
return (IOrderedEnumerable<T>)x.MakeGenericMethod(itemType, propType).Invoke(null, new object[] e, expression.Compile() );
static IOrderedEnumerable<T> InvokeOrderBy<T, U>(IEnumerable<T> e, Func<T, U> f)
return e.OrderBy(f);
【讨论】:
不过,当 SortColumn 作为字符串传入时,这是行不通的。 你已经错过了 C# 代码中 e 参数中的 this,因为它们不是扩展方法。 @Richard:这很有趣,因为我一直在努力确保 VB 是正确的(作为一个 C# 人)我在翻译成 C# 时错过了this
。
这太棒了——我得研究一下。还有一件事,我将如何做到这一点,以便我可以说是要按升序还是降序排列?
只需复制并粘贴它并替换所有 OrderBy -> OrderByDescending。顺便说一句,这不是一个非常高效的方法,因为它必须使用反射并动态构建表达式。如果您知道您正在使用的类型,请使用 Jon 的解决方案。【参考方案3】:
将排序列作为函数传递。
原来如此
public SomeList Foo(Function<Foo, bool> sortFunction, int skip, int PageSize)
return returnReports.OrderBy(sortFunction).Skip(skip).Take(PageSize).ToList();
这样称呼
SomeList(f => f.Bar, 5, 10);
【讨论】:
Action如果您使用数据库作为数据源,那么您可以使用Dynamic LINQ 项目,该项目允许您将 Where 子句的参数指定为字符串。
如果您使用“Linq to objects”,则需要创建作为参数动态传递的 lambda 函数。为此,您可以使用“Expression.Xyz”方法构建表达式树,然后使用“Compile”方法将表达式树转换为可调用委托(Func 类型),您可以将其用作参数在哪里。 another SO thread here 有一个如何构造表达式树的例子。
【讨论】:
【参考方案5】:如果你只是传递了一个字符串,你就不能(容易地)做到这一点。您可以有一个从 String 到 Func<IEnumerable<Report>, IEnumerable<Report>>
的映射,例如(在 C# 中)
// Horrible type. Ick.
private static readonly
Dictionary<string, Func<IEnumerable<Report>,IEnumerable<Report>>>
Orderings =
new Dictionary<string, Func<IEnumerable<Report>,IEnumerable<Report>>>
"FirstColumn", (IEnumerable<Report> reports) =>
reports.OrderBy(report => report.FirstColumn) ,
"SecondColumn", (IEnumerable<Report> reports) =>
reports.OrderBy(report => report.SecondColumn) ,
(etc)
;
然后使用:
// For production usage, include some error checking!
return Orderings[sortColumn].Skip(skip).Take(pageSize).ToList();
如果您可以将SortColumn
作为适当的Func
传入(可能通过使您的方法通用),这将避免这里的混乱。
【讨论】:
以上是关于linq 为列表排序(MyObjects)的主要内容,如果未能解决你的问题,请参考以下文章