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


当前回答

我可以用下面的代码做到这一点。不需要编写长而复杂的代码。

 protected void sort_array(string field_name, string asc_desc)
        {

            objArrayList= Sort(objArrayList, field_name, asc_desc);
        }

        protected List<ArrayType> Sort(List<ArrayType> input, string property, string asc_desc)
        {
            if (asc_desc == "ASC")
            {

                return input.OrderBy(p => p.GetType()
                                           .GetProperty(property)
                                           .GetValue(p, null)).ToList();
            }
            else
            {
                return input.OrderByDescending(p => p.GetType()
                                               .GetProperty(property)
                                               .GetValue(p, null)).ToList();
            }
        }

其他回答

我试图这样做,但有问题与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()的代码,请参阅这篇文章。

只是在别人说的基础上。我发现下面的方法效果很好。

public static IEnumerable<T> OrderBy<T>(this IEnumerable<T> input, string queryString)
{
    if (string.IsNullOrEmpty(queryString))
        return input;

    int i = 0;
    foreach (string propname in queryString.Split(','))
    {
        var subContent = propname.Split('|');
        if (Convert.ToInt32(subContent[1].Trim()) == 0)
        {
            if (i == 0)
                input = input.OrderBy(x => GetPropertyValue(x, subContent[0].Trim()));
            else
                input = ((IOrderedEnumerable<T>)input).ThenBy(x => GetPropertyValue(x, subContent[0].Trim()));
        }
        else
        {
            if (i == 0)
                input = input.OrderByDescending(x => GetPropertyValue(x, subContent[0].Trim()));
            else
                input = ((IOrderedEnumerable<T>)input).ThenByDescending(x => GetPropertyValue(x, subContent[0].Trim()));
        }
        i++;
    }

    return input;
}

这个答案是对@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中使用排序。

我无意中发现了这个问题。

使用Marc的ApplyOrder实现,我把一个Extension方法组合在一起,处理类似sql的字符串,如:

list.OrderBy("MyProperty DESC, MyOtherProperty ASC");

详情可以在这里找到:http://aonnull.blogspot.com/2010/08/dynamic-sql-like-linq-orderby-extension.html

另一种解决方案使用以下类/接口。它不是真正的动态,但它是有效的。

public interface IID
{
    int ID
    {
        get; set;
    }
}

public static class Utils
{
    public static int GetID<T>(ObjectQuery<T> items) where T:EntityObject, IID
    {
        if (items.Count() == 0) return 1;
        return items.OrderByDescending(u => u.ID).FirstOrDefault().ID + 1;
    }
}