c# - 如何使用 C# 表达式 API 使对象列表成为 Lamba 中的参数
问题描述
我正在尝试动态创建一个谓词以传递给 linq where 子句。这是一个通用方法,它接受两个相同类型的列表和属性名称列表进行比较。
void SomeMethod<T>(List<T> oldRecords, List<T> newRecords, List<string> propertiesOfT)
{
// dynamically build predicate for this
var notMatch = oldRecords.Where(o => !newRecords.Any(n => n.Prop1 == o.Prop1 && n.Prop2 == o.Prop2)).ToList();
// do somethind with notMatch
}
我想转换这个:
var notMatch = oldRecords.Where(o => !newRecords.Any(n => n.Prop1 == o.Prop1 && n.Prop2 == o.Prop2)).ToList();
为达到这个:
var predicate = "n => n.Prop1 == o.Prop1 && n.Prop2 == o.Prop2"; // sudo code
var notMatch = oldRecords.Where(o => !newRecords.Any(predicate));
或这个
var predicate = "o => !newRecords.Any(n => n.Prop1 == o.Prop1 && n.Prop2 == o.Prop2)" // sudo code
var notMatch = oldRecords.Where(predicate);
动态创建表达式时如何填充 newRecords?以及如何在表达式中引用参数 o 和参数 n。
我已经做到了这一点:
//construct the two parameters
var o = Expression.Parameter(typeof(T), "o");
var n = Expression.Parameter(typeof(T), "n");
// How to I go about populating o with values and n with values
// from oldRecords and newRecords? or is that no neccessary
var property = Expression.Property(o, typeof(T).GetProperty("Id").Name);
var value = Expression.Constant(Convert.ChangeType("12345", typeof(T).GetProperty("Id").PropertyType), typeof(T).GetProperty("Id").PropertyType);
BinaryExpression binaryExpression = Expression.MakeBinary(ExpressionType.Equal, property, value);
任何 sudo 代码或线索在哪里寻找实现这一目标?
解决方案
有了反射,这很容易。你只需要考虑一下。这是工作版本。
void SomeMethod<T>(List<T> oldRecords, List<T> newRecords, List<string> propertiesOfT)
{
// get the list of property to match
var properties = propertiesOfT.Select(prop => typeof(T).GetProperty(prop)).ToList();
// Get all old record where we don't find any matching new record where all the property equal that old record
var notMatch = oldRecords.Where(o => !newRecords.Any(n => properties.All(prop => prop.GetValue(o).Equals(prop.GetValue(n))))).ToList();
}
这是我尝试过的样本集,它有效
public class test
{
public int id { get; set; } = 0;
public string desc { get; set; } = "";
public test(string s, int i)
{
desc = s;id = i;
}
}
private void Main()
{
var oldRecords = new List<test>()
{
new test("test",1),
new test("test",2)
};
var newRecords = new List<test>()
{
new test("test1",1),
new test("test",2)
};
SomeMethod(oldRecords, newRecords, new List<string>() { "id", "desc" });
}
推荐阅读
- npm - 如何忽略 npm 运行错误并继续使用 Travis-CI?
- python - 列出 HDFS 文件时出现分段错误 11
- go - 是否可以在 POD 运行时替换容器中的可执行文件?
- excel - 向列添加值会增加运行时间是否有原因?
- python - 根据距离和出现频率选择一个项目(从一组项目中)
- r - 如何在子列表上使用“lapply”(r)
- python-3.x - Rasa Core - 无法访问操作模板名称,因为该名称不是该域的注册操作
- python - 如何在 DRF 中组合/混合对象级别和用户级别权限?
- c - C - 错误:“struct name_s”类型的定义不完整
- docker - 如何使用 ansible 删除过时的容器?