按属性名称(字符串值)排序列表? [复制]
Posted
技术标签:
【中文标题】按属性名称(字符串值)排序列表? [复制]【英文标题】:Order a list by a property name(string value)? [duplicate] 【发布时间】:2014-10-30 06:15:43 【问题描述】:我有一个object
s 的列表。如何使用属性名称订购此列表?
string orderbyField = "Code";
List<object> l = FillList();
l = l.OrderBy(o => orderbyField);
我可以为这个问题提供扩展程序吗?
【问题讨论】:
能否提供你FillList的完整代码sn-p 关注的是你有 object 的列表而不是特定的类,所以你如何确保列表中的所有对象都具有名为“代码”的属性.. 更好创建特定类型的列表..或具有多种类型使用接口类型列表 我没有特定的类型。 FillList 返回一个 LINQ 实体对象。 s.t 像 dc.Employer。我将此列表用作 MVC.NET 中自定义网格的数据源。 如果您没有特定类型,这意味着您无法确保该对象具有 Code 属性。那么创建此 OrderBy 没有意义b> LINQ 但我在运行时(动态)知道属性名称。例如,单击网格上的代码标题,我从对象中获取“代码”属性。如果有办法做出这样的事情:list.OrderBy(o => o.GetType().GetProperty("Code"); 【参考方案1】:如果您不必以字符串形式提供属性名称,使用dynamic
非常简单:
List<object> l = FillList();
l = l.OrderBy(o => ((dynamic)o).Id);
如果属性名称必须是一个字符串,那么它会变得有点复杂,但可以使用反射来完成(虽然它不是很有效):
l = l.OrderBy(o => o.GetType()
.GetProperty("Code")
.GetValue(o, null));
您还应该考虑添加一些错误处理,例如如果该属性不存在。
此外,如果列表中的所有元素都具有相同的 runtime 类型,那么使用表达式树编译 getter 函数并重用它(而不是直接使用反射)会更有效。
public static Func<object, object> CreateGetter(Type runtimeType, string propertyName)
var propertyInfo = runtimeType.GetProperty(propertyName);
// create a parameter (object obj)
var obj = Expression.Parameter(typeof(object), "obj");
// cast obj to runtimeType
var objT = Expression.TypeAs(obj, runtimeType);
// property accessor
var property = Expression.Property(objT, propertyInfo);
var convert = Expression.TypeAs(property, typeof(object));
return (Func<object, object>)Expression.Lambda(convert, obj).Compile();
并像这样使用它:
var codeGetter = CreateGetter(l[0].GetType(), "Code"); // using the 1st element as an example
l = l.OrderBy(o => codeGetter(o));
【讨论】:
【参考方案2】:按属性名排序,没有类型反射
public static class IQueryableExtensions
public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string
propertyName)
return (IQueryable<T>)OrderBy((IQueryable)source, propertyName);
public static IQueryable OrderBy(this IQueryable source, string propertyName)
var x = Expression.Parameter(source.ElementType, "x");
var body = propertyName.Split('.').Aggregate<string, Expression>(x,
Expression.PropertyOrField);
var selector = Expression.Lambda
(Expression.PropertyOrField(x, propertyName), x);
return source.Provider.CreateQuery(
Expression.Call(typeof(Queryable), "OrderBy", new Type[]
source.ElementType, selector.Body.Type ,
source.Expression, selector
));
public static IQueryable<T> OrderByDescending<T>(this IQueryable<T> source,
string propertyName)
return (IQueryable<T>)OrderByDescending((IQueryable)source, propertyName);
public static IQueryable OrderByDescending(this IQueryable source, string
propertyName)
var x = Expression.Parameter(source.ElementType, "x");
var selector = Expression.Lambda(Expression.PropertyOrField(x,
propertyName),x);
return source.Provider.CreateQuery(
Expression.Call(typeof(Queryable), "OrderByDescending", new Type[]
source.ElementType, selector.Body.Type ,
source.Expression, selector
));
【讨论】:
相当不错。很不错。【参考方案3】: public static IEnumerable<TSource> ComplexOrderBy<TSource>(this IEnumerable<TSource> source, string orderString)
if (string.IsNullOrWhiteSpace(orderString))
return source;
IOrderedEnumerable<TSource> orderedQuery = null;
var sortingFields = orderString.Split(new[] "," , StringSplitOptions.RemoveEmptyEntries);
var propertyNames = typeof(TSource).GetProperties().Select(prop => prop.Name.ToLower()).ToImmutableHashSet();
for (var i = 0; i < sortingFields.Length; i++)
var sortingSet = sortingFields[i].Split(new[] " " , StringSplitOptions.RemoveEmptyEntries);
var sortBy = sortingSet[0].ToLower();
var isDescending = sortingSet.Length > 1 && sortingSet[1].Trim().ToLower() == "desc";
try
var propertySelector = sortBy.GetPropertySelector<TSource>();
orderedQuery = isDescending
?
(i == 0 ? source.OrderByDescending(propertySelector.Compile()) : orderedQuery.OrderByDescending(propertySelector.Compile()).ThenByDescending(propertySelector.Compile()))
:
(i == 0 ? source.OrderBy(propertySelector.Compile()) : orderedQuery.ThenBy(propertySelector.Compile()));
// Just ignoring illegal properties for simplicity
catch (ArgumentNullException)
catch (ArgumentException)
return orderedQuery ?? source;
public static Expression<Func<T, object>> GetPropertySelector<T>(this string propertyName)
var parameterExpression = Expression.Parameter(typeof(T), "x");
Expression body = parameterExpression;
foreach (var member in propertyName.Split('.'))
body = Expression.Property(body, member);
return Expression.Lambda<Func<T, object>>(Expression.Convert(body, typeof(object)), parameterExpression);
【讨论】:
“GetPropertySelector”对我来说并不熟悉。也是自定义代码? @antal-istván 感谢您指出这一点 :) 我添加了我错过的简短自定义方法以上是关于按属性名称(字符串值)排序列表? [复制]的主要内容,如果未能解决你的问题,请参考以下文章