List<(int integer, string str)> myTupleList;
foreach (var tuple in myTupleList)
tuple = (tuple.integer, tuple.str);
myTupleList.ForEach(tuple =>
tuple = (tuple.integer, tuple.str));
Why does the foreach give a compiler error, but not the Linq.ForEach?
Irrelevant details to get to 220 characters:
I wasted 2 hours because I forgot that you can't assign to the iteration variable in a foreach. While it was obviously my fault, it would have been nice to get a compiler error to save me some frustration. Why can't Linq.ForEach do this?
The variable you declare in foreach
is considered a part of the foreach
statement. The language spec calls it the "iteration variable". The syntax also looks distinct from a normal variable declaration, as it is followed by in
. Because of this, it is more justified to add special restrictions to it, like not being able to reassign it.
ForEach(x => ...)
on the other hand, is not one single syntactic construct like foreach
is. It is merely a call to a method called ForEach
, and passes a lambda expression to that method. Unlike the iteration variable of a foreach
, the x
here is nothing special, just the parameter of a lambda expression.
Lambda expressions represent "inline" method definitions - its parameters are like method parameters, which have always been reassignable. A language change such as "all lambda parameters are not allowed to be reassigned" would be hard to justify, and a change like "only the parameters of lambdas passed to methods named ForEach
are not allowed to be reassigned" would not be practical to implement. In general it is difficult to know where a lambda is going to be passed.
That said, the newly introduced in
parameter modifier prevents method parameters from being reassigned, but alas, it is too late - changing ForEach
to take a lambda with an in
parameter would be a breaking change.