动态Orderby函数
本文关键字:函数 Orderby 动态 | 更新日期: 2023-09-27 18:21:21
在我的"Invoice"类中,它有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;
}
在我提出这个问题之前,我提到了这个帖子。输入考虑的两个问题相同,但产出不同。我尝试使用该解决方案并四处玩耍,但无法解决我的具体问题。在我的情况下,我正在调用第三方API(Xeroapi),我想专门构建这个输出。
排序时,必须返回属性值,而不是类型或自身属性
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();
您可以将对象传递给反射函数并返回适当的属性,如下所示:
.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();
Grundy在评论中建议使用dynamic LINQ
可能是更好的解决方案。
您可能还希望能够在排序方向(升序、降序)之间切换。这会给你带来另一个问题。通过一些小的改变,您应该能够根据这个答案调整您的解决方案。
使用方法非常简单,只需在集合上调用Extension方法OrderBy<T>
即可。这也是您要查找的代码块所在的位置。
您可以在字典中进行简单的查找,而不是进行反射。
static readonly Dictionary<string, Func<Invoice, decimal>> keySelectors = ...;
在启动时(或使用Lazy),您初始化所有密钥选择器:
keySelectors.Add("AmountDue", a=> a.AmountDue);
// add all 20 options here
现在,每次你需要一个,它只是一个快速的字典查找。
优点:
- 将用于连接UI和业务逻辑的字符串与字段名解耦,从而可以安全地重构它们
- 团队中的其他开发人员很容易理解和维护