[英]Suggestions on how to optimize code for ordering by string in linq
我當時正在編寫一個IQueryable友好的WebGrid替代品,但由於必須按字符串形式傳遞的列名來對結果進行排序,因此我停了下來。 我設法實現了我的目標,但是我不喜歡所得到的代碼,所以我希望有人可以給我提示如何改進它。
我為IQueryable編寫了一個擴展程序,用於根據在這里找到的內容按字符串排序,但是起初它不起作用,並且給了我一個錯誤,該錯誤表明(或多或少)Int32無法轉換為Object(此時我已經按列名和ID列測試排序,這就是為什么錯誤顯示為Int32)。 有問題的行:
var mySortExpression = Expression.Lambda<Func<T, object>>(Expression.Property(param, columnName), param);
我已經基於此頁面上的內容添加了一個轉換,但是那也不起作用,並且我收到一條錯誤消息,提示我無法按對象類進行排序。 這是它現在的樣子:
var mySortExpression = Expression.Lambda<Func<T, object>>(Expression.Convert(Expression.Property(param, columnName), type), param);
所以我發現我需要在這一行中提供一個可排序的類型:
var mySortExpression = Expression.Lambda<Func<T, type>>(Expression.Property(param, columnName), param);
並將整個內容重寫如下:
public static IQueryable<T> OrderByString<T>(this IQueryable<T> query, string columnName)
{
var elementType = typeof(T);
var param = Expression.Parameter(elementType, "x");
var prop = elementType.GetProperty(columnName);
Type type = Nullable.GetUnderlyingType(prop.PropertyType);
if (type == null)
{
type = prop.PropertyType;
}
if (type.Equals(typeof(string)))
{
var mySortExpression = Expression.Lambda<Func<T, string>>(Expression.Property(param, columnName), param);
return query.OrderBy(mySortExpression);
}
if (type.Equals(typeof(char)))
{
var mySortExpression = Expression.Lambda<Func<T, char>>(Expression.Property(param, columnName), param);
return query.OrderBy(mySortExpression);
}
if (type.Equals(typeof(int)))
{
var mySortExpression = Expression.Lambda<Func<T, int>>(Expression.Property(param, columnName), param);
return query.OrderBy(mySortExpression);
}
if (type.Equals(typeof(float)) || type.Equals(typeof(double)))
{
var mySortExpression = Expression.Lambda<Func<T, double>>(Expression.Property(param, columnName), param);
return query.OrderBy(mySortExpression);
}
// This last part won't work but I left it so that it can compile (all routes need to return value etc.)
var mySortExpression1 = Expression.Lambda<Func<T, object>>(Expression.Convert(Expression.Property(param, columnName), type), param);
return query.OrderBy(mySortExpression1);
}
這實際上有效,但是所有這些重復看起來都不太好。 有什么辦法可以改善此代碼?
正如RaphaëlAlthaus所建議的那樣,我使用https://stackoverflow.com/a/233505/2123652的代碼解決了該問題,但我進行了一些小的更改以使其能夠正確處理接口。 結果代碼如下所示:
public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string property)
{
return ApplyOrder<T>(source, property, "OrderBy");
}
public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> source, string property)
{
return ApplyOrder<T>(source, property, "OrderByDescending");
}
public static IOrderedQueryable<T> ThenBy<T>(this IOrderedQueryable<T> source, string property)
{
return ApplyOrder<T>(source, property, "ThenBy");
}
public static IOrderedQueryable<T> ThenByDescending<T>(this IOrderedQueryable<T> source, string property)
{
return ApplyOrder<T>(source, property, "ThenByDescending");
}
static IOrderedQueryable<T> ApplyOrder<T>(IQueryable<T> source, string property, string methodName) {
string[] props = property.Split('.');
Type elementType = source.ElementType;
Type type = elementType;
ParameterExpression arg = Expression.Parameter(type, "x");
Expression expr = arg;
foreach(string prop in props) {
// use reflection (not ComponentModel) to mirror LINQ
PropertyInfo pi = type.GetProperty(prop);
expr = Expression.Property(expr, pi);
type = pi.PropertyType;
}
Type delegateType = typeof(Func<,>).MakeGenericType(elementType, type);
LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);
object result = typeof(Queryable).GetMethods().Single(
method => method.Name == methodName
&& method.IsGenericMethodDefinition
&& method.GetGenericArguments().Length == 2
&& method.GetParameters().Length == 2)
.MakeGenericMethod(elementType, type)
.Invoke(null, new object[] {source, lambda});
return (IOrderedQueryable<T>)result;
}
在colde變化涉及取代typeof(T)
與source.ElementType
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.