簡體   English   中英

關於如何優化linq中按字符串排序的代碼的建議

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM