我有一个IEnumerable,我正在通过.Where表达式应用多个过滤器。我的代码看起来像这样
public List<MyObject> FilteringFunction(List<MyObject> listToFilter, List<Filter> filters)
{
// A dirty way to have an enumerable instead of List
var enumerableToFilter = listToFilter.Where(x => true);
foeach(var filter in filters)
{
enumerableToFilter = enumerableToFilter.Where(x => x.Value.Contains(filter.Value));
}
return enumerableToFilter.ToList();
}
我只会在我的收藏中迭代一次吗? (因为我只有一个使用LINQ to SQL的数据库调用)
答案 0 :(得分:3)
Enumerables延迟执行,直到您迭代它们,并且通过集合在单次迭代中应用多个过滤器。结合其他linq语句可能会强制早期枚举,我没有测试过每个组合。这只会是非常大的数据集或低规格性能关键系统的问题。
以下是使用Visual Studios c#interactive
的示例> class Item
. {
. private int _number;
. public int Number
. {
. get { Console.WriteLine($"Got number {_number}"); return _number; }
. set { _number = value; }
. }
. }
>
> IEnumerable<Item> items = new List<Item>() {
. new Item { Number = 1 },
. new Item { Number = 2 },
. new Item { Number = 3 },
. new Item { Number = 4 },
. new Item { Number = 5 },
. new Item { Number = 6 }
. };
>
> var filteredItems = items.Where(item => item.Number > 3).Where(item => item.Number % 2 == 0);
>
> var listedItems = filteredItems.ToList();
Got number 1
Got number 2
Got number 3
Got number 4
Got number 4
Got number 5
Got number 5
Got number 6
Got number 6
>
请注意,过滤掉1,2和3,并且不会调用第二个过滤方法。 4,5和6全部通过第一个过滤器,因此应用了两个过滤器。
关键点:请注意,在将枚举读取到列表之前,实际上不会进行过滤。在将结果枚举到列表之前,您将能够继续附加过滤器。
答案 1 :(得分:1)
首先,结果将是空的,以确保您使用不同的值过滤相同的属性,并且假设您已更正此问题,回答您的问题,因为iqueryable它将仅调用数据库一次,因为Enumerable对象是同样,因为迭代将在您使用foreach迭代对象或调用GetEnumerator时发生,在您的情况下,您没有这样做
答案 2 :(得分:0)
如果您有许多过滤器,由于许多委托创建和调用以及许多对Where
的调用,开销可能会变得明显。话虽这么说,你应该进行性能测试,以确定它是否真的是一个问题。
您可以重构代码以测试同一谓词中的所有过滤器:
public List<MyObject> FilteringFunction(List<MyObject> listToFilter, List<Filter> filters)
{
Func<MyObject, bool> predicate =
x =>
filters.All(f => x.Value.Contains(f.Value));
return listToFilter.Where(predicate).ToList();
}
PS:对此:
// A dirty way to have an enumerable instead of List
有一种更清洁的方式:
var enumerableToFilter = listToFilter as IEnumerable<MyObject>;
甚至:
var enumerableToFilter = listToFilter.AsEnumerable();