In this case it doesn't hurt you because you aren't using the delegate at a place outside the loop. Of course, you aren't really doing anything useful in the example, so it is unclear if this "stands" for your actual code.
Threads and deferred callbacks would suffer though, so yes it is (in a way) valid. If unsure, fix it:
foreach (string s in splits)
{
var clone = s;
regexes.Where(x => x.Pattern.Contains(clone));
}
To clarify, this problem only hurts when the captured variable is used outside of the normal flow of the foreach loop. When used directly inside the loop, and on the same thread (no Parallel
), the captured variable will always be at the expected value. Anything that breaks that will see random data; typically (but not always) the last value.
Note in particular that this "deferred delegate" includes things like building up Where
filters on a query, as you'll find they all use the last value. The following would be bad:
var query = ...
foreach (string s in splits)
{ // BAD CODE!
query = query.Where(x => x.Foo.Contains(s));
}
Re any "better way" (comments)... well, the cloned variable trick has the advantage of working, but here's a cute trick - fixes the above "BAD CODE!":
query = splits.Aggregate(query, (tmp, s) => tmp.Where(x => x.Foo.Contains(s)));
Personally I'd find the following easier to grok though:
foreach (string s in splits)
{
var tmp = s;
query = query.Where(x => x.Foo.Contains(tmp));
}