Pavel
Pavel

Reputation: 1288

How to set something in a item in a collection?

I have ten positions with x, y and name. I would like to set all x to x+1. How to do this? I tried different methods, but I always get that I cannot modify the list. It should be done with for or foreach.

I get "Cannot modify members of "item" because it is foreach iteration variable."

public struct Position
{
    public int x { get; set; }

    public int y{ get; set; }
    public string name{ get; set; }

}
class Program
{
    static void Main(string[] args)
    {

        List<Position> positions = new List<Position>();
        Position position = new Position();
        position.x = 12;
        position.y = 12;
        position.name = "left";
        positions.Add(position);
        position = new Position();
        position.x = 13;
        position.y = 13;
        position.name = "right";
        positions.Add(position);

        Console.WriteLine(positions.Count);

        Console.WriteLine();

        Position newPosition;
        foreach (Position item in positions)
        {   

        }

        Console.WriteLine();
        foreach (Position item in positions)
        {
            Console.WriteLine(item.x + " " + item.name);
        }
    }
}
}

Upvotes: 0

Views: 189

Answers (4)

King King
King King

Reputation: 63317

You should consider using class instead of struct. However if it's a requirement. You can still make it work. The problem is you used a foreach which in fact always refer to the underlying list item, if the item is reference type, it's OK without problem but if it's value type, this value will be copied to the iterator. And all the modifications on the copy iterator are meaningless. So error is needed. You surely have to use a normal for instead. However it is not enough. Your positions is a List<Position> and when you get some item from it, actually some copied value is returned because of the internal implementation of indexer. To solve this you can do one of the followings:

First solution:

for(int i = 0; i < positions.Count; i++){
  //copy first
  var current = positions[i];
  //update value
  current.x++;
  //set back to list
  positions[i] = current;
}

Second solution:

//convert the list to array so that all the items will be fetched directly 
//without using indexer:
var temp = positions.ToArray();
for(int i = 0; i < temp.Length; i++){
  temp[i].x++;
}

Upvotes: 1

Hamidreza
Hamidreza

Reputation: 3118

i hope i get what in your mind truly:

int preX1 = 0, PreX2 = 0; 
for (int i = 0; i <= positions.Count - 1; i++)
{   
     if(i == 0)
     {
         preX1 = positions[i].x;
     }
     else
     {
         preX2 = positions[i].x;
         positions[i].x = preX1;
         preX1 = preX2;
     }
}

Upvotes: 0

Felix Castor
Felix Castor

Reputation: 1675

Structs are immutable types. So once you assign it, it can't be changed within the list. The foreach loop isn't really the problem. Editing an element of the list outside of the foreach will give the same error.

There are a number of questions addressing this on Stack Overflow with some valuable insight:

Cannot modify a struct in a list

Why are mutable structs evil?

Why are C# structs immutable?

So if you had to use a struct in this scenario you would have to make a mutable struct, which is --evil-- from what I have read.

Upvotes: 0

John Koerner
John Koerner

Reputation: 38079

You need to increment x within the loop.

If you want to use a for each, then you need to also make position a class:

public class Position
{
    public int x { get; set; }

    public int y{ get; set; }
    public string name{ get; set; }

}

foreach (Position item in positions)
{   
     item.x = item.x + 1;
}

Upvotes: 1

Related Questions