当我将属性名称作为字符串时,对C#中的属性进行编码的最简单方法是什么?例如,我想允许用户通过他们选择的属性(使用LINQ)来订购一些搜索结果.他们将在UI中选择"order by"属性 - 当然是字符串值.有没有办法直接使用该字符串作为linq查询的属性,而不必使用条件逻辑(if/else,switch)将字符串映射到属性.反射?
从逻辑上讲,这就是我想做的事情:
query = query.OrderBy(x => x."ProductId");
更新:我最初没有指定我正在使用Linq to Entities - 看起来反射(至少GetProperty,GetValue方法)不会转换为L2E.
我会提供其他人发布的替代方案.
System.Reflection.PropertyInfo prop = typeof(YourType).GetProperty("PropertyName"); query = query.OrderBy(x => prop.GetValue(x, null));
这避免了重复调用反射API以获取属性.现在唯一重复的调用是获取值.
然而
我建议使用PropertyDescriptor
替代,因为这将允许将自定义TypeDescriptor
s分配给您的类型,从而可以使用轻量级操作来检索属性和值.在没有自定义描述符的情况下,它无论如何都会回归到反射.
PropertyDescriptor prop = TypeDescriptor.GetProperties(typeof(YourType)).Find("PropertyName"); query = query.OrderBy(x => prop.GetValue(x));
至于加快速度,请查看Marc Gravel HyperDescriptor
在CodeProject上的项目.我用它取得了巨大的成功; 它可以为业务对象的高性能数据绑定和动态属性操作提供生命保护.
我有点迟到了,但是,我希望这会有所帮助.
使用反射的问题在于,除了内部.Net提供程序之外,任何Linq提供程序几乎肯定不会支持生成的表达式树.这适用于内部集合,但是在分页之前在源(在SQL,MongoDb等)进行排序时,这将不起作用.
下面的代码示例为OrderBy和OrderByDescending提供了IQueryable扩展方法,可以这样使用:
query = query.OrderBy("ProductId");
扩展方法:
public static class IQueryableExtensions { public static IOrderedQueryableOrderBy (this IQueryable source, string propertyName) { return source.OrderBy(ToLambda (propertyName)); } public static IOrderedQueryable OrderByDescending (this IQueryable source, string propertyName) { return source.OrderByDescending(ToLambda (propertyName)); } private static Expression > ToLambda (string propertyName) { var parameter = Expression.Parameter(typeof(T)); var property = Expression.Property(parameter, propertyName); var propAsObject = Expression.Convert(property, typeof(object)); return Expression.Lambda >(propAsObject, parameter); } }
问候,马克.
我喜欢@Mark Powell的答案,但正如@ShuberFu所说,它给出了错误LINQ to Entities only supports casting EDM primitive or enumeration types
.
删除var propAsObject = Expression.Convert(property, typeof(object));
不适用于值类型的属性,例如整数,因为它不会隐式地将int封装到对象.
使用Kristofer Andersson和Marc Gravell的想法我找到了一种使用属性名构造Queryable函数的方法,并且它仍然可以使用Entity Framework.我还包括一个可选的IComparer参数.警告: IComparer参数不适用于Entity Framework,如果使用Linq to Sql,则应该省略它.
以下适用于Entity Framework和Linq to Sql:
query = query.OrderBy("ProductId");
而@Simon Scheurer这也有效:
query = query.OrderBy("ProductCategory.CategoryId");
如果你没有使用Entity Framework或Linq to Sql,这可行:
query = query.OrderBy("ProductCategory", comparer);
这是代码:
public static class IQueryableExtensions { public static IOrderedQueryableOrderBy (this IQueryable query, string propertyName, IComparer
是的,我认为除了反思之外还有另一种方式.
例:
query = query.OrderBy(x => x.GetType().GetProperty("ProductId").GetValue(x, null));
query = query.OrderBy(x => x.GetType().GetProperty("ProductId").GetValue(x, null));
试图回忆起我的头脑中的确切语法,但我认为这是正确的.