[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