我在寫一個列表排序擴展方法。 我的輸入是列表和一個帶有屬性名稱和排序方向的字符串。 該字符串可以有多個屬性,像這樣: 「名稱ASC,日期降序」等列表動態鏈接列表<T> orderby
我已經實施的字符串解析和使用反射來從字符串獲取該屬性本身,而是什麼,我停留在現在我如何動態鏈接順序的方法。
類似: _list.orderBy(x=>x.prop1).thenBy(x=>x.prop2)
等
有什麼辦法來動態地建立這個?
我在寫一個列表排序擴展方法。 我的輸入是列表和一個帶有屬性名稱和排序方向的字符串。 該字符串可以有多個屬性,像這樣: 「名稱ASC,日期降序」等列表動態鏈接列表<T> orderby
我已經實施的字符串解析和使用反射來從字符串獲取該屬性本身,而是什麼,我停留在現在我如何動態鏈接順序的方法。
類似: _list.orderBy(x=>x.prop1).thenBy(x=>x.prop2)
等
有什麼辦法來動態地建立這個?
使用反射從字符串屬性名稱一個PropertyInfo的。然後,您可以使用PropertyInfo構建表達式樹來動態構造所有的orderbys。一旦你有了表達式樹,將它編譯成一個委託,(比如說Func,IEnumerable>)將_list參數傳遞給這個委託,並且它將給你有序結果作爲另一個枚舉。
,以便得到有關可枚舉泛型方法反映信息,看看答案對這個職位: Get a generic method without using GetMethods
public static class Helper
{
public static IEnumerable<T> BuildOrderBys<T>(
this IEnumerable<T> source,
params SortDescription[] properties)
{
if (properties == null || properties.Length == 0) return source;
var typeOfT = typeof (T);
Type t = typeOfT;
IOrderedEnumerable<T> result = null;
var thenBy = false;
foreach (var item in properties
.Select(prop => new {PropertyInfo = t.GetProperty(prop.PropertyName), prop.Direction}))
{
var oExpr = Expression.Parameter(typeOfT, "o");
var propertyInfo = item.PropertyInfo;
var propertyType = propertyInfo.PropertyType;
var isAscending = item.Direction == ListSortDirection.Ascending;
if (thenBy)
{
var prevExpr = Expression.Parameter(typeof (IOrderedEnumerable<T>), "prevExpr");
var expr1 = Expression.Lambda<Func<IOrderedEnumerable<T>, IOrderedEnumerable<T>>>(
Expression.Call(
(isAscending ? thenByMethod : thenByDescendingMethod).MakeGenericMethod(typeOfT, propertyType),
prevExpr,
Expression.Lambda(
typeof (Func<,>).MakeGenericType(typeOfT, propertyType),
Expression.MakeMemberAccess(oExpr, propertyInfo),
oExpr)
),
prevExpr)
.Compile();
result = expr1(result);
}
else
{
var prevExpr = Expression.Parameter(typeof (IEnumerable<T>), "prevExpr");
var expr1 = Expression.Lambda<Func<IEnumerable<T>, IOrderedEnumerable<T>>>(
Expression.Call(
(isAscending ? orderByMethod : orderByDescendingMethod).MakeGenericMethod(typeOfT, propertyType),
prevExpr,
Expression.Lambda(
typeof (Func<,>).MakeGenericType(typeOfT, propertyType),
Expression.MakeMemberAccess(oExpr, propertyInfo),
oExpr)
),
prevExpr)
.Compile();
result = expr1(source);
thenBy = true;
}
}
return result;
}
private static MethodInfo orderByMethod =
MethodOf(() => Enumerable.OrderBy(default(IEnumerable<object>), default(Func<object, object>)))
.GetGenericMethodDefinition();
private static MethodInfo orderByDescendingMethod =
MethodOf(() => Enumerable.OrderByDescending(default(IEnumerable<object>), default(Func<object, object>)))
.GetGenericMethodDefinition();
private static MethodInfo thenByMethod =
MethodOf(() => Enumerable.ThenBy(default(IOrderedEnumerable<object>), default(Func<object, object>)))
.GetGenericMethodDefinition();
private static MethodInfo thenByDescendingMethod =
MethodOf(() => Enumerable.ThenByDescending(default(IOrderedEnumerable<object>), default(Func<object, object>)))
.GetGenericMethodDefinition();
public static MethodInfo MethodOf<T>(Expression<Func<T>> method)
{
MethodCallExpression mce = (MethodCallExpression) method.Body;
MethodInfo mi = mce.Method;
return mi;
}
}
public static class Sample
{
private static void Main()
{
var data = new List<Customer>
{
new Customer {ID = 3, Name = "a"},
new Customer {ID = 3, Name = "c"},
new Customer {ID = 4},
new Customer {ID = 3, Name = "b"},
new Customer {ID = 2}
};
var result = data.BuildOrderBys(
new SortDescription("ID", ListSortDirection.Ascending),
new SortDescription("Name", ListSortDirection.Ascending)
).Dump();
}
}
public class Customer
{
public int ID { get; set; }
public string Name { get; set; }
}
樣品的結果如圖LinqPad
您可以使用這樣的事情:
var query = _list.OrderBy(x=>x.prop1);
if (shouldOrderByProp2Too)
query = query.ThenBy(x=>x.prop2);
if (shouldOrderByProp3Too)
query = query.ThenBy(x=>x.prop3);
// ...
// then use query the way you had your code
的評論: 在這種情況下,我會去工具在你的列表中的對象IComparable
,然後就來排序/或使用Compareres動態檢查爲此 - 我能想到的唯一的其他事情就是用反射和動態調用來做到這一點...不是你想做的事情,如果不是真的需要的話)
感謝您的回答,但我更希望有一種方法可用於任何N個屬性,如果可能的話。 – 2012-03-12 07:26:13
我不知道如何通過反射來添加訂單(太懶了),但這裏是僞代碼的基本概念:
var query = list.OrderBy(properties.First());
bool first = true;
foreach(var property in properties.Skip(1))
{
query = query.ThenBy(property);
}
請參閱:http://stackoverflow.com/a/233505/861716 – 2012-03-12 09:54:36