我在VS2008动态LINQ示例中找到了一个示例,允许您使用类似sql的字符串(例如OrderBy(“Name, Age DESC”))进行排序。不幸的是,所包含的方法只适用于IQueryable<T>。有什么办法得到这个功能IEnumerable<T>?


当前回答

经过大量的搜索,这对我来说很有效:

public static IEnumerable<TEntity> OrderBy<TEntity>(this IEnumerable<TEntity> source, 
                                                    string orderByProperty, bool desc)
{
    string command = desc ? "OrderByDescending" : "OrderBy";
    var type = typeof(TEntity);
    var property = type.GetProperty(orderByProperty);
    var parameter = Expression.Parameter(type, "p");
    var propertyAccess = Expression.MakeMemberAccess(parameter, property);
    var orderByExpression = Expression.Lambda(propertyAccess, parameter);
    var resultExpression = Expression.Call(typeof(Queryable), command, 
                                           new[] { type, property.PropertyType },
                                           source.AsQueryable().Expression, 
                                           Expression.Quote(orderByExpression));
    return source.AsQueryable().Provider.CreateQuery<TEntity>(resultExpression);
}

其他回答

我试图这样做,但有问题与Kjetil Watnedal的解决方案,因为我不使用内联linq语法-我更喜欢方法风格的语法。我的具体问题是尝试使用自定义IComparer进行动态排序。

我的解决方案是这样的:

给定一个IQueryable查询,如下:

List<DATA__Security__Team> teams = TeamManager.GetTeams();
var query = teams.Where(team => team.ID < 10).AsQueryable();

给定一个运行时排序字段参数:

string SortField; // Set at run-time to "Name"

动态OrderBy看起来是这样的:

query = query.OrderBy(item => item.GetReflectedPropertyValue(SortField));

这是使用一个叫做GetReflectedPropertyValue()的小助手方法:

public static string GetReflectedPropertyValue(this object subject, string field)
{
    object reflectedValue = subject.GetType().GetProperty(field).GetValue(subject, null);
    return reflectedValue != null ? reflectedValue.ToString() : "";
}

最后一件事——我提到过我想让OrderBy使用自定义iccomparer——因为我想做自然排序。

要做到这一点,我只需要改变OrderBy为:

query = query.OrderBy(item => item.GetReflectedPropertyValue(SortField), new NaturalSortComparer<string>());

有关NaturalSortComparer()的代码,请参阅这篇文章。

我想使用反射来获得你想要排序的任何属性是可行的:

IEnumerable<T> myEnumerables
var query=from enumerable in myenumerables
          where some criteria
          orderby GetPropertyValue(enumerable,"SomeProperty")
          select enumerable

private static object GetPropertyValue(object obj, string property)
{
    System.Reflection.PropertyInfo propertyInfo=obj.GetType().GetProperty(property);
    return propertyInfo.GetValue(obj, null);
}

注意,使用反射比直接访问属性要慢得多,因此必须研究性能。

你可以将IEnumerable转换为IQueryable。

items = items.AsQueryable().OrderBy("Name ASC");

将List转换为IEnumerable或Iquerable,使用System.LINQ.Dynamic命名空间添加,然后你可以用逗号分隔的字符串提到OrderBy方法,OrderBy方法默认来自System.LINQ.Dynamic。

这个答案是对@John Sheehan - Runscope提供的解决方案需要一个示例的评论的回应

请为我们其他人提供一个例子。

在DAL(数据访问层),

IEnumerable版本:

public  IEnumerable<Order> GetOrders()
{
    // i use Dapper to return IEnumerable<T> using Query<T>
    //.. do stuff

    return orders  // IEnumerable<Order>
}

IQueryable版本

public IQueryable<Order> GetOrdersAsQuerable()
{
    IEnumerable<Order> qry= GetOrders();

    // use the built-in extension method  AsQueryable in  System.Linq namespace
    return qry.AsQueryable();            
}

现在你可以使用IQueryable版本来绑定,例如Asp.net中的GridView和排序的好处(你不能使用IEnumerable版本进行排序)

我使用Dapper作为ORM并构建IQueryable版本,并在asp.net中的GridView中使用排序。