According to Resharper this two shall do the same:
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;
}
How so? What am I missing?
Judging by comments, you're expecting that this lambda expression will only be executed once, while strTemp
still has a value of null
.
s => strTemp == null || !strTemp.Contains(s)
That's not the case. It will execute for each element of the array, and will use the latest value of strTemp
in each case. Even though the Where
method is only called once, the lambda expression (or rather, the delegate created from it) will be executed for each element in array
.
Your code would probably be better written as:
string joined = string.Join(";", array.Distinct());
... however. In particular, in your current code, if your array is { "ab", "a", "ab", "c" }
you'll end up with an output of just ab;c
where I suspect you want ab;a;c
... this is because "a"
is already contained in "ab" by the second iteration of the loop. Of course if you really want that behaviour, the code you've got will work... but it does sound unusual to me.
EDIT: To understand all this, you need to understand how LINQ uses lazy evaluation. The Where
method returns immediately without having executed the predicate at all... but when you ask the collection for its first element (via GetEnumerator()
/ MoveNext()
) it will iterate over the array, testing the predicate against each item until it finds one which matches. It will then yield that item, and when you ask it for the next item, it will carry on from where it had got to, again testing the predicate against the remaining elements of the array.
It may be easiest to demonstrate this with a little code:
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);
}
}
}
Output:
Just before loop
Testing 0
Received 0
Testing 1
Testing 2
Received 2
Testing 3
Testing 4
Received 4
Testing 5
Testing 6
Received 6
Testing 7
Testing 8
Received 8
Testing 9
As you can see:
See more on this question at Stackoverflow