使用字典我循环遍历IEnumerable并每次根据过滤字典应用过滤器。 FilterType枚举决定过滤器应该应用于哪个字段,字符串是自由文本过滤器本身。
我遇到的问题是,如果我向字典添加多个过滤器(即FilterType.Customer和FilterType.Name过滤器),过滤器将应用于Customer和Name字段,但freetext过滤器将取自添加的第一个过滤器。即在下面的代码中,nameFilterBox.Text应用于LINQ查询中的Name和Customer字段,而customerFilterBox.Text根本没有应用。因此,字典的FilterType部分被读取两次,但字符串过滤器仅从第一个读取。
我真的不明白为什么会这样。
static IEnumerable<Jobb> jobQuery = GetInitialJobQuery();
Dictionary<FilterType, string> filters = new Dictionary<FilterType, string>();
filters.Add(FilterType.Name, nameFilterBox.Text);
filters.Add(FilterType.Customer, customerFilterBox.Text);
foreach (var filter in filters)
{
switch (filter.Key)
{
case FilterType.Customer:
jobQuery = jobQuery.Where(x => x.KUNDREF != null &&
x.KUNDREF.ToLower().Contains(filter.Value.ToLower()));
break;
case FilterType.Name:
jobQuery = jobQuery.Where(x => x.JOBBESKR != null &&
x.JOBBESKR.ToLower().Contains(filter.Value.ToLower()));
break;
}
}
答案 0 :(得分:3)
这是foreach循环变量捕获错误。你的lambda在filters
的最后一个值上运行,而不是你想的那个。
解决方法是在foreach
循环中声明一个新变量:
foreach (var filterForeach in filters)
{
var filter = filterForeach; // for the lambdas
switch (filter.Key)
{
case FilterType.Customer:
jobQuery = jobQuery.Where(x => x.KUNDREF != null &&
x.KUNDREF.ToLower().Contains(filter.Value.ToLower()));
break;
case FilterType.Name:
jobQuery = jobQuery.Where(x => x.JOBBESKR != null &&
x.JOBBESKR.ToLower().Contains(filter.Value.ToLower()));
break;
}
}
或者,由于你只在lambdas中使用filter.Value
,你也可以这样做:
foreach (var filter in filters)
{
var value = filter.Value.ToLower(); // for the lambdas
switch (filter.Key)
{
case FilterType.Customer:
jobQuery = jobQuery.Where(x => x.KUNDREF != null &&
x.KUNDREF.ToLower().Contains(value));
break;
case FilterType.Name:
jobQuery = jobQuery.Where(x => x.JOBBESKR != null &&
x.JOBBESKR.ToLower().Contains(value));
break;
}
}
Eric Lippert在此发表了关于此事的博文:Closing over the loop variable considered harmful。
答案 1 :(得分:1)
我不确定,但我认为它与从枚举器中读取值的方式有关,因此它不会在lambda的闭包中结束。由于值在循环之后使用,您将使用枚举器的Current
属性中剩余的值,即最后一项。
尝试将值复制到局部变量中,使其最终出现在闭包中:
string value = filter.Value.ToLower();
switch (filter.Key) {
case FilterType.Customer:
jobQuery = jobQuery
.Where(x => x.KUNDREF != null && x.KUNDREF.ToLower().Contains(value));
break;
case FilterType.Name: {
jobQuery = jobQuery
.Where(x => x.JOBBESKR != null && x.JOBBESKR.ToLower().Contains(value));
break;
}