C# Linq处理OrderBy的变量数
我需要在Linq(to实体)语句中支持数量可变的Orderby术语。也就是说,我的函数将接受一个属性列表,其中的数据应按顺序排列。属性可以有升序或降序排序。处理构造Linq查询的最佳方法是什么C# Linq处理OrderBy的变量数,c#,linq,linq-to-entities,C#,Linq,Linq To Entities,我需要在Linq(to实体)语句中支持数量可变的Orderby术语。也就是说,我的函数将接受一个属性列表,其中的数据应按顺序排列。属性可以有升序或降序排序。处理构造Linq查询的最佳方法是什么 谢谢 要按任意属性排序,需要构建表达式树以传递给OrderBy 要按任意数量的属性排序,您需要在循环中调用然后再调用。您应该能够按照以下方式执行操作: public IEnumerable<MyType> DoSomething(params Expression<Func<MyT
谢谢 要按任意属性排序,需要构建表达式树以传递给
OrderBy
要按任意数量的属性排序,您需要在循环中调用
然后再调用。您应该能够按照以下方式执行操作:
public IEnumerable<MyType> DoSomething(params Expression<Func<MyType,object>>[] properties)
{
var query = // create LINQ query that returns IQueryable<MyType>
query = query.OrderBy(properties.First());
foreach (var property in properties.Skip(1))
{
query = query.ThenBy(property);
}
}
…
var results = DoSomething(() => x.Age, () => x.Height, () => x.LastName);
public IEnumerable DoSomething(参数表达式[]属性)
{
var query=//创建返回IQueryable的LINQ查询
query=query.OrderBy(properties.First());
foreach(properties.Skip(1)中的var属性)
{
query=query.ThenBy(属性);
}
}
…
var结果=剂量测量(()=>x.年龄,()=>x.身高,()=>x.姓氏);
您需要处理指定的属性少于2个的情况。从开始,这可以成为一个很好的扩展方法:
public static class EnumerableExtensions
{
public static IEnumerable<T> OrderByMany<T>(this IEnumerable<T> enumerable,
params Expression<Func<T, object>>[] expressions)
{
if (expressions.Length == 1)
return enumerable.OrderBy(expressions[0].Compile());
var query = enumerable.OrderBy(expressions[0].Compile());
for (int i = 1; i < expressions.Length;i++)
{
query = query.ThenBy(expressions[i].Compile());
}
return query;
}
}
这是可能的:
var people = new Person[]
{
new Person() {Name = "John", Age = 40},
new Person() {Name = "John", Age = 20},
new Person() {Name = "Agnes", Age = 11}
};
foreach(var per in people.OrderByMany(x => x.Name, x => x.Age))
{
Console.WriteLine("{0} Age={1}",per.Name,per.Age);
}
输出:
Agnes Age=11
John Age=20
John Age=40
更新
您可以添加另一个重载的OrderByMany
方法来支持SortOrder,尽管它很快就会变得笨重。就我个人而言,我只会选择语法
var query = from p
in people
order by Name, Age descending;
然而,作为记录,至少在C#4中,我将使用枚举和元组来完成重载
public enum SortOrder
{
Ascending,
Descending
}
还有额外的过载:
public static IEnumerable<T> OrderByMany<T>(this IEnumerable<T> enumerable,
params Tuple<Expression<Func<T, object>>,SortOrder>[] expressions)
{
var query = (expressions[0].Item2 == SortOrder.Ascending)
? enumerable.OrderBy(expressions[0].Item1.Compile())
: enumerable.OrderByDescending(expressions[0].Item1.Compile());
for (int i = 1; i < expressions.Length; i++)
{
query = expressions[i].Item2 == SortOrder.Ascending
? query.ThenBy(expressions[i].Item1.Compile())
: query.ThenByDescending(expressions[i].Item1.Compile());
}
return query;
}
公共静态IEnumerable OrderByMany(此IEnumerable可枚举,
参数元组[]表达式)
{
变量查询=(表达式[0]。项2==排序器。升序)
?enumerable.OrderBy(表达式[0].Item1.Compile())
:enumerable.OrderByDescending(表达式[0].Item1.Compile());
for(int i=1;i
用法变得笨拙且难以阅读:
foreach (var per in people.OrderByMany(
new Tuple<Expression<Func<Person, object>>, SortOrder>(x => x.Age, SortOrder.Descending),
new Tuple<Expression<Func<Person, object>>, SortOrder>(x => x.Name, SortOrder.Ascending)))
{
Console.WriteLine("{0} Age={1}", per.Name, per.Age);
}
foreach(people.OrderByMany中的变量per)(
新元组(x=>x.Age,SortOrder.Descending),
新元组(x=>x.Name,SortOrder.升序)))
{
WriteLine(“{0}Age={1}”,per.Name,per.Age);
}
我喜欢Jamiec的想法,但我讨厌使用元组,因为语法很难看。因此,我构建了一个小型类来封装元组,并使用更好的变量名公开Item1和Item2属性的getter
还请注意,我使用了升序的默认排序顺序,因此如果要按降序排序,只需指定排序器
public class SortExpression<T>
{
private Tuple<Expression<Func<T, object>>, SortOrder> tuple;
public SortExpression( Expression<Func<T, object>> expression, SortOrder order =SortOrder.Ascending )
{
tuple = new Tuple<Expression<Func<T,object>>, SortOrder>(expression, order);
}
public Expression<Func<T, object>> Expression {
get { return tuple.Item1; }
}
public SortOrder Order {
get { return tuple.Item2; }
}
}
公共类SortExpression
{
私有元组;
公共排序表达式(表达式表达式,排序顺序=SortOrder.升序)
{
tuple=新的tuple(表达式、顺序);
}
公开表达{
获取{return tuple.Item1;}
}
公共分拣令{
获取{return tuple.Item2;}
}
}
在我的特定应用程序中,我有一个repository基类,它接受IQueryable并将其转换为ObservableCollection。在该方法中,我使用SortExpression类:
public ObservableCollection<T> GetCollection(params SortExpression<T>[] sortExpressions) {
var list = new ObservableCollection<T>();
var query = FindAll();
if (!sortExpressions.Any()) {
query.ToList().ForEach(list.Add);
return list;
}
var ordered = (sortExpressions[0].Order == SortOrder.Ascending)
? query.OrderBy(sortExpressions[0].Expression.Compile())
: query.OrderByDescending(sortExpressions[0].Expression.Compile());
for (var i = 1; i < sortExpressions.Length; i++) {
ordered = sortExpressions[i].Order == SortOrder.Ascending
? ordered.ThenBy(sortExpressions[i].Expression.Compile())
: ordered.ThenByDescending(sortExpressions[i].Expression.Compile());
}
ordered.ToList().ForEach(list.Add);
return list;
}
public-observeCollection-GetCollection(参数SortExpression[]sortExpressions){
var list=新的ObservableCollection();
var query=FindAll();
如果(!sortExpressions.Any()){
query.ToList().ForEach(list.Add);
退货清单;
}
var ordered=(sortExpressions[0]。Order==SortOrder.升序)
?query.OrderBy(sortExpressions[0].Expression.Compile())
:query.OrderByDescending(sortExpressions[0].Expression.Compile());
对于(变量i=1;i
以下是正在使用的方法:
var repository = new ContactRepository(UnitOfWork);
return repository.GetCollection(
new SortExpression<Contact>(x => x.FirstName),
new SortExpression<Contact>(x => x.LastName));
var repository=新联系人存储库(UnitOfWork);
return repository.GetCollection(
新的SortExpression(x=>x.FirstName),
新的SortExpression(x=>x.LastName));
谢谢!OrderBYMany是否可以修改为支持传递IComparer?忽略上面的内容。我添加了IComparer很好。如何修改它以通过升序和降序排序。一个很好的答案!您还可以编写一个GetTuple扩展。请看一个例子。这样一来,阅读起来就容易多了!:)@JerryKur你能告诉我你是如何添加IComparer的吗?在添加IComparer comparer
作为参数后,myy Visual Studio在OrderBy方法调用时抱怨说,无法从用法推断方法“Enumerable.OrderBy(IEnumerable,Func,IComparer)”的类型参数。尝试显式指定类型参数。
var repository = new ContactRepository(UnitOfWork);
return repository.GetCollection(
new SortExpression<Contact>(x => x.FirstName),
new SortExpression<Contact>(x => x.LastName));