创建匿名LINQ拉姆达排序表达式
问题描述:
如何创建能够将基于MyObject的性质采取在的SortExpression一个通用的方法,这样的事情:创建匿名LINQ拉姆达排序表达式
void CreateSortedReport(IList<MyObject> list, Expression<Func<MyObject, TSort>> sortExpression, bool ascending = true)
{
//sort the [list] by sortExpression and by direction;
}
,这样我可以使用它像这样:
CreateSortedReport(myItems, x=>x.Name);
或
CreateSortedReport(myItems, x=>x.CreateDate);
编辑1: 我之所以问通用的方法,因为有一些方法,这是非常相似的:
CreateReportSortedByName(myItems) {
return myItems.OrderBy(x=>x.Name);
}
CreateReportSortedByDate(myItems) {
return myItems.OrderBy(x=>x.CreateDate);
}
答
假设MyObject
的具体类型,只是一个通用的参数(<TSort>
)添加到您的方法签名:
void CreateReport<TSort>(IList<MyObject> list, Expression<Func<MyObject, TSort>> sortExpression, bool ascending = true)
如果你想MyObject
是一个泛型参数,您的签名看起来就像这样:
void CreateReport<MyObject, TSort>(IList<MyObject> list, Expression<Func<MyObject, TSort>> sortExpression, bool ascending = true)
答
要使用内置排序功能提供就地排序,您需要编写一个实现IComparer<T>
的类。
例如:
class CompareWithDelegate<TOnObject, TSort> : IComparer<TOnObject>
{
Func<TOnObject, TSort> evaluator;
IComparer comparer = Comparer.Default;
bool ascending;
public CompareWithDelegate(Expression<Func<TOnObject, TSort>> expr, bool ascending = true)
{
evaluator = expr.Compile();
this.ascending = ascending;
}
public int Compare(TOnObject left, TOnObject right)
{
var leftVal = evaluator(left);
var rightVal = evaluator(right);
return (ascending ? 1 : -1) * comparer.Compare(leftVal, rightVal);
}
}
然后:
void CreateSortedReport<TSort>(List<MyObject> list, Expression<Func<MyObject, TSort>> sortExpression, bool ascending = true)
{
list.Sort(new CompareWithDelegate<MyObject, TSort>(sortExpression));
list.Dump();
}
注意,list
必须List<MyObject>
,不IList<MyObject>
。
或者,如果你不需要它是原地的,你有两个选择:
更改签名Func<MyObject, TSort>
:
void CreateSortedReport<TSort>(List<MyObject> list, Func<MyObject, TSort> sortExpression, bool ascending = true)
{
var t =
ascending
? list.OrderBy (sortExpression)
: list.OrderByDescending(sortExpression);
}
或编译的飞行表达:
void CreateSortedReport<TSort>(List<MyObject> list, Expression<Func<MyObject, TSort>> sortExpression, bool ascending = true)
{
var method = sortExpression.Compile();
var t =
ascending
? list.OrderBy (method)
: list.OrderByDescending(method);
}
答
您可以建立一个基于内置List(of T).Sort(IComparer(of T))的扩展方法。
public static class SortExtension
{
public static void SortBy<T, TProperty>(this List<T> list, Func<T, TProperty> orderby, bool ascending = true)
{
list.Sort(new InnerComparer<T, TProperty>(orderby, ascending));
}
class InnerComparer<T, TProperty> : IComparer<T>
{
private readonly Func<T, TProperty> _property;
private readonly int _ascending;
public InnerComparer(Func<T, TProperty> property, bool ascending)
{
_property = property;
_ascending = ascending ? 1 : -1;
}
int IComparer<T>.Compare(T x, T y)
{
var p1 = _property(x);
var p2 = _property(y);
return _ascending * Comparer<TProperty>.Default.Compare(p1, p2);
}
}
}
用法:
myObjects.SortBy(o => o.MyProperty);
@DioPhung,如果你在'IList的'操作,可以替代使用'Func键'你的表达单子。 –
@sstan:没错,我想在该方法内部进行就地排序。 –