据Resharper说,这两个人也应该这样做:
1)
string strTemp = null;
foreach (var s in array)
{
if (strTemp == null || !strTemp.Contains(s))
{
strTemp += (!string.IsNullOrEmpty(strTemp) ? ";" : string.Empty) + s;
}
}
2)
string strTemp = null;
foreach (var s in array.Where(s => strTemp == null || !strTemp.Contains(s)))
{
strTemp += (!string.IsNullOrEmpty(strTemp) ? ";" : string.Empty) + s;
}
怎么样?我错过了什么?
答案 0 :(得分:5)
根据评论判断,您预计此lambda表达式只会执行一次,而strTemp
的值仍为null
。
s => strTemp == null || !strTemp.Contains(s)
事实并非如此。它将为数组的每个元素执行,并在每种情况下使用最新值strTemp
。即使只调用Where
方法一次,也会为array
中的每个元素执行lambda表达式(或者更确切地说,是从它创建的委托)。
您的代码可能更好地写为:
string joined = string.Join(";", array.Distinct());
......但是。特别是,在您当前的代码中,如果您的数组是{ "ab", "a", "ab", "c" }
,那么您最终会得到ab;c
的输出,其中我怀疑您希望{{1} } ...这是因为ab;a;c
已经包含在" ab"通过循环的第二次迭代。当然,如果你真的想要这种行为,那么你所获得的代码将会起作用......但对我来说这听起来并不常见。
编辑:要理解这一切,您需要了解LINQ如何使用延迟评估。 "a"
方法立即返回,而没有执行谓词 at all ...但是当您向集合询问其第一个元素时(通过Where
/ GetEnumerator()
)它将迭代数组,针对每个项目测试谓词,直到找到匹配的谓词。然后它会产生该项,当你向它询问 next 项时,它将继续从它到达的位置,再次针对数组的其余元素测试谓词。
用一些代码证明这一点可能最容易:
MoveNext()
输出:
using System;
using System.Linq;
class Test
{
static void Main()
{
var numbers = new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var filtered = numbers.Where(x => {
Console.WriteLine("Testing {0}", x);
return x % 2 == 0;
});
Console.WriteLine("Just before loop");
foreach (var item in filtered)
{
Console.WriteLine("Received {0}", item);
}
}
}
如你所见:
答案 1 :(得分:0)
版本2将if
- 条件从版本1重构为Where
语句中foreach
函数调用的过滤器。
答案 2 :(得分:0)
if-block和.Where
方法填充相同的函数。
在选项1中,您遍历整个数组并检查变量是否与if语句匹配。
在选项2中,您对数组应用了一个过滤器,该过滤器等同于选项1中的if条件。
然后strTemp被处理。过滤后的数据在两种情况下都是相同的,因为if语句和where子句是相同的。