Dynamically Sorting with LINQ

后端 未结 9 1886
自闭症患者
自闭症患者 2020-12-16 04:57

I have a collection of CLR objects. The class definition for the object has three properties: FirstName, LastName, BirthDate.

I have a string that reflects the name

相关标签:
9条回答
  • 2020-12-16 05:38

    For this sort of dynamic work I've been using the Dynamic LINQ library which makes this sort of thing easy:

    http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

    http://msdn2.microsoft.com/en-us/vcsharp/bb894665.aspx

    0 讨论(0)
  • 2020-12-16 05:39

    For dynamic sorting you could evaluate the string i.e. something like

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

    For a more generic solution see this SO thread: Strongly typed dynamic Linq sorting

    0 讨论(0)
  • 2020-12-16 05:40

    You need to build an Expression Tree and pass it to OrderBy.
    It would look something like this:

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

    Alternatively, you can use Dynamic LINQ, which will allow your code to work as-is.

    0 讨论(0)
  • 2020-12-16 05:41
    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();
        }
    
    0 讨论(0)
  • 2020-12-16 05:45

    You can actually use your original line of code

    var results = myCollection.OrderBy(sortProperty);
    

    simply by using the System.Linq.Dynamic library.

    If you get a compiler error (something like cannot convert from or does not contain a definition...) you may have to do it like this:

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

    No need for any expression trees or data binding.

    0 讨论(0)
  • 2020-12-16 05:49

    Okay, my argument with SLaks in his comments has compelled me to come up with an answer :)

    I'm assuming that you only need to support LINQ to Objects. Here's some code which needs significant amounts of validation adding, but does work:

    // 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 });
    }
    

    Test code:

    string[] foo = new string[] { "Jon", "Holly", "Tom", "William", "Robin" };
    
    foreach (string x in foo.OrderByProperty("Length"))
    {
        Console.WriteLine(x);
    }
    

    Output:

    Jon
    Tom
    Holly
    Robin
    William
    

    It even returns an IOrderedEnumerable<TSource> so you can chain ThenBy clauses on as normal :)

    0 讨论(0)
提交回复
热议问题