使用LINQ进行动态排序

时间:2011-01-18 15:50:11

标签: linq

我有一组CLR对象。该对象的类定义有三个属性:FirstName,LastName,BirthDate。

我有一个字符串,它反映了集合应按其排序的属性的名称。另外,我有一个排序方向。如何将此排序信息动态应用于我的收藏?请注意,排序可以是多层的,例如我可以按LastName排序,然后按FirstName排序。

目前,我正在尝试以下运气:

var results = myCollection.OrderBy(sortProperty);

但是,我收到的消息是:

...不包含'OrderBy'的定义,并且最好的扩展方法重载......有一些无效的参数。

9 个答案:

答案 0 :(得分:10)

好吧,我在评论中与SLaks的争论迫使我想出一个答案:)

我假设你只需要支持LINQ to Objects。这里有一些代码需要大量的验证添加,但确实有效:

// We want the overload which doesn't take an EqualityComparer.
private static MethodInfo OrderByMethod = typeof(Enumerable)
    .GetMethods(BindingFlags.Public | BindingFlags.Static)
    .Where(method => method.Name == "OrderBy" 
           && method.GetParameters().Length == 2)
    .Single();

public static IOrderedEnumerable<TSource> OrderByProperty<TSource>(
    this IEnumerable<TSource> source,
    string propertyName) 
{
    // TODO: Lots of validation :)
    PropertyInfo property = typeof(TSource).GetProperty(propertyName);
    MethodInfo getter = property.GetGetMethod();
    Type propType = property.PropertyType;
    Type funcType = typeof(Func<,>).MakeGenericType(typeof(TSource), propType);
    Delegate func = Delegate.CreateDelegate(funcType, getter);
    MethodInfo constructedMethod = OrderByMethod.MakeGenericMethod(
        typeof(TSource), propType);
    return (IOrderedEnumerable<TSource>) constructedMethod.Invoke(null,
        new object[] { source, func });
}

测试代码:

string[] foo = new string[] { "Jon", "Holly", "Tom", "William", "Robin" };

foreach (string x in foo.OrderByProperty("Length"))
{
    Console.WriteLine(x);
}

输出:

Jon
Tom
Holly
Robin
William

它甚至会返回IOrderedEnumerable<TSource>,因此您可以正常链接ThenBy子句:)

答案 1 :(得分:7)

您需要构建Expression Tree并将其传递给OrderBy 它看起来像这样:

var param = Expression.Parameter(typeof(MyClass));
var expression = Expression.Lambda<Func<MyClass, PropertyType>>(
    Expression.Property(param, sortProperty),
    param
);

或者,您可以使用Dynamic LINQ,这将允许您的代码按原样运行。

答案 2 :(得分:1)

protected void sort_grd(object sender, GridViewSortEventArgs e)
    {
        if (Convert.ToBoolean(ViewState["order"]) == true)
        {
            ViewState["order"] = false;

        }
        else
        {
            ViewState["order"] = true;
        }
        ViewState["SortExp"] = e.SortExpression;
        dataBind(Convert.ToBoolean(ViewState["order"]), e.SortExpression);
    }

public void dataBind(bool ord, string SortExp)
    {
        var db = new DataClasses1DataContext(); //linq to sql class
        var Name = from Ban in db.tbl_Names.AsEnumerable()
                         select new
                         {
                             First_Name = Ban.Banner_Name,
                             Last_Name = Ban.Banner_Project
                         };
        if (ord)
        {
            Name = BannerName.OrderBy(q => q.GetType().GetProperty(SortExp).GetValue(q, null));
        }
        else
        {
            Name = BannerName.OrderByDescending(q => q.GetType().GetProperty(SortExp).GetValue(q, null));
        }
        grdSelectColumn.DataSource = Name ;
        grdSelectColumn.DataBind();
    }

答案 3 :(得分:0)

你可以用Linq

来做到这一点
var results = from c in myCollection
    orderby c.SortProperty
    select c;

答案 4 :(得分:0)

答案 5 :(得分:0)

对于动态排序,您可以评估字符串,例如

List<MyObject> foo = new List<MyObject>();
string sortProperty = "LastName";
var result = foo.OrderBy(x =>
                {
                if (sortProperty == "LastName")
                    return x.LastName;
                else
                    return x.FirstName;
                });

有关更通用的解决方案,请参阅此SO主题:Strongly typed dynamic Linq sorting

答案 6 :(得分:0)

您需要使用反射来获取PropertyInfo,然后使用它来构建表达式树。像这样:

var entityType = typeof(TEntity);
var prop = entityType.GetProperty(sortProperty);
var param = Expression.Parameter(entityType, "x");
var access = Expression.Lambda(Expression.MakeMemberAccess(param, prop), param);

var ordered = (IOrderedQueryable<TEntity>) Queryable.OrderBy(
    myCollection, 
    (dynamic) access);

答案 7 :(得分:0)

您可以复制粘贴我在该答案中发布的方法,并更改签名/方法名称: How to make the position of a LINQ Query SELECT variable

答案 8 :(得分:0)

您实际上可以使用原始代码行

var results = myCollection.OrderBy(sortProperty);

只需使用System.Linq.Dynamic库。

如果您遇到编译器错误(无法转换或不包含定义......),您可能必须这样做:

var results = myCollection.AsQueryable().OrderBy(sortProperty);

不需要任何表达式树或数据绑定。