[C#.NET][LINQ] OrderBy String (By Property Name)
Linq 所提供的排序方法,必須要傳入強型別的屬性給 OrderBy,但有時候還是會用到欄位字串排序,比如說點選 GridView 上的 Column 進行排序,它處理起來其實不難,只要將屬性的值拿出來餵給 IEnumerable.OrderBy | IQueryable.OrderBy 就可以了
首先準備假資料:(資料真的很假,年齡跟生日不吻合)
{ public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } public string Email { get; set; } public DateTime? Birthday { get; set; } public static IEnumerable<Employee> GetAllEmployees() { var employees = new List<Employee>(); employees.Add(new Employee() { Id = 1, Age = 49, Name = "yao", Email = "yao@aa.bb", Birthday = new DateTime(1981, 11, 12, 21, 44, 14) }); employees.Add(new Employee() { Id = 2, Age = 22, Name = "Kobe", Email = "kobe@aa.cc", Birthday = new DateTime(1966, 08, 11, 20, 35, 14) }); employees.Add(new Employee() { Id = 3, Age = 33, Name = "Jordan", Email = "jordan@aa.bb", Birthday = new DateTime(1971, 01, 12, 02, 33, 14) }); employees.Add(new Employee() { Id = 4, Age = 61, Name = "Duke", Email = "Duke@aa.cc", Birthday = new DateTime(1981, 02, 02, 17, 25, 14) }); employees.Add(new Employee() { Id = 5, Age = 26, Name = "Bill", Email = "bill@aa.cc", Birthday = new DateTime(1980, 03, 12, 13, 25, 14) }); employees.Add(new Employee() { Id = 6, Age = 25, Name = "Elliot", Email = "Elliot@aa.cc", Birthday = new DateTime(1983, 02, 22, 13, 25, 14) }); employees.Add(new Employee() { Id = 7, Age = 36, Name = "Gabe", Email = "Gabe@aa.cc", Birthday = new DateTime(1940, 12, 22, 09, 25, 14) }); employees.Add(new Employee() { Id = 8, Age = 19, Name = "George", Email = "George@aa.cc", Birthday = new DateTime(1987, 03, 22, 13, 25, 14) }); employees.Add(new Employee() { Id = 9, Age = 21, Name = "Ian", Email = "Ian@aa.cc", Birthday = new DateTime(1940, 09, 23, 13, 04, 14) }); employees.Add(new Employee() { Id = 10, Age = 28, Name = "Kevin", Email = "Kevin@aa.cc", Birthday = new DateTime(1950, 12, 22, 13, 25, 14) }); return employees; } }
取得物件欄位的值程式碼如下:
{ PropertyInfo propertyInfo = typeof(TSource).GetProperty(propertyName); var result = propertyInfo.GetValue(source, null); return result; }
調用端,傳入要排序的欄位即可
觀察 LINQ 輸出結果,如我所期望,如下圖
最後把它們變成擴充方法
{ return orders(sources, propertyName, false); } public static IEnumerable<TSource> OrderByDescending<TSource>(this IEnumerable<TSource> sources, string propertyName) { return orders(sources, propertyName, true); } private static IEnumerable<TSource> orders<TSource>(IEnumerable<TSource> sources, string propertyName, bool isDescending) { PropertyInfo propertyInfo = typeof(TSource).GetProperty(propertyName); if (propertyInfo == null) { return sources; } if (isDescending) { return sources.OrderByDescending(x => propertyInfo.GetValue(x, null)); } else { return sources.OrderBy(x => propertyInfo.GetValue(x, null)); } }
當然也可以使用 Expression
{ return orders(sources, propertyName, "OrderBy"); } public static IQueryable<TSource> OrderByDescending<TSource>(this IQueryable<TSource> sources, string propertyName, params object[] values) { return orders(sources, propertyName, "OrderByDescending"); } private static IQueryable<TSource> orders<TSource>(IQueryable<TSource> sources, string propertyName, string orderExpression) { var type = typeof(TSource); var propertyInfo = type.GetProperty(propertyName); var parameter = Expression.Parameter(type, "parameter"); var propertyAccess = Expression.MakeMemberAccess(parameter, propertyInfo); var orderByExp = Expression.Lambda(propertyAccess, parameter); MethodCallExpression resultExp = Expression.Call( typeof(Queryable), orderExpression, new Type[] { type, propertyInfo.PropertyType }, sources.Expression, Expression.Quote(orderByExp)); return sources.Provider.CreateQuery<TSource>(resultExp); }
完整程式碼如下:
最後用單元測試測剛剛寫的方法
程式碼如下:
本文出自:http://www.dotblogs.com.tw/yc421206/archive/2014/11/25/147419.aspx
補充:
Nuget Server 上的 System.Linq.Dynamic,就是在處理這一部份,太晚發現這下白寫了
若有謬誤,煩請告知,新手發帖請多包涵
Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET