关于如何在linq中优化字符串排序代码的建议(Suggestions on how to optimize code for ordering by string in linq)

编程入门 行业动态 更新时间:2024-10-24 08:31:53
关于如何在linq中优化字符串排序代码的建议(Suggestions on how to optimize code for ordering by string in linq)

我正在为WebGrid编写一个IQueryable友好替代品,我在我必须通过作为字符串传递的列名来订购结果的部分停了下来。 我设法实现了我的目标,但我不喜欢生成的代码所以我希望有人可以给我一个提示如何改进它。

我为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); }

这实际上有效,但所有这些重复看起来都不太好。 有没有办法改进这段代码?

I was writing a IQueryable friendly replacement for WebGrid and I came to a halt around the part where I have to order the results by column name passed as a string. I managed to achieve my goal, but I don't like the resulting code so I hoped that someone could give me a hint how to improve it.

I wrote an extension for IQueryable for ordering by string based on what I found here, however it did not work at first and was giving me an error that said (more or less) that Int32 cannot be converted to Object (at this point I was testing ordering by column name with a column of ids, that's why the error said Int32). The problematic line:

var mySortExpression = Expression.Lambda<Func<T, object>>(Expression.Property(param, columnName), param);

I've added a conversion based on what can be found at this page, but that didn't work either and I got an error that said that I cannot order by object class. Here is how it looked at this point:

var mySortExpression = Expression.Lambda<Func<T, object>>(Expression.Convert(Expression.Property(param, columnName), type), param);

So I figured out that I need to provide a sortable type in this line:

var mySortExpression = Expression.Lambda<Func<T, type>>(Expression.Property(param, columnName), param);

And rewritten the whole thing as follows:

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); }

This actually works, but all those repetitions don't look too good. Is there any way to improve this code?

最满意答案

正如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的更改包括用source.ElementType替换typeof(T) 。

As suggested by Raphaël Althaus I solved the problem by using code from https://stackoverflow.com/a/233505/2123652, but I applied a small change to allow it to handle interfaces properly. The result code looks like this:

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; }

The change in colde involved replacing typeof(T) with source.ElementType.

更多推荐

本文发布于:2023-07-23 12:01:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1231640.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:字符串   代码   建议   如何在   ordering

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!