Having trouble wrapping my head around the concept of modifying these two different lists. So when using a regular for loop to iterate over each one, we can directly modify the list of integers, but cannot modify a specific item in the list of ValueTuples.
Consider this example
var test = new List<int>() { 1, 2, 3, 4 };
for (int i = 0; i < test.Count; i++)
{
test[i] += 1;
}
var test2 = new List<(int, int)>() { (1, 2), (2, 3), (3, 4) };
for(int i = 0; i < test2.Count; i++)
{
test2[i].Item1 += 1;
}
So in this, we can successfully add 1 to each integer value in the first list. However, with the second list we actually get a compiler error of CS1612 which states "Cannot modify the return value of 'List<(int, int)>.this[int]' because it is not a variable."
I read into the error on the official docs, and it makes sense that in the second example we are returning a copy of the ValueTuple, therefore we are not modifying the actual one in the list. But then why does the integer example work?
Feel like I might just be overcomplicating this, but wanted to ask here and see where I could be going wrong.
To understand why
test[i] += 1compiles buttest2[i].Item1 += 1doesn't, let's examine how the C# compiler transforms them into simpler statements.test[i] += 1is transformed as follows:The
get_Itemandset_Itemmethods refer to thegetandsetaccessors ofList<T>'s indexer. I'm usingget_Itemandset_Itemhere instead oftest[i]to clarify whethertest[i]refers to a get or a set.test2[i].Item1 += 1is transformed as follows:Notice two important points:
set_Item. With ValueTuple, there isn't.Item1occurs on a temporary copy oftest2[i], so it ultimately has no observable effect. This is why the compiler reports error CS1612: to prevent you from writing code that doesn't do what you think it does.You can get your code to compile in a couple ways:
Use an array instead of
List. Iftest2were an array, thentest2[i]would be a mutable reference to the element at indexi, not a copy. Array indexers are special in this regard.Replace the entire element
test2[i]:The last statement invokes
set_Itembecause the left-hand side of the assignment is an indexer expression and nothing else. (That's just the way the C# language works.)