在我的"发票"它有20多个字段,我需要支持对所有字段进行排序。
我有一个接受属性字符串的方法(例如" AmountDue")。现在我需要OrderBy AmoundDue字段。
我的具体要求是,传递一个属性名称字符串值,我想返回一个像
这样的函数 Func<Invoice, decimal> keySelector = a=> a.AmountDue
;
动态构建整个表达式。
我可以使用keySelector
进行排序
_api.Invoices.Find().Where(c => c.Contact.Id == contactId).OrderBy(keySelector).ToList();
到目前为止,我能够使用字符串值识别类型。需要一些帮助来返回一个函数。
public static Type VariableType(string prop)
{
Type type = typeof(TResource);
PropertyInfo pi = type.GetProperty(prop, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
type = pi.PropertyType;
return type;
}
在发布此问题之前,我提到this post。输入是 两个问题都是相同的,但输出是不同的。一世 试图使用该解决方案并玩弄,但无法解决我的问题 具体问题。就我而言,我正在调用第三方API(Xero api)我想专门构建这个输出。
答案 0 :(得分:2)
排序时,您必须返回属性值,而不是类型或属性本身
String propertyName = "AmountDue";
var result = _context
.Invoices
.Find()
.Where(c => c.Contact.Id == contactId)
.OrderBy(item => typeof(Invoice).GetProperty(
propertyName,
BindingFlags.Public | BindingFlags.Instance)
.GetValue(item))
.ToList();
答案 1 :(得分:1)
您可以将对象传递给反射函数并返回相应的属性,如下所示:
.OrderBy(o => keySelector(o, propertyName))
public static Type VariableType(object o, string prop)
{
Type type = typeof(TResource);
PropertyInfo pi = type.GetProperty(prop, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
return pi.GetValue(o);
}
但我不认为这会对IQueryable
起作用,因为它无法将函数转换为SQL。因此,您必须先执行查询(例如使用ToList()
)
_context.Invoices.Find().Where(c => c.Contact.Id == contactId).ToList().OrderBy(o => keySelector(o, propertyName)).ToList();
使用dynamic LINQ
作为Grundy在评论中建议可能是更好的解决方案。
答案 2 :(得分:0)
您可能还希望能够在排序方向(升序,降序)之间切换。这会带给你另一个问题。通过一些小的更改,您应该能够从this answer调整您的解决方案。
然后使用非常简单,只需在您的集合上调用Extension方法OrderBy<T>
即可。这也是您正在寻找的代码片段。
答案 3 :(得分:0)
而不是反射,你可以在字典中进行简单的查找。
static readonly Dictionary<string, Func<Invoice, decimal>> keySelectors = ...;
启动时(或使用Lazy)初始化所有keySelectors:
keySelectors.Add("AmountDue", a=> a.AmountDue);
// add all 20 options here
现在每次你需要它时,它只是一个快速的字典查找。
优点: