动态 属性 + Linq

Dynamic property + Linq

我有一个对象列表。我有一个过滤器值列表。我需要一个对象列表的计数,其中 field/property(在 运行 时通过变量指定)具有在过滤器列表中找到的值。顺便说一句,还有其他“过滤”属性,但这些 属性 名称是“固定的”,因此在构建时已知。

假设过滤器列表具有以下值:

橙色、黄色、蓝色

假设对象列表具有以下 properties/values:

Name: Bike, Color: Red |
Name: Car, Color: Green |
Name: Box, Color: Yellow |
Name: Door, Color: Orange |

“过滤字段”是在 运行 时定义为“颜色”的字符串变量 property/field。

结果应该是 2(盒子和门),因为列表中的其他对象没有在过滤器列表中找到的“颜色”。

这是我所拥有的并且它有效,但我正在寻找一种在 运行 时间动态指定“过滤字段”属性 名称(“Field1”)的方法。

total = (from objects in ObjectsObservableCollection where ((object.InCity && cityList.Select(ma => ma.CityText).Contains(objects.CityLabel)) && FilterValuesList.Select(ff => ff.ToString().ToUpper()).Contains(objects.**Field1**.ToString().ToUpper())) select objects.ID).Count();

我可以使用 switch-case(每个 属性 都有一个 select 语句)来确定哪个 属性 被用作 [=42 处的“过滤字段” =]-time(因为所有 属性 名称在 运行-time 都是已知的)但我真的很想了解如何以“正确的方式”做到这一点。

我认为表达式是正确的方法,但我无法理解语法。如果我正在搜索的是 1 个值(而不是值列表),我想我可以做到。

任何人都可以给我一个提示,也许指向一篇文章或教程,或者解释我需要用什么来完成这个?

如果您已经有一组固定的字段要测试,假设它们都是 string 字段,您可以创建一个 Dictionary 访问器 lambda,可以通过以下方式查找字段名称:

var FilterValues = FilterValueList.Select(s => s.ToLowerInvariant()).ToHashSet();
var TransportAccessorsDict = new[] {
    new { FieldName = "Color", Accessor = (Func<Transport,String>)(t => t.Color) },
    new { FieldName = "Name", Accessor = (Func<Transport,String>)(t => t.Name) },
}
.ToDictionary(fa => fa.FieldName, fa => fa.Accessor);

var getFilterField = TransportAccessorsDict[FilterField];
var total = (from objects in ObjectsObservableCollection
             where FilterValues.Contains(getFilterField(objects).ToLowerInvariant())
             select objects.ID
            ).Count();

这应该是合理的性能,但如果性能是一个重要的考虑因素,您可能应该将 FilterValuesList 转换为大写(我认为小写是首选,尽管两者都不好,文化感知字符串不敏感包含将是最好的) HashSet 在 LINQ 查询中使用它之前。

我删除了 ToString 调用,因为它们应该是多余的,否则你会有更大的(类型)问题。