我有一组CLR对象。该对象的类定义有三个属性:FirstName,LastName,BirthDate。
我有一个字符串,它反映了集合应按其排序的属性的名称。另外,我有一个排序方向。如何将此排序信息动态应用于我的收藏?请注意,排序可以是多层的,例如我可以按LastName排序,然后按FirstName排序。
目前,我正在尝试以下运气:
var results = myCollection.OrderBy(sortProperty);
但是,我收到的消息是:
...不包含'OrderBy'的定义,并且最好的扩展方法重载......有一些无效的参数。
答案 0 :(得分:10)
好吧,我在评论中与SLaks的争论迫使我想出一个答案:)
我假设你只需要支持LINQ to Objects。这里有一些代码需要大量的验证添加,但确实有效:
// We want the overload which doesn't take an EqualityComparer.
private static MethodInfo OrderByMethod = typeof(Enumerable)
.GetMethods(BindingFlags.Public | BindingFlags.Static)
.Where(method => method.Name == "OrderBy"
&& method.GetParameters().Length == 2)
.Single();
public static IOrderedEnumerable<TSource> OrderByProperty<TSource>(
this IEnumerable<TSource> source,
string propertyName)
{
// TODO: Lots of validation :)
PropertyInfo property = typeof(TSource).GetProperty(propertyName);
MethodInfo getter = property.GetGetMethod();
Type propType = property.PropertyType;
Type funcType = typeof(Func<,>).MakeGenericType(typeof(TSource), propType);
Delegate func = Delegate.CreateDelegate(funcType, getter);
MethodInfo constructedMethod = OrderByMethod.MakeGenericMethod(
typeof(TSource), propType);
return (IOrderedEnumerable<TSource>) constructedMethod.Invoke(null,
new object[] { source, func });
}
测试代码:
string[] foo = new string[] { "Jon", "Holly", "Tom", "William", "Robin" };
foreach (string x in foo.OrderByProperty("Length"))
{
Console.WriteLine(x);
}
输出:
Jon
Tom
Holly
Robin
William
它甚至会返回IOrderedEnumerable<TSource>
,因此您可以正常链接ThenBy
子句:)
答案 1 :(得分:7)
您需要构建Expression Tree并将其传递给OrderBy
它看起来像这样:
var param = Expression.Parameter(typeof(MyClass));
var expression = Expression.Lambda<Func<MyClass, PropertyType>>(
Expression.Property(param, sortProperty),
param
);
或者,您可以使用Dynamic LINQ,这将允许您的代码按原样运行。
答案 2 :(得分:1)
protected void sort_grd(object sender, GridViewSortEventArgs e)
{
if (Convert.ToBoolean(ViewState["order"]) == true)
{
ViewState["order"] = false;
}
else
{
ViewState["order"] = true;
}
ViewState["SortExp"] = e.SortExpression;
dataBind(Convert.ToBoolean(ViewState["order"]), e.SortExpression);
}
public void dataBind(bool ord, string SortExp)
{
var db = new DataClasses1DataContext(); //linq to sql class
var Name = from Ban in db.tbl_Names.AsEnumerable()
select new
{
First_Name = Ban.Banner_Name,
Last_Name = Ban.Banner_Project
};
if (ord)
{
Name = BannerName.OrderBy(q => q.GetType().GetProperty(SortExp).GetValue(q, null));
}
else
{
Name = BannerName.OrderByDescending(q => q.GetType().GetProperty(SortExp).GetValue(q, null));
}
grdSelectColumn.DataSource = Name ;
grdSelectColumn.DataBind();
}
答案 3 :(得分:0)
你可以用Linq
来做到这一点var results = from c in myCollection
orderby c.SortProperty
select c;
答案 4 :(得分:0)
对于这种动态的工作,我一直在使用Dynamic LINQ库,这使得这类事情变得简单:
答案 5 :(得分:0)
对于动态排序,您可以评估字符串,例如
List<MyObject> foo = new List<MyObject>();
string sortProperty = "LastName";
var result = foo.OrderBy(x =>
{
if (sortProperty == "LastName")
return x.LastName;
else
return x.FirstName;
});
有关更通用的解决方案,请参阅此SO主题:Strongly typed dynamic Linq sorting
答案 6 :(得分:0)
您需要使用反射来获取PropertyInfo,然后使用它来构建表达式树。像这样:
var entityType = typeof(TEntity);
var prop = entityType.GetProperty(sortProperty);
var param = Expression.Parameter(entityType, "x");
var access = Expression.Lambda(Expression.MakeMemberAccess(param, prop), param);
var ordered = (IOrderedQueryable<TEntity>) Queryable.OrderBy(
myCollection,
(dynamic) access);
答案 7 :(得分:0)
您可以复制粘贴我在该答案中发布的方法,并更改签名/方法名称: How to make the position of a LINQ Query SELECT variable
答案 8 :(得分:0)
您实际上可以使用原始代码行
var results = myCollection.OrderBy(sortProperty);
只需使用System.Linq.Dynamic库。
如果您遇到编译器错误(无法转换或不包含定义......),您可能必须这样做:
var results = myCollection.AsQueryable().OrderBy(sortProperty);
不需要任何表达式树或数据绑定。