我有以下BL方法
public static void SomeMethod (List<SomeClass> group)
{
IEnumerable<SomeClass> groupWithFalse =(from SomeClass gr in group
where gr.SomeProp== false
select gr);
foreach (SomeClass grFalse in groupWithFalse)
{
grFalse.Save();
}
if (groupWithFalse.Any())
{
// do some stuff
}
}
dl保存的模拟实现(在大量单元测试中无法更改)是:
public void Save()
{
group.SomeProp = true;
}
如果我尝试对流的最后一个语句进行单元测试,例如(groupWithFalse.Any())
语句失败,显然没有更多元素将该属性设置为false。
如果我将业务逻辑中的代码更改为:
public static void SomeMethod (List<SomeClass> group)
{
List<SomeClass> groupWithFalse = new List<SomeClass>();
foreach (var g in group)
{
if (g.SomeProp == false)
groupWithFalse.Add(g);
}
foreach (SomeClass grFalse in groupWithFalse)
{
grFalse.Save();
}
if (groupWithFalse.Any())
{
// do some stuff
}
}
条件语句if (groupWithFalse.Any())
在单元测试中不会失败。为什么会这样?感谢
答案 0 :(得分:3)
运行LINQ查询不会存储结果 相反,它会在每次枚举时重新执行查询。
调用Save()
后,查询将为空,因为所有项都不符合where
子句。
将其更改为
var unsaved = group.Where(g => !g.SomeProp).ToList();
致电ToList()
会将结果存储在List<T>
;这可以避免重新执行查询。
答案 1 :(得分:2)
由于deferred execution,您的问题正在发生。在您的第一个示例中,groupWithFalse
不表示SomeProp
为false的对象列表,它指的是可以评估到该列表的查询。
如果您希望列表在整个函数期间保持不变,只需在LINQ查询的末尾添加.ToList()
,如下所示:
IEnumerable<SomeClass> groupWithFalse =(from SomeClass gr in group
where gr.SomeProp == false
select gr).ToList();
// ^^^^^^^^^
这将导致查询立即执行 并将其结果返回到List<SomeClass>
,如果修改其中的对象,其内容将不会更改。
答案 2 :(得分:0)
你的问题在于LINQ的Lazy Evalution。在第一个示例中,LINQ查询实际上是TWICE运行的。首先枚举调用Save()方法,然后调用Any()。
作为使用LINQ时的一般规则,在每个查询之后放置ToList()。
答案 3 :(得分:0)
好的,在第一个实现中发生的事情是,您正在定义一个迭代器groupWithFalse
,它迭代group
设置为SomeProp
的{{1}}元素。您已经迭代false
并将groupWithFalse
设置为SomeProp
以获取所有这些元素,现在当您再次迭代时(对true
的调用会产生第二次迭代), element将Any
设置为SomeProp
,因为您只是将其设置为当然,{}}}当然返回true
(迭代现在生成空集合)。
详细说明,基本上当你说
时Any
您正在定义一个对象(false
),该对象捕获逻辑“给我IEnumerable<SomeClass> groupWithFalse =(from SomeClass gr in group
where gr.SomeProp== false
select gr);
中groupWithFalse
设置为false的元素序列”。显然,此对象实际上不是group
设置为false的那些元素的集合或序列。第一次迭代此对象(SomeProp
)时,此规则将生成SomeProp
为foreach
的元素(如果SomeProp
中有任何内容)。但是当您再次迭代(false
)时,此规则将不会生成任何元素,因为您已修改此规则从中抽取其元素的集合group
。
在第二次迭代中,您正在检查名为Any
的{{1}}是否为空集合,而不是因为您已在group
循环中添加了元素它
以下是我编写代码的方法:
List<SomeClass>
现在代码读起来像“获取groupWithFalse
foreach
public static void SomeMethod (List<SomeClass> group) {
IEnumerable<SomeClass> groupWithFalse =(from SomeClass gr in group
where gr.SomeProp== false
select gr);
if(groupWithFalse.Any()) {
foreach (SomeClass grFalse in groupWithFalse) {
grFalse.Save();
}
// do some stuff
}
}
group
的元素。如果有SomeProp
,false
他们然后做一些东西。“
答案 4 :(得分:0)
在第一个示例中,您使用的是IEnumerable。把它想象成一个查询,而不是一个对象列表。那么你使用上面的查询迭代整个集合“group”,该查询说“只迭代SomeProp等于false的元素”。
然后在你的foreach语句中修改“group”列表中对象的状态。
然后你在你的查询中应用了额外的谓词,指出“组”列表中是否有任何元素,其中某个prop等于false?“而且你显然得到了答案“没有他们没有”。
在第二个示例中,您只是获取新的元素集合,而不是查询。那么你迭代它,chage state然后问“有任何元素吗?”并回答“是”的答案。与之前的元素相同,但更改了SomeProp属性值。