using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Web.UI.WebControls;
using dynamic = System.Linq.Dynamic;
using System.Linq.Expressions;
namespace Project.Lib.Extensions
{
public static partial class Utils
{
public static List<T> SortForMe<T>(this List<T> list, string propertyName,SortDirection sortDirection)
{
string exp1 = string.Format("model.{0}", propertyName);
var p1 = Expression.Parameter(typeof(T), "model");
var e1 = dynamic.DynamicExpression.ParseLambda(new[] { p1 }, null, exp1);
if (e1 != null)
{
if (sortDirection==SortDirection.Ascending)
{
var result = list.OrderBy((Func<T, object>)e1.Compile()).ToList();
return result;
}
else
{
var result = list.OrderByDescending((Func<T, object>)e1.Compile()).ToList();
return result;
}
}
return list;
}
}
}
我正在使用此代码按propertyName对我的通用列表进行排序。当属性类型为string
时,此代码会成功运行,但当类型为long
或int
时,我会收到此异常:
无法投射类型的对象 'System.Func`2 [Project.Lib.Model.UserQueryCount,System.Int64]'键入 'System.Func`2 [Project.Lib.Model.UserQueryCount,System.Object的]'。
var result = list.OrderBy((Func<T, dyamic>)e1.Compile()).ToList();
在上面一行中,我决定使用dynamic
,但又获得了异常。我该怎么办?
我改变了我的方法:
public static List<TModel> SortForMe<TModel>(this List<TModel> list, string propertyName,SortDirection sortDirection) where TModel:class
{
var ins = Activator.CreateInstance<TModel>();
var prop= ins.GetType().GetProperty(propertyName);
var propertyType = prop.PropertyType;
string exp1 = string.Format("model.{0}", propertyName);
var p1 = System.Linq.Expressions.Expression.Parameter(typeof(TModel), "model");
var e1 = System.Linq.Dynamic.DynamicExpression.ParseLambda(new[] { p1 }, null, exp1);
if (e1 != null)
{
if (sortDirection==SortDirection.Ascending)
{
return list.OrderBy((Func<TModel, propertyType>)e1.Compile()).ToList();
}
return list.OrderByDescending((Func<TModel, propertyType>)e1.Compile()).ToList();
}
return list;
}
我使用反射获得了propertyType但在Func中我不能像这样使用它:"Func<TModel, propertyType>"
有没有办法解决这个问题
感谢您的帮助。
答案 0 :(得分:1)
它不起作用的原因确实是拳击,如另一个答案所述。
class S
{
public int f;
public S s;
}
{
Func<S, S> sGetter = s => s.s; // okay
Func<S, object> objectGetter = s => s.s; // okay
objectGetter = sGetter; // also okay
}
{
Func<S, int> intGetter = s => s.f; // okay
Func<S, object> objectGetter = s => s.f; // still okay
objectGetter = intGetter; // not okay
}
Func<S, object> objectGetter = s => s.f
工作但最后一个赋值不起作用的原因是它实际上被解释为Func<S, object> objectGetter = s => (object)s.f
,并且该强制转换执行实际操作。 intGetter
和objectGetter
不会做同样的事情,因此不能将其重新解释为另一个。意识到这一点,如果你自己包括那个演员,你应该没问题。据我所知,如果您只是指定所需的返回类型为object
,那么DQL(您正在使用的,对吗?)会为您做到这一点:
var e1 = DynamicExpression.ParseLambda(new[] { p1 }, typeof(object), exp1);
答案 1 :(得分:0)
我怀疑这与拳击类型有关,但我不能确定。但是,有一种解决方法,不涉及装箱,两者都解决了您的问题,使您的方法更容易使用。
您可以实际使用返回该属性的lambda表达式,而不是标识要排序的属性的字符串。这可以通过以下方法完成:
private static string GetPropertyName<TObject, TProperty>(Expression<Func<TObject, TProperty>> property)
{
MemberExpression memberExpression = (MemberExpression)property.Body;
PropertyInfo propertyInfo = (PropertyInfo)memberExpression.Member;
return propertyInfo.Name;
}
请注意,我已将Func
委托包装到Expression
类型中(您可能希望read more关于它)。这样,我可以查询表达式并找出它使用的成员。当然,除了简单的x => x.Property
lambdas之外,所有这些都会失败,所以你可能想要做一些错误检查。
要使用它,您必须稍微更改一下扩展方法:
public static List<TObject> SortForMe<TObject, TProperty>(
this List<TObject> list,
Expression<Func<TObject, TProperty>> property,
SortDirection sortDirection)
{
string propertyName = GetPropertyName(property);
...
...
// when casting compiled expression to Func, instead of object, use TProperty
// that way, you will avoid boxing
var result = list.OrderBy((Func<T, TProperty>)e1.Compile()).ToList();
...
...
}
实际使用情况如下:
List<Foo> foos = ... ;
foos.SortForMe(x => x.IntegerProperty, SortDirection.Ascending);
foos.SortForMe(x => x.StringProperty, SortDirection.Ascending);
IntegerProperty
和StringProperty
是在Foo
类型上定义的实际属性。使用该方法时无需指定实际的类型参数 - C#的类型推断在这里发挥得非常好。